GitHub - orionfollett/oarm: Interpreter for Orion's subset of ARM Assembly written in C89.

3 min read Original article ↗
  • Assembler and CPU emulator that supports a small subset of ARM assembly.
  • Written in strict C89.
  • No dependencies besides a C standard library and compiler.
  • Has only been tested on Mac and Linux.

How to run:

source dev.sh
run --help
run --docs
run asm/all.s

ASM Instructions (can be obtained with "oarm --docs"

oarm (Orion's subset of ARM assembly) documentation

Arguments:
  constant: ex: '#10' is the integer 10, '#-33' is negative 33
  register: ex: 'x0' is the first register, 'x9' is the last register
  memory address: ex: '[#1]' is memory address 1, '[x2]' is the address of the value in register x2

Debugging:
  reg - print all registers
  mem - print all memory
  rpc - print the program counter
  rcb - print the comparison byte

Registers + Memory:
  mov - move a constant or register value to a register ex: 'mov x0, x0, #1'
  ldr - load value at memory address into register ex: 'ldr x0, [#1]'
  str - store the value from register into memory ex: 'str x0, [#1]'

Arithmetic:
  add - add two register or constant values and store in register ex: 'add x0, x0, #1' increments x0 by 1
  sub - subtract
  lsl - bitwise shift left ex: 'lsl x0, x0, #1' shifts the value in x0 left 1
  lsr - bitwise shift right

Branches:
  cmp - compare two register or constant values, sets the sign byte to -1, 0, or 1 ex: 'cmp x0, #1'
  <label name>: - labels are arbitrary strings with a colon ex: 'exit:' declares the exit label
  b - branch (jump) to the label specified ex: 'b exit' jumps the exit label
  beq - branch if equal, jumps if the cmp byte is 0 ex: 'beq exit'
  bne - branch if not equal
  blt - branch if less than
  ble - branch if less than or equal
  bgt - branch if greater than
  bge - branch if greater than or equal

Register Labels:
  .reg <label_name> <register> - give pretty name to register ex: '.reg counter x0' lets you use the word 'counter' in place of 'x0'

Summary

This is a fun, educational project to get a better intuition for basic assembly and practice writing C. There are two executables: test, which runs the tests, and oarm, which is the main application.

There are two "modules": oarm and ostd.

  1. ostd has my personal standard library. I came into this project with nothing, so I implemented some string utilities and a hash map. I mostly only implemented functions that I directly needed. For example the hash map has no "pop" or "remove" function since I didn't require it.

  2. oarm has the main application logic. Instructions are executed one at a time, state is copied on each instruction execution. Performance was not a concern as long as it felt reasonable to run very small programs on modern hardware.

Philosophy

Since this was educational, I used as little outside resources as possible beyond compiler warnings, man pages, and the occasional Google/LLM question. No code was generated by AI. I chose to write this in C because I'm planning on doing more embedded projects down the line, so I wanted to brush up my C.

Developer Scripts:

  • fmt
  • run
  • build
  • test