Skip to main content

Assembler

State of the part

The assembler implements the full ISA and is stable. It was mainly developed by Florian Bauckholt and Nils Husung.

The assembler is based on customasm. To run the assembler, you need to install a Rust toolchain and customasm via cargo install customasm. The customasm rules are contained in the isa/isa.s file. So if you are in the same directory, you can assemble files as follows:

customasm [-p|-o <out.bin>] isa.s [userspace.s|rom.s] <input.s> [...]

The -p switch makes customasm print the code to stdout, by default in an annotated hex format. You can select the format via the -f option, see customasm --help for the available formats.

If -p is not given, a binary file will be generated. By default, the name will be isa.bin as name of the first input file is isa.s. Of course, you can change this using the -o option.

userspace.s can be used to output the code starting at address 0x2000, where the general purpose RAM section begins. However, the first byte in the binary will be the one located at address 0x2000.

To write programs for the ROM, you can use rom.s instead. In this mode, only addresses from 0x0000 to 0x0fff can be used (the assembler will generate an error if the code does not fit in there). However, the file size will be 128 KiB to make minipro (the program we use for writing to the flash chips) happy.

minipro command

The minipro command we use for flashing the ROM is:

minipro -s -p SST39SF010 -w <file.bin>

Pseudo-Instructions

Besides mnemonics for the native instructions, the assembler also provides a few pseudo-instructions. In particular, these are:

  • shl as add acc, acc
  • rcl as adc acc, acc
  • Some alternative mnemonics for jumps, see jcc
  • binop d, imm8 as mov acc, d; binop acc, imm8; mov d, acc where d is an arbitrary 8-bit operand ≠ acc and binop is any binary operation ≠ cmp
  • cmp d, imm8 as mov acc, d; cmp acc, imm8 where d is an arbitrary 8-bit operand ≠ acc
  • binop d, r as mov acc, d; binop acc, r; mov d, acc where d is an arbitrary 8-bit operand ≠ acc and binop is any binary operation ≠ cmp
  • cmp d, r as mov acc, d; cmp acc, r where d is an arbitrary 8-bit operand ≠ acc
  • push ab as push a; push b with variants for ab, cd, pi (little-endian in memory)
  • pop ab as pop b; pop a with variants for ab, cd, pi
  • xchg xx, yy as push xx; push yy; pop xx; pop yy with variants for ab, cd, pi
  • asserteq r, imm8 as cmp r, imm8; assertz (using the pseudo-instruction above if racc)
  • asserteq r, s as cmp r, s; assertz (r and s denote 8-bit operands)
  • asserteq [imm16], imm8 as mov acc, [imm16]; cmp acc, imm8; assertz
  • asserteq [imm16], r as mov acc, [imm16]; cmp acc, r; assertz
  • asserteq ab, imm16 as asserteq a, imm16[15:8]; asserteq b, imm16[7:0], correspondingly for cd and pi. There is no such instruction for sp, because we cannot directly access the upper and lower byte of sp.
  • assertflags flags where the flags can be denoted in the style SZVC or __V_. _ means that the corresponding flag is unset (and not “don’t care”). The corresponding assembly code is:
    pushf ; 2x pushf to simply restore the flags
    pushf
    pop acc
    cmp acc, flags
    assertz
    popf
  • setflags flags as mov acc, flags; push acc; popf where the flags are denoted as above.
  • fail as mov acc, 1; cmp acc, 0; assertz