needs num/math asm/label mem/kv lib/psrs unit asm/riscv \ Parameters | Register naming enum x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 \ x16 x17 x18 x19 x20 x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 \ Usual calling conventions enum xZERO xRA xSP xGP \ xTAIL is used by the tail, macro and its use is forbidden consts x2 xRSP x3 xPSP x4 xW x5 xA x6 xS x7 xSYSVARS x30 xTAIL \ Instr type encoding and immediates enum _I _S _B _U _J _JR _RI _R _N \ _N for uNknown \ Opcode to type mapping for quadrant 3 create _Itypes map< c, _I _N _N _N _I _U _I _N \ _S _N _N _N _R _U _R _N \ _N _N _N _N _N _N _N _N \ _B _JR _N _J _N _N _N _N consts $03 LOAD $13 OP-IMM $17 AUIPC $1b OP-IMM-32 \ $23 STORE $33 OP $37 LUI $3b OP-32 \ $63 BRANCH $67 JALR $6f JAL : opc@ $7f and ; : funct3@ 12 rshift $7 and ; : funct7@ 25 rshift $7f and ; : ?I->RI ( op type -- type ) \ is this an immediate shift? dup _I = if swap ( type op ) bi funct3@ $3 and 1 = | opc@ OP-IMM = and if drop _RI then else nip then ; : itype@ ( op -- type ) dup opc@ 2 rshift _Itypes + c@ ?I->RI ; \ Macros and options 0 value _reverse? : _$rst 0 to _reverse? ; : ,) ( op -- ) le, _$rst ; : _setter ( mask lshift "name" -- ) tuck lshift swap here# rot> , , does> A! @ lshift swap A> 4+ @ invand or ; $1f 15 _setter _rs1) $1f 20 _setter _rs2) $1f 07 _setter _rd) $07 12 _setter funct3) $7f 25 _setter funct7) \ Assembly macros : _hi ( n -- n:31-12>>12 ) dup $fff invand 12 rshift swap $800 and if 1+ then ; : _lo ( n -- n:11-0 ) $fff and ; \ Register and functions encoding alias noop _chkrs1 ( op n -- op n ) alias noop _chkrs2 \ . alias noop _chkrd \ . :~ if _chkrs2 _rs2) else _chkrs1 _rs1) then ; : rs1) _reverse? ~ ; : rs2) _reverse? not ~ ; : rd) _chkrd _rd) ; : rdrs1) tuck rd) swap rs1) ; alias rs1) base) alias rs2) src) alias rd) dst) \ ===== Immediate handling ===== code sex12 20 i) <<, 20 i) signed) >>, exit, : nbovfl ( imm reqsz -- imm f ) [ 1 i) -, PSP) S>) @, W) &) S>) signed) >>, S) &) @, 1 i) +, -2 i) &, ] bool ; : nbovfl# nbovfl if ."wrong immediate size: " .x nl> abort then ; : _immsz# ( imm reqsz -- imm ) dup 32 <> if nbovfl# else drop then ; : imm! ( op imm offl -- op ) 2>r ( V1: imm V2: offl ) begin V2 c@ while V2 1+ c@ pow2 V2 2+ c@ pow2 - V1 and ( op mimm ) V2 2+ c@ rshift V2 c@ lshift V2 1+ c@ V2 2+ c@ - pow2 1- V2 c@ lshift inv rot and or doto V2 3 + | repeat 2rdrop ; 0 const _ENDL \ End of a list. \ List of triplets that specifies how immediates are arranged in instruction. \ 1 is instr location, 2 upper imm range excluded, 3 lower imm range included create _Il map< c, 20 12 00 _ENDL create _Sl map< c, 25 12 05 07 05 00 _ENDL create _Bl map< c, 31 13 12 25 11 05 08 05 01 07 12 11 _ENDL create _Ul map< c, 12 32 12 _ENDL create _Jl map< c, 31 21 20 21 11 01 20 12 11 12 20 12 _ENDL create _RIl map< c, 20 05 00 _ENDL \ Type to immediate mapping kvtbl[ _I :> 12 _immsz# _Il imm! ; _JR over _S :> 12 _immsz# _Sl imm! ; _B :> 13 _immsz# _Bl imm! ; _U :> 32 _immsz# 12 lshift _Ul imm! ; _J :> 21 _immsz# _Jl imm! ; _RI :> abs 6 _immsz# _RIl imm! ; ]kvtbl _ : imm) over itype@ _ swap ?kvexec not ?abort"imm) on wrong instruction type!" ; \ Type to parameter mapping 3 const _PARAMNO :~ ( "a" "b" "c" -- n ) here# _PARAMNO 0 do ' , loop ; kvtbl[ _R ~ rd) rs1) rs2) _I ~ rd) rs1) imm) _RI ~ rd) rs1) imm) _JR ~ rd) rs1) imm) _S ~ rs2) rs1) imm) _B ~ rs1) rs2) imm) _U ~ rd) imm) drop _J ~ rd) imm) drop ]kvtbl _args : iargs ( op -- a ) itype@ _args swap kv@# ; : _p) 1+ rollk 1- over iargs over 1- 4* + >r 0 do swap V1 @ execute doto V1 4- | loop rdrop ; : 3p) 3 _p) ; : 2p) 2 _p) ; : _chkreg dup 31 > if abort"invalid register!" then ; :~ ( op n a -- ) r! oover iargs _PARAMNO idx ?nip not if r> 4- entryname[] rtype abort" on wrong instruction type!" then rdrop ; :realias _chkrs1 _chkreg ['] rs1) ~ ; :realias _chkrs2 _chkreg ['] rs2) ~ ; :realias _chkrd _chkreg ['] rd) ~ ; \ Branches and jump utilities \ _U to accept LUI and AUIPC create _ctrlflow map< c, _B _J _JR _U : _chkinstr ( op -- ) itype@ _ctrlflow 3 cidx ?nip not ?abort"forward on non control-flow instruction!" ; :> ' dup execute _chkinstr execute, [compile] swap compile imm) ; :> ' execute dup _chkinstr swap [compile] imm) ; compiling [jmp] immediate : forward! ( jmpaddr -- ) here over - ( a rel ) over le@ opc@ AUIPC = if over le@ over _hi imm) oover le! rot 4+ swap swap then ( a rel ) _lo over le@ dup _chkinstr swap imm) swap le! ; \ ====== Instructions ====== :~ does> LOAD swap funct3) ; map< ~ 0 lb) 1 lh) 2 lw) 4 lbu) 5 lhu) :~ does> STORE swap funct3) ; map< ~ 0 sb) 1 sh) 2 sw) :~ does> OP swap funct3) $00 funct7) ; map< ~ 0 add) 1 sll) 2 slt) 3 sltu) 4 xor) 5 srl) 6 or) 7 and) :~ does> OP swap funct3) $20 funct7) ; map< ~ 0 sub) 5 sra) :~ does> OP-IMM swap funct3) ; map< ~ 0 addi) 2 slti) 3 sltiu) 4 xori) 6 ori) 7 andi) : slli) OP-IMM 1 funct3) $00 funct7) ; : srli) OP-IMM 5 funct3) $00 funct7) ; : srai) OP-IMM 5 funct3) $20 funct7) ; :~ does> BRANCH swap funct3) ; map< ~ 0 beq) 1 bne) 4 blt) 5 bge) 6 bltu) 7 bgeu) : jal) JAL ; : jalr) JALR ; : auipc) AUIPC ; : lui) LUI ; :~ does> OP swap funct3) 1 funct7) ; map< ~ 0 mul) 1 mulh) 2 mulhsu) 3 mulhu) 4 div) 5 divu) 6 rem) 7 remu) :~ does> OP-32 swap funct3) 1 funct7) ; map< ~ 0 mulw) 4 divw) 5 divuw) 6 remw) 7 remuw) \ Pseudo instructions : mv) addi) 0 imm) ; : not) xori) -1 imm) ; : neg) sub) 1 to _reverse? xZERO rs2) ; : b) beq) xZERO rs1) xZERO rs2) ; : j) jal) xZERO rd) ; : beqz) beq) xZERO rs2) ; : bnez) bne) xZERO rs2) ; :~ does> execute 1 to _reverse? ; ' blt) ~ bgt) ' bge) ~ ble) ' bltu) ~ bgtu) ' bgeu) ~ bleu) : ret) jalr) xZERO rd) xRA base) 0 imm) ; : ret, ret) ,) ; : nop) addi) xZERO rd) xZERO rs1) 0 imm) ; : nop, nop) ,) ; \ ===== Macros ===== : li, ( reg imm -- ) 12 nbovfl if over lui) swap rd) over _hi imm) ,) dipdup _lo sex12 else x0 swap then ( rd rs1 imm ) addi) 4 roll> 3p) ,) ; : pc>reg, ( r -- ) auipc) swap rd) 0 imm) ,) ; \ Stack manipulation macros : _push, ( r stk-reg -- ) >r addi) r@ r@ -4 3p) ,) sw) swap r> 0 3p) ,) ; : _pop, ( r stk-reg -- ) >r lw) swap r@ 0 3p) ,) addi) r@ r> 4 3p) ,) ; : push, xRSP _push, ; : pop, xRSP _pop, ; : ppush, xPSP _push, ; : ppop, xPSP _pop, ; \ Control flow macros \ Relative addressing : _reg>rd ( reg -- reg ) xRA = xRA * ; \ reg to jalr) rd for tail/call : tcall, ( rel@ reg -- ) >r 21 nbovfl if dup auipc) r@ rd) swap _hi imm) ,) jalr) r@ _reg>rd rd) r> rs1) swap _lo imm) ,) else jal) r> _reg>rd rd) swap imm) ,) then ; : tail, xTAIL tcall, ; : call, xRA tcall, ; \ Absolute addressing : absb, ( abs@ -- ) abs>rel tail, ; : absbl, ( abs@ -- ) abs>rel call, ;