Assembler

RSM includes an integrated assembler, making it possible to compile & run code at runtime. The assembler can be disabled/removed from builds with a macro, if desired.

Includes an AST API for code generation without an intermediate assembly step, useful if you want to make a compiler that targets RSM.

Compiling

Assembly programs can be compiled just in time when executing a program or ahead of time with the rsm tool's -o flag to produce a ROM image.

hello.rsm

data message = "Hello world\n"
fun main(i32) {
  R0 = message       // address of message
  R1 = 12            // length of message
  R0 = write R0 R1 1 // write to stdout
}

Running it directly:

$ rsm hello.rsm
Hello world

Compiling to a ROM image and then running it:

$ rsm -o hello.rom hello.rsm
$ rsm hello.rom
Hello world

Assembly language

Example

// This program asks for your name on stdin and then greets you
const STDIN = 0
const STDOUT = 1
const STKSIZE = 64 // stack space (must be a multiple of 8)

data ask_msg     = "What is your name?\n"
data readerr_msg = "Failed to read stdin\n"
data no_name_msg = "I see, you don't want to tell me.\n"
data reply_msg1  = "Hello "
data reply_msg2  = "! Nice to meet ya\n"

fun main(i32) {
  // reserve STKSIZE bytes of stack space
  SP = sub SP STKSIZE

  // ask the user for their name
  call print ask_msg 19
  if R0 end

  // read up to STKSIZE bytes from STDIN, to stack memory at SP
  R0 = STKSIZE // number of bytes to read
  R8 = read SP R0 STDIN
  R0 = lts R8 0 // check if read failed ()
  if R0 readerr
  R8 = R8 - 1   // exclude any line break
  R0 = lts R8 1 // check if read was empty
  if R0 noname

  // reply with the user's name
  call print reply_msg1 6
  call print SP R8 // SP = address of name read
  call print reply_msg2 18
  jump end

noname:
  call print no_name_msg 34
  jump end
readerr:
  // note: To test this, use "0<&-" in csh, e.g. out/rsm askname.rsm 0<&-
  call print readerr_msg 21
end:
  SP = add SP STKSIZE // restore stack pointer
}

fun print(addr i64, size i64) ok i1 {
  R0 = write R0 R1 STDOUT
  R0 = lts R0 R1  // return 1 on failed or short write
}

Compile and run:

$ rsm examples/askname.rsm
What is your name?
Robin
Hello Robin! Nice to meet ya
$

Syntax

Whitespace is ignored

file       = (fundef | constdef | datadef)*

constdef   = "const" name type? "=" expr ";"
datadef    = "data" name (type ("=" expr)? | "=" expr) ";"

fundef     = "fun" name "(" params? ")" result? funbody?
params     = param ("," param)*
result     = param ("," param)*
param      = name type | type
funbody    = "{" block0? block* "}"
block0     = blockstmt*
block      = name ":" blockstmt*
blockstmt  = operation | assignment | binop | constdef | datadef

type       = inttype | arraytype
inttype    = "i1" | "i8" | "i16" | "i32" | "i64"
arraytype  = type "[" intlit "]"

operation  = opcode operand*
           ; brz R1 end
binop      = operand ("-" | "+" | "*" | "/") operand
           ; x + 3
assignment = reg "=" (operation | operand) ";"
operand    = reg | literal | name

literal    = intlit
intlit     = "-"? (binlit | declit | hexlit)
binlit     = "0b" ("0" | "1")+
declit     = (0-9)+
hexlit     = "0x" (0-9A-Fa-f)+

name       = ("_" | A-Za-z | uniprint) ("_" | A-Za-z | 0-9 | uniprint)

uniprint   = <utf8 encoding of printable unicode codepoint>

opcode     = copy | copyv | load | load4u | load4s | load2u
           | load2s | load1u | load1s | store | store4 | store2 | store1
           | add | sub | mul | adds | subs | muls | div
           | mod | and | or | xor | shl | shrs | shru
           | binv | not | eq | neq | ltu | lts | lteu
           | ltes | gtu | gts | gteu | gtes | if | ifz
           | call | jump | ret | tspawn | syscall | write | read
           | mcopy | mcmp | stkmem

Comments are ignored and can appear wherever whitespace can appear

comment      = linecomment | blockcomment
linecomment  = "//" <any character except LF> <LF>
blockcomment = "/*" <any character> "*/"