# RISCV assembler

The general *modus operandi* of this assembler is very close to [asm/arm]. This
is an example invocation:

  add) x1 rd) x1 rs1) x2 rs2) ,) \ add x2 to x1
  add) x1 x1 x2 3p) ,) \ using batch parameters

## Register constants

The 32 registers of the CPU can be referred to by constants x0 to x31.
Otherwise, there are also aliases for registers with a special role:

  xZERO=0 xRA=1 xSP=2 xGP=3

  xRSP=2 xPSP=3 xW=4 xA=5 xS=6 xSYSVARS=7

## Instruction parameters

Those words all have a ( op reg -- op ) signature and set the different fields
of the RISC-V instruction: rd) rs1) rs2) funct3) funct7)

Additionally, there is rdrs1) which sets both RD and RS1 to the same value.

For the load and store instructions, parameters can be hard to remember and
error prone, so we have these aliases:

  base)  --> rs1)
  src)   --> rs2)
  dst)   --> rd)

### Batch parameters

Instructions can become quite verbose due to parameters adding up. Batch
parameters are here to the rescue! These are special parameters which accept
more than one parameter and use rd),rs1),rs2,imm) depending on the instruction
type. To sum up, instructions are built and checked automatically.

The parameter order is always rd) rs1) rs2) imm) modulo the incompatible ones.
The order of rs1/rs2 is reversed for store instructions, see examples below.
These batch parameters have the following signature:
3p) ( op n1 n2 n3 -- op )
2p) ( op n1 n2 -- op )

3p) drops "n3" when called on instructions which accept only 2 parameters.

Examples:
addi) xA rd) xW rs1) 5 imm) ,) \ is the same as
addi) xA xW 5 3p) ,)
jal) xRA rd) 42 imm) ,) \ is the same as
jal) xRA 42 2p) ,)

lw) xA dst) x10 base) 12 imm) ,) \ is the same as
lw) xA x10 12 3p) ,)
sw) xA src) x10 base) x12 imm) ,) \ is the same as
sw) xA x10 12 3p) ,)

## Immediates

RISC-V immediates are even trickier than with ARM, and that's something. This
assembler has the "imm) ( op n -- op )" keyword that will set the immediate
fields correctly depending on the instruction. Under the hood, it's all very
complex, but this word does the right thing. If "n" is out of bounds, we abort.

You will often want to load a register with an arbitrary number. This means a
possibility of multiple instructions. For this purpose, we have a macro, "li, (
reg n -- )". For example, "x1 42 li," will write the needed instructions so that
register x1 contains 42.

## Instructions

All instruction words have a ( -- op ) signature.

Load/Store
  lb) lbu) lh) lhu) lw) sb) sh) sw)

Integer Register-Immediate
  addi) slti) sltiu) andi) ori) xori)
  slli) srli) srai)
  lui) auipc)

Integer Register-Register
  add) sub) slt) sltu) and) or) xor)
  sll) srl) sra)

Jumping around
  jal) jalr)
  beq) bne) blt) bltu) bge) bgeu)

Multiply and divide (M extension)
  mul) mulh) mulhu) mulhsu) mulw)
  div) divu) divw) divuw)
  rem) remu) remw) remuw)

## Pseudo-instructions

The words below have the ( -- op ) signature as well. They are derived from the
words listed above.

mv) not) neg) b) j)
bgt) ble) bgtu) bleu) beqz) bnez)
ret) nop)

## Macros

push, ( reg -- )
  Grow xRSP by 4 and store "reg" into the new slot.

pop, ( reg -- )
  Load xRSP top to "reg" and shrink xRSP by 4.

ppush, ( reg -- )
  Like "push,", but for xPSP.

ppop, ( reg -- )
  Like "pop,", but for xPSP.

pc>reg ( reg -- )
  Load current PC value into "reg".

Macros below compile to one or two instructions depending on the operand size.
Manual instructions should be used if the resulting size needs to be known.

tail, ( a -- )
  Jump to relative address "a".

absb, ( pc -- )
  Jump to absolute address "pc".

call, ( a -- )
  Call relative address "a".

absbl, ( pc -- )
  Call absolute address "pc".

## Branching

Except for jalr) which jumps to register+offset, all branching words branch to
offsets relative to PC, which is consistent with how branching works in other
Dusk assemblers. This means that this assembler plays well with [asm/label].

At its core, you supply the offset to jump to through "imm)". It works. For
example, if you have an absolute address in "L1", you can jump to it with
"j) L1 abs>rel imm) ,)"

[jmp] ( "name" -- ) *I*
  Transform an instruction from a "( -- op )" signature to a "( fakerel -- op )"
  one. This is used to accomodate control-flow instructions such as "beq)",
  "jal)", etc. to the forwarding mechanism in [asm/label].
  The call to "imm)" is thus automatically performed and not needed.

  Instructions are checked for validity when calling this word, see below.

  Examples:
    forward [fwd] jal) xRA rd) ,) \ works
    : foo forward [fwd] jal) xRA rd) ,) ; \ works
    forward [fwd] addi) ... \ aborts
    : bar forward [fwd] addi) ; \ aborts during compilation
