# ARM assembler

ARM instructions all encode to a 32-bit number and the way these encodings work
incite us to deviate a little bit from the general Dusk assembler mechanism:
Instead of pushing arguments to PS and then call the "operation writer" word, we
begin the operation mnemonic and "accumulate" arguments into it.  When all
arguments are accumulated, the number on PS is exactly what we want to write,
which we can do with "le,", of which ",)" is an alias.

For example, to write a "add" instruction with r4 as a destination (Rd), r5 as
the first operand (Rn) and 42 as an immediate, we would do:

    add) r4 rd) r5 rn) 42 imm) ,)

Symbol-wise, ")" means "accumulate", where the final ",)" means "write what has
been accumulated".

WARNING: this assembler will not prevent you from assembling nonsensical
instructions, checks are minimal (it does check immediate ranges though). For
example, this means that using "rn)" on "mov)" or "rd)" on "cmp)" results in a
broken instruction.

## Generic words

All operations work on registers and they pretty much all have a destination
register and one or two operand registers. Each register has a constant word:

    r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15
    rFP rIP rSP rLR rPC

These constants are meant to be used in conjunction with these accumulator
words:

    rd) Destination register
    rn) First operand register
    rm) Second operand register
    rs) Used only for Multiply
    rdn) Shortcut for rd) rn) when they're the same

Whenever there's a second operand register, the barrel shifter can be configured
with these words which all have the ( op n -- op ) signature, "op" being the
accumulated operation:

    lsl) lsr) asr) ror)     n = shift by "n" bits
    rlsl) rlsr) rasr) rror) n = register id containing the amount to shift by

Immediates replace the rm) operand and can be specified with the imm) word.
Shift encoding is automatically performed by imm) and will abort with an error
message if the specified immediate can't be encoded.

All operations can be conditionally executed. This condition is activated by one
of these words:

    eq) ne) cs) cc) z) nz) hs) lo) mi) pl) vs) vc) hi) ls) ge) lt) gt) le) al)

## Data processing instructions

All those instructions except mov) and mvn) have 3 operators:

    and) eor) sub) rsb) add) adc) sbc) rsc)
    tst) teq) cmp) cmn) orr) mov) bic) mvn)

rn) shouldn't be used with mov) and mvn)

To have the operation set the CPSR flags, you can use the word f) which sets the
"S" bit of the instruction.

tst) teq) cmp) and cmn) have an implied "f)".

## Multiply

The multiply instruction, mul), has a different structure than other data
processing instructions and does Rd := Rm * Rs. For this instruction, rn) can't
be used and there's a rs) parameter word just for this instruction (Rs is
generally set with the lsl), lsr), etc. family of words).

Additionally, there's the possibility of making a Multiply+Add through the acc)
word, which takes a register ID in parameter.

Rd cannot be the same as Rm and rPC can't be used.

The f) flag works with mul). Example usages:

    mul) r0 rd) r1 rm) r2 rs) ,)
    mul) r0 rd) r1 rm) r2 rs) r3 acc) ,)
    mul) r0 rd) r1 rm) r2 rs) f) ,)

## Single Data Transfer

The str) and ldr) operations only use rd) and rn), with rd) being the register
containing the value to store or the register being the target for the load
operation. rn) is the register containing the target adress for the store/load
operation.

Many options come with those two operations and they are enabled with those
words:

    +i)   op n -- op  Add offset "n" to rn)
    -i)   op n -- op  Subtract offset "n" from rn)
    +r)   op r -- op  Add offset in register "r" to rn)
    -r)   op r -- op  Subtract offset in register "r" from rn)
    pre)  op -- op    Add offset before transfer (default)
    post) op -- op    Add offset after transfer
    8b)   op -- op    Load/Store operation is 8-bit
    !)    op -- op    Write effective address back to rn)

## Swap

The swp) instruction has the same base semantics as ldr) and str), that is, that
rn) is the base address, but it doesn't support any kind of indexing. Only the
8b) flag can be used.

    swp) r1 rd) r2 rn) r1 rm) ,) \ Swaps the value at address r2 with r1
    swp) r1 rd) r2 rn) r3 rm) ,) \ r3 --> [r2] --> r1

## MCR/MRC

The instructions are used to receive data from (MRC) or to send data to (MCR) a
coprocessor. It has it has the following arguments:

    cp#)  op n -- op  The target coprocessor number
    cpi)  op n -- op  Coprocessor "information"
    cpop) op n -- op  Operation mode
    rd)   op r -- op  Destination register on the main CPU
    rn)   op r -- op  Coprocessor operand register 1
    rm)   op r -- op  Coprocessor operand register 2

In a "ARM syntax" listing that looks like:

	MCR p15, 1, r2, c3, c4, 5

p15 is cp#), 1 is cpop), r2 is rd), c3 is rn), c4 is rm) and 5 is cpi).

## Branching

The b) bl) and bx) branching words differ from other mnemonic words because they
need an argument from PS. In the case of b) and bl), it's a relative offset that
follows rules described in doc/asm/intro, that is, that "0" must mean an
infinite loop.

In the case of bx), the argument is a register ID. Examples:

    begin abs>rel b) ,) \ infinite loop
    r0 bx) eq) ,) \ jump to address in R0 if Z is set
