- 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.
-
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.
-
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