# ARM HAL implementation

HAL opcode structure (close to ARM structure)
b3:0   Number bank index
b4     Zero
b5     Rn is an absolute memory addr in bank if set
b11:6  Zeroes
b15:12 Rd (destination register)
b19:16 Rn (source register)
b21:20 Zeroes
b22    8-bit if set
b23    dir)
b24    &)
b25    Immediate if set
b26    32-bit if set, 16-bit if unset
b27    signed)
b31:28 Cond

Register assignment:
r13=RSP r10=PSP r9=W r11=A r8=S r7=SYSVARS

Rn< ( n -- n<<16 )
Rd< ( n -- n<<12 )
Rn! ( op n -- op )
Rd! ( op n -- op )
Rn@ ( op -- n )
Rd@ ( op -- n )

bbl, ( a o -- )
  Write a B or BL instr, with "o" being either $ea000000 or $eb000000, targeting
  absolute addr "a".

?off, ( op instr -- op instr off )
  If "op" indicates that we should add an offset to LDR/STR "instr", do so,
  while possibly writing down instructions and yield the offset that was
  written.

ldrstr, ( op instr -- )
  Write down a LDR or STR instruction corresponding to "op", with "instr" as
  a base. A "neutral" instr is e5900000, but it can be something else if you
  wand to add, for example, pre/post increments.

immrot ( n -- imm+rot rest ) *Z*
  Spits "n" into an immediate and rotation field compatible with arithmetic
  instructions of the Data Processing type.

  Z if set if rest is 0.

addlit, ( dstreg n -- )
  Compile an addition of number "n" to register "dstreg".

imm, ( dstreg n -- )
  Compile number "n" being set to register "dstreg".

op, ( op instr -- )
  merge operand with instr and write

ariinner, ( op instr -- )
  Proxy "op," with this processing:
  1. Remove OP8B which messes with arithmetic opcodes
  2. If opcode is one of the "comparison" opcodes, forcefully set Rd to 0
     before writing it off.
  3. Also check for "mul". In that case, we move Rn to Rs.

ari, ( op instr -- )
  Write arithmetic operation, that is:
  1. Load operand's src in r0
  2. Apply instr with operand's dst as Rd and Rn and r0 as Rm.

  Stack state is a bit difficult to follow, so here is it:
  _imm ( op instr -- )
  _complex ( op instr n imm+rot -- )
  _complex2 ( op instr n -- )
  _mul ( op instr n -- )
  _imm2 ( op instr -- )
  _inv ( op instr -- )

eor, ( rd rm -- )
  Write a "eor) rd rdn) rm rm) ,)".

shift, ( op mask -- )
  Write a "mov) dst rd) dst rm) src shiftmask)". That's what e1b00000 is.
  After the initial Rd and mask orr-ing in, we're set for everything except
  b11:6 and b4, which values depend on whether we have HALIMM set. Stack before
  the HALIMM check is ( op opcode ).

?mem>rn ( op -- op )
  Checks if operand is m). If it is, compile a write of this value to r1 and
  set Rn to r1.

rn>r1, ( op -- op )
  Compile a @, on "op" being dereferenced and stripped of HALINV with r1 as a
  destination. Then, yield "op" witn Rn being r1 and its offset field being
  zeroed out.

?rn>r1 ( op -- op )
  If op's Rn is the same as Rd, run rn>r1,

?bigoff>r1 ( op -- op )
  If op's offset doesn't fit in a single LDR/STR, run rn>r1.
