duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

kernel.fs (31266B) - raw


      1 ?f<< /asm/arm.fs
      2 ?f<< /xcomp/tools.fs
      3 
      4 \ HAL opcode structure (close to ARM structure)
      5 \ b3:0   Number bank index
      6 \ b4     Has an nonzero offset
      7 \ b5     Rn is an absolute memory addr in bank if set
      8 \ b11:6  Zeroes
      9 \ b15:12 Rd
     10 \ b19:16 Rn
     11 \ b21:20 Zeroes
     12 \ b22    8-bit if set
     13 \ b23    Inverted destination <>)
     14 \ b24    Dereferenced source &)
     15 \ b25    Immediate if set
     16 \ b26    32-bit if set, 16-bit if unset
     17 \ b27    Zero
     18 \ b31:28 Cond
     19 
     20 \ Macros
     21 : xnip, add) rPSP rdn) CELLSZ imm) ,) ;
     22 : xdrop, rTOP ppop, ;
     23 : xgrow, sub) rPSP rdn) CELLSZ imm) ,) ;
     24 : xdup, rTOP ppush, ;
     25 : pushret, rLR push, ;
     26 : popret, rLR pop, ;
     27 : ret, rLR bx) ,) ;
     28 : absb, abs>rel b) ,) ;
     29 : absbl, abs>rel bl) ,) ;
     30 : abscall, pushret, absbl, popret, ;
     31 : wcall, xwordlbl abscall, ;
     32 : wjmp, xwordlbl abs>rel b) ,) ; \ only for leaf words!
     33 
     34 : pc>reg, ( pc r -- )
     35   dip pc -^ 8 + | ( off r )
     36   mov) over rd) rPC rm) ,)
     37   sub) swap rdn) swap imm) ,) ;
     38 
     39 : pc@>reg, ( pc r -- )
     40   dip pc -^ 8 + | ( off r )
     41   ldr) swap rd) rPC rn) swap -i) ,) ;
     42 
     43 : movi2, ( r n1 n2 -- )
     44   rot mov) over rd) rot imm) ,) ( n1 r )
     45   add) swap rdn) swap imm) ,) ;
     46 
     47 : xconst ( n -- ) pc swap le, xcode xdup, rTOP pc@>reg, ret, ;
     48 
     49 : return) ( -- operand ) mov) rPC rd) rLR rm) ;
     50 : setrd0) ( -- operand ) bic) $f000 imm) ;
     51 : setrn0) ( -- operand ) bic) $f0000 imm) ;
     52 : setimm0) ( -- operand ) bic) $3f imm) ;
     53 
     54 : values ( n -- ) for 0 value next ;
     55 16 values lblimmsplit lbladdnwr lbllitwr lblimmwr
     56           lblrn>rm lblrdn lblrd<>rn lblmov lblswp
     57           lblcwrite lbldwrite lblmoverange lblwriterange lblopwr
     58           lblerrmsg lblmain
     59 $8000 to binstart
     60 binstart const RSTOP
     61 RSTOP $1000 - const PSTOP
     62 $04 const COMPILING
     63 $08 const HERE
     64 $0c const SYSDICT \ our length field lands at COMPILING MSB, which is always 0
     65 $10 const HBANKIDX
     66 $14 const RCNT
     67 $18 const NEXTMETA
     68 $1c const MOD
     69 $20 const NEXTWORD
     70 $24 const BOOTPTR
     71 $28 const HEREMAX
     72 \ 24b unused
     73 $40 const CURWORD
     74 $60 const HBANK
     75 $10000 const HERESTART
     76 \ Basis for all operands. Always cond, 32-bit, Rd=rTOP
     77 $e4009000 const HALBASE
     78 \ Mask for HAL-related flags with no meaning in ARM instructions
     79 $07800000 const HALMASK
     80 $0000003f const HALBMASK
     81 $01000000 const HALDEREF
     82 $02000000 const HALIMM
     83 $00800000 const HALINV
     84 $00000010 const HALOFF
     85 $00000020 const HALMEM
     86 $04000000 const HAL16B
     87 $00400000 const HAL8B
     88 
     89 \ ARM immediate system makes it difficult to place sysvars at arbitrary places
     90 \ in the code and they need to be neatly arranged in an easy to refer
     91 \ base+offset place. However, to facilitate initialization, we also want them to
     92 \ be pre-initialized in the binary, at compile time. For this reason, we place
     93 \ sysvars directly at the beginning of the binary, right after the initial
     94 \ forward jump.
     95 here# to org
     96 forward b) ,) \ coldboot
     97 0 le, \ COMPILING
     98 HERESTART le, \ HERE
     99 0 le, \ SYSDICT
    100 0 le, \ HBANKIDX
    101 0 le, \ RCNT
    102 0 le, \ NEXTMETA
    103 0 le, \ MOD
    104 0 le, \ NEXTWORD
    105 0 le, \ BOOTPTR
    106 $10000000 le, \ HEREMAX
    107 $18 allot0 \ unused
    108 $20 allot0 \ CURWORD
    109 $40 allot0 \ HBANK
    110 binstart HERE + xconst HERE
    111 binstart SYSDICT + xconst sysdict
    112 binstart RCNT + xconst [rcnt]
    113 binstart NEXTMETA + xconst nextmeta
    114 binstart MOD + xconst MOD
    115 binstart NEXTWORD + xconst NEXTWORD
    116 binstart HEREMAX + xconst HEREMAX
    117 binstart CURWORD + xconst curword
    118 HERESTART xconst herestart
    119 PSTOP xconst PSTOP
    120 RSTOP xconst RSTOP
    121 12 xconst DOESSZ
    122 4 xconst BRSZ
    123 
    124 xcode bye 0 b) ,)
    125 xcode dbg 0 b) ,)
    126 
    127 pc to L1 \ fail
    128   mov) rTOP rd) 0 imm) ,)
    129   ret,
    130 
    131 \ parse char
    132 pc to L2 \ rTOP=a-with-'-skipped r0=u
    133   cmp) r0 rn) 3 imm) ,)
    134   L1 abs>rel b) ne) ,)
    135   ldr) r0 rd) rTOP rn) ,)
    136   and) r1 rd) r0 rn) $ff00 imm) ,)
    137   cmp) r1 rn) $2700 imm) ,) \ ' char
    138   L1 abs>rel b) ne) ,)
    139   and) r0 rdn) $ff imm) ,)
    140   r0 ppush,
    141   mov) rTOP rd) 1 imm) ,)
    142   ret,
    143 
    144 \ parse hexadecimal
    145 pc to L3 \ rTOP=a-with-$-skipped r0=u
    146   cmp) r0 rn) 2 imm) ,)
    147   L1 abs>rel b) lo) ,)
    148   sub) r0 rdn) 1 imm) ,) \ skip $
    149   mov) r2 rd) 0 imm) ,) \ accumulated result
    150 pc \ loop
    151   ldr) r1 rd) rTOP rn) 8b) 1 +i) post) ,)
    152   orr) r1 rdn) $20 imm) ,)
    153   sub) r1 rdn) '0' imm) f) ,)
    154   L1 abs>rel b) lo) ,)
    155   cmp) r1 rn) 10 imm) ,)
    156   forward b) lo) ,) to L4 \ parse ok, under 10
    157   sub) r1 rdn) 'a' '0' - imm) f) ,)
    158   L1 abs>rel b) lo) ,)
    159   add) r1 rdn) 10 imm) ,)
    160   cmp) r1 rn) 16 imm) ,)
    161   L1 abs>rel b) hs) ,)
    162 L4 forward! \ parse ok
    163   add) r2 rd) r1 rn) r2 rm) 4 lsl) ,) \ r2 = r2*16 + r1
    164   sub) r0 rdn) 1 imm) f) ,)
    165   ( loop ) abs>rel b) nz) ,)
    166   r2 ppush,
    167   mov) rTOP rd) 1 imm) ,)
    168   ret,
    169 
    170 \ parse unsigned decimal
    171 pc to L4 \ rTOP=a+1 r1=first-char r0=u
    172   mov) r4 rd) r1 rm) ,) \ for '-' check
    173   cmp) r1 rn) '-' imm) ,)
    174   ldr) z) r1 rd) rTOP rn) 8b) 1 +i) post) ,)
    175   sub) z) r0 rdn) 1 imm) f) ,)
    176   L1 abs>rel b) z) ,) \ '-' only? can't parse
    177   mov) r2 rd) 0 imm) ,) \ accumulated result
    178   mov) r3 rd) 10 imm) ,) \ const for mul)
    179 pc \ loop
    180   sub) r1 rdn) '0' imm) f) ,)
    181   L1 abs>rel b) lo) ,)
    182   cmp) r1 rn) 10 imm) ,)
    183   L1 abs>rel b) hs) ,)
    184   mul) r2 rd) r3 rm) r2 rs) r1 acc) ,)
    185   ldr) r1 rd) rTOP rn) 8b) 1 +i) post) ,)
    186   sub) r0 rdn) 1 imm) f) ,)
    187   ( loop ) abs>rel b) nz) ,)
    188   cmp) r4 rn) '-' imm) ,)
    189   rsb) z) r2 rdn) 0 imm) ,) \ negate
    190   r2 ppush,
    191   mov) rTOP rd) 1 imm) ,)
    192   ret,
    193 
    194 xcode parse ( str -- n? f )
    195   ldr) r0 rd) rTOP rn) 8b) 1 +i) post) ,) \ rTOP=a r0=u
    196   ldr) r1 rd) rTOP rn) 8b) 1 +i) post) ,)
    197   cmp) r1 rn) ''' imm) ,)
    198   L2 abs>rel b) eq) ,)
    199   cmp) r1 rn) '$' imm) ,)
    200   L3 abs>rel b) eq) ,)
    201   mov) r2 rd) r1 rm) ,)
    202   L4 abs>rel b) ,)
    203 
    204 xcode rtype ret, \ placeholder
    205 
    206 xcode compiling
    207   xdup, rTOP binstart COMPILING movi2,
    208   ldr) rTOP rdn) ,)
    209   ret,
    210 
    211 xcode [ ximm
    212   mov) r0 rd) 0 imm) ,)
    213   r1 binstart COMPILING movi2,
    214   str) r0 rd) r1 rn) ,)
    215   ret,
    216 
    217 pc to L1 \ set MOD to 0
    218   mov) r0 rd) 0 imm) ,)
    219   r1 binstart MOD movi2,
    220   str) r0 rd) r1 rn) ,)
    221   ret,
    222 xcode quit
    223   mov) rSP rd) RSTOP imm) ,)
    224   L1 abs>rel bl) ,)
    225   wcall, [
    226   forward b) ,) to lblmain \ never returns
    227 
    228 xcode (abort)
    229   ( coldboot ) forward!
    230   mov) rPSP rd) PSTOP imm) ,)
    231   wjmp, quit
    232 
    233 \ During early boot, it's better to halt the machine than to go back to the
    234 \ mainloop because the mainloop likely sends us to an infinite error loop
    235 \ through boot<.
    236 pc ," boot failure"
    237 xcode abort
    238   ( pc ) r0 pc>reg,
    239   r0 ppush,
    240   mov) rTOP rd) 12 imm) ,)
    241   wcall, rtype
    242   0 b) ,)
    243 
    244 xcode findmeta ( id ll -- ll-or-0 ) \ preserves r6
    245   r0 ppop,
    246 pc to L2 \ r0=id rTOP=ll
    247   cmp) rTOP rn) 0 imm) ,)
    248   return) z) ,) \ not found
    249   ldr) r1 rd) rTOP rn) 4 +i) ,)
    250   cmp) r0 rn) r1 rm) ,)
    251   return) z) ,) \ found
    252   ldr) rTOP rdn) ,)
    253   L2 abs>rel b) ,)
    254 
    255 xcode findmod ( w -- w )
    256   r0 binstart MOD movi2, ldr) r0 rdn) ,)
    257   cmp) r0 rn) 0 imm) ,)
    258   return) z) ,) \ no mod
    259   mov) r6 rd) rTOP rm) ,) \ save w
    260   sub) rTOP rdn) 8 imm) ,) \ rTOP=ll
    261   pushret, L2 abs>rel bl) ,) popret,
    262   cmp) rTOP rn) 0 imm) ,)
    263   mov) z) rTOP rd) r6 rm) ,) \ restore w if meta not found
    264   return) z) ,) \ no mod
    265   pushret, L1 abs>rel bl) ,) popret,
    266   add) rTOP rdn) 8 imm) ,)
    267   ret,
    268 
    269 pc to lblerrmsg \ r0=sa r1=sl
    270   r0 ppush,
    271   mov) rTOP rd) r1 rm) ,)
    272   wcall, rtype
    273   wjmp, (abort)
    274 
    275 xcode boot<
    276   r0 binstart BOOTPTR movi2,
    277   ldr) r1 rd) r0 rn) ,)
    278   xdup, ldr) rTOP rd) r1 rn) 8b) 1 +i) post) ,)
    279   str) r1 rd) r0 rn) ,)
    280   ret,
    281 
    282 xcode in< wjmp, boot<
    283 
    284 pc to lblmoverange \ r0=src r1=len r2=dst. out: r0=src+len r2=dst+len Saves r3
    285   cmp) r1 rn) 0 imm) ,) \ guard against zero
    286   return) z) ,)
    287   pc
    288     ldr) r4 rd) r0 rn) 8b) 1 +i) post) ,)
    289     str) r4 rd) r2 rn) 8b) 1 +i) post) ,)
    290     sub) r1 rdn) 1 imm) f) ,)
    291     ( pc ) abs>rel b) ne) ,)
    292   ret,
    293 
    294 pc \ we have a nonzero lblnextword. r0=src
    295   r1 binstart NEXTWORD movi2,
    296   mov) r2 rd) 0 imm) ,)
    297   str) r2 rd) r1 rn) ,)
    298   ldr) r1 rd) r0 rn) 8b) ,) \ len
    299   add) r1 rdn) 1 imm) ,)
    300   r2 binstart CURWORD movi2, \ dst
    301   mov) rTOP rd) r2 rm) ,)
    302   lblmoverange abs>rel b) ,)
    303 
    304 xcode maybeword ( -- str-or-0 )
    305   xdup,
    306   r0 binstart NEXTWORD movi2, ldr) r0 rdn) ,)
    307   cmp) r0 rn) 0 imm) ,)
    308   ( pc ) abs>rel b) ne) ,)
    309   pc
    310     wcall, in<
    311     xnip,
    312     cmp) rTOP rn) 0 imm) ,)
    313     mov) le) rTOP rd) 0 imm) ,)
    314     return) le) ,) \ EOF
    315     cmp) rTOP rn) SPC imm) ,)
    316     ( pc ) abs>rel b) le) ,) \ rTOP=first non-ws
    317   mov) r6 rd) 0 imm) ,)
    318   r5 binstart CURWORD movi2,
    319   pc
    320     add) r6 rdn) 1 imm) ,)
    321     str) rTOP rd) r5 rn) 8b) 1 +i) pre) !) ,)
    322     wcall, in<
    323     xnip,
    324     cmp) rTOP rn) SPC imm) ,)
    325     ( pc ) abs>rel b) gt) ,)
    326   rTOP binstart CURWORD movi2,
    327   str) r6 rd) rTOP rn) 8b) ,)
    328   ret,
    329 
    330 pc ," word expected" alignhere
    331 xcode word
    332   wcall, maybeword
    333   ( pc ) r0 pc>reg,
    334   mov) r1 rd) 13 imm) ,)
    335   cmp) rTOP rn) 0 imm) ,)
    336   lblerrmsg abs>rel b) z) ,)
    337   ret,
    338 
    339 pc ,"  word not found" alignhere
    340 xcode (wnf)
    341   r0 binstart CURWORD movi2,
    342   ldr) rTOP rd) r0 rn) 8b) 1 +i) post) ,)
    343   r0 ppush,
    344   wcall, rtype
    345   ( pc ) r0 pc>reg,
    346   mov) r1 rd) 15 imm) ,)
    347   lblerrmsg abs>rel b) ,)
    348 
    349 xcode execute ( a -- )
    350   mov) r0 rd) rTOP rm) ,)
    351   xdrop,
    352   r0 bx) ,)
    353 
    354 xcode find ( name 'dict -- w-or-0 )
    355   r2 ppop,
    356   ldr) r1 rd) r2 rn) 8b) 1 +i) post) ,) \ r2=a r1=len
    357 pc \ loop1
    358   ldr) r3 rd) rTOP rn) 8b) 5 -i) ,) \ entry len
    359   and) r3 rdn) $3f imm) ,) \ remove flags
    360   cmp) r1 rn) r3 rm) ,)
    361   forward b) ne) ,) to L1
    362   \ same length
    363   sub) r4 rd) rTOP rn) 5 imm) ,)
    364   sub) r4 rdn) r1 rm) ,) \ beginning of name range
    365   mov) r3 rd) 0 imm) ,)
    366 pc \ loop2
    367   ldr) r5 rd) r4 rn) 8b) r3 +r) ,)
    368   ldr) r0 rd) r2 rn) 8b) r3 +r) ,)
    369   cmp) r5 rn) r0 rm) ,)
    370   forward b) ne) ,) to L2
    371   add) r3 rdn) 1 imm) ,)
    372   cmp) r3 rn) r1 rm) ,)
    373   ( loop2 ) abs>rel b) ne) ,)
    374   \ same contents
    375   add) rTOP rdn) 4 imm) ,) \ e>w
    376   ret,
    377 L2 forward! L1 forward! \ not matching, try next
    378   ldr) rTOP rdn) 0 +i) ,)
    379   cmp) rTOP rn) 0 imm) ,)
    380   ( loop1 ) abs>rel b) ne) ,)
    381   \ not found
    382   ret,
    383 
    384 pc to lblcwrite \ r0=char
    385   r2 binstart HERE movi2,
    386   ldr) r1 rd) r2 rn) ,)
    387   str) r0 rd) r1 rn) 8b) 1 +i) post) ,)
    388   str) r1 rd) r2 rn) ,)
    389   ret,
    390 
    391 pc to lbldwrite \ r0=n. Destroys r1 and r2, preserves rest and flags
    392   r2 binstart HERE movi2,
    393   ldr) r1 rd) r2 rn) ,)
    394   str) r0 rd) r1 rn) 4 +i) post) ,)
    395   str) r1 rd) r2 rn) ,)
    396   ret,
    397 
    398 pc to lblwriterange \ r0=addr r1=len
    399   r3 binstart HERE movi2,
    400   ldr) r2 rd) r3 rn) ,)
    401   pushret, lblmoverange abs>rel bl) ,) popret,
    402   str) r2 rd) r3 rn) ,)
    403   ret,
    404 
    405 xcode entry pushret, ( 'dict s -- )
    406   r0 binstart RCNT movi2,
    407   mov) r1 rd) 0 imm) ,)
    408   str) r1 rd) r0 rn) ,)
    409   mov) r6 rd) rTOP rm) ,)
    410   ldr) r5 rd) r6 rn) 8b) 1 +i) post) ,) \ r5=a r6=len
    411   add) rTOP rd) r5 rn) 1 imm) ,) \ rTOP=len+1
    412   r0 binstart HERE movi2,
    413   ldr) r1 rd) r0 rn) ,)
    414   add) r2 rd) r1 rn) rTOP rm) ,)
    415   and) r2 rdn) 3 imm) f) ,)
    416   sub) ne) r1 rdn) r2 rm) ,)
    417   add) ne) r1 rdn) 4 imm) ,)
    418   str) ne) r1 rd) r0 rn) ,)
    419   xdrop, \ rTOP='dict
    420   mov) r0 rd) r6 rm) ,)
    421   mov) r1 rd) r5 rm) ,)
    422   lblwriterange absbl,
    423   mov) r0 rd) r5 rm) ,)
    424   lblcwrite absbl,
    425   r0 binstart NEXTMETA movi2,
    426   ldr) r0 rdn) ,)
    427   lbldwrite absbl,
    428   ldr) r0 rd) rTOP rn) ,) \ r0=dict
    429   r1 binstart HERE movi2, ldr) r1 rdn) ,)
    430   str) r1 rd) rTOP rn) ,) \ "here" is new sysdict
    431   xdrop,
    432   popret,
    433   lbldwrite abs>rel b) ,)
    434 
    435 xcode code
    436   wcall, sysdict
    437   wcall, word
    438   wjmp, entry
    439 
    440 pc to L1 \ r3=meta-id
    441   r2 binstart SYSDICT movi2, ldr) r2 rdn) ,)
    442   r0 binstart HERE movi2, ldr) r0 rdn) ,)
    443   sub) r2 rdn) 4 imm) ,)
    444   swp) r0 rd) r2 rn) r0 rm) ,)
    445   pushret, lbldwrite abs>rel bl) ,) popret,
    446   mov) r0 rd) r3 rm) ,)
    447   lbldwrite abs>rel b) ,)
    448 
    449 xcode code16b mov) r3 rd) EMETA_16B imm) ,) L1 abs>rel b) ,)
    450 xcode code8b mov) r3 rd) EMETA_8B imm) ,) L1 abs>rel b) ,)
    451 
    452 \ HAL operands
    453 HALBASE rTOP rn) xconst W)
    454 HALBASE rA rn) xconst A)
    455 HALBASE rPSP rn) xconst PSP)
    456 HALBASE rSP rn) xconst RSP)
    457 0 eq) xconst Z)
    458 0 ne) xconst NZ)
    459 0 hs) xconst >=)
    460 0 lo) xconst <)
    461 0 hi) xconst >)
    462 0 ls) xconst <=)
    463 0 ge) xconst s>=)
    464 0 lt) xconst s<)
    465 0 gt) xconst s>)
    466 0 le) xconst s<=)
    467 
    468 xcode _hbank' ( slot -- a ) \ Preserves r0 r1 r2
    469   and) r3 rd) rTOP rn) $f imm) ,)
    470   rTOP binstart HBANK movi2,
    471   add) rTOP rdn) r3 rm) 2 lsl) ,)
    472   ret,
    473 
    474 xcode hbank' ( slot -- a ) \ Preserves r0 r1 r2
    475   and) r3 rd) rTOP rn) $f imm) ,)
    476   rTOP binstart HBANK movi2,
    477   add) rTOP rdn) r3 rm) 2 lsl) ,)
    478   ret,
    479 
    480 xcode hbank@ ( slot -- n )
    481   wcall, _hbank'
    482   ldr) rTOP rdn) ,)
    483   ret,
    484 
    485 xcode hbank! ( n -- slot )
    486   r0 binstart HBANKIDX movi2,
    487   mov) r1 rd) rTOP rm) ,)
    488   ldr) rTOP rd) r0 rn) ,)
    489   and) r2 rd) rTOP rn) $f imm) ,)
    490   wcall, _hbank'
    491   str) r1 rd) rTOP rn) ,)
    492   mov) rTOP rd) r2 rm) ,)
    493   add) r2 rdn) 1 imm) ,)
    494   str) r2 rd) r0 rn) ,)
    495   ret,
    496 
    497 pc HALBASE HALMEM or le,
    498 xcode m) ( a -- operand )
    499   wcall, hbank!
    500   ( pc ) r0 pc@>reg,
    501   orr) rTOP rdn) r0 rm) ,)
    502   ret,
    503 
    504 pc HALBASE HALIMM or le,
    505 xcode i) ( n -- operand )
    506   wcall, hbank!
    507   ( pc ) r0 pc@>reg,
    508   orr) rTOP rdn) r0 rm) ,)
    509   ret,
    510 
    511 \ Instead of using a new number bank, add n to operand's current bank
    512 pc to L1 ( operand n -- operand )
    513   rTOP push,
    514   ldr) rTOP rd) rPSP rn) ,) \ rTOP=operand
    515   wcall, hbank'
    516   ldr) r0 rd) rTOP rn) ,)
    517   r1 pop,
    518   add) r0 rdn) r1 rm) ,)
    519   str) r0 rd) rTOP rn) ,)
    520   xdrop, ret,
    521 
    522 xcode +) ( operand n -- operand )
    523   ldr) r0 rd) rPSP rn) ,)
    524   tst) r0 rn) HALIMM imm) ,)
    525   L1 abs>rel b) nz) ,)
    526   tst) r0 rn) HALMEM HALOFF or imm) ,)
    527   L1 abs>rel b) nz) ,)
    528   wcall, hbank!
    529   ldr) r0 rd) rPSP rn) ,)
    530   xnip,
    531   orr) rTOP rdn) r0 rm) ,)
    532   orr) rTOP rdn) HALOFF imm) ,)
    533   ret,
    534 
    535 xcode 8b) ( operand -- operand )
    536   orr) rTOP rdn) HAL8B imm) ,)
    537   ret,
    538 
    539 xcode 16b) ( operand -- operand )
    540   bic) rTOP rdn) HAL16B imm) ,)
    541   ret,
    542 
    543 xcode 32b) ( operand -- operand )
    544   bic) rTOP rdn) HAL8B imm) ,)
    545   orr) rTOP rdn) HAL16B imm) ,)
    546   ret,
    547 
    548 xcode A>) ( operand -- operand )
    549   setrd0) rTOP rdn) ,)
    550   orr) rTOP rdn) rA 12 lshift imm) ,)
    551   ret,
    552 
    553 xcode <>) ( operand -- operand )
    554   orr) rTOP rdn) HALINV imm) ,)
    555   ret,
    556 
    557 xcode &) ( operand -- operand )
    558   tst) rTOP rn) HALMEM imm) ,)
    559   bic) nz) rTOP rdn) HALMEM imm) ,)
    560   orr) nz) rTOP rdn) HALIMM imm) ,)
    561   orr) z) rTOP rdn) HALDEREF imm) ,)
    562   ret,
    563 
    564 \ HAL operations
    565 \ r0 is used as the immediate accumulator
    566 \ TODO: add out-of-range error for offsets not fitting 12 bits
    567 
    568 \ merge operand with instr and write
    569 pc to lblopwr ( operand -- ) \ r0=base instr. Preserves r3
    570   bic) rTOP rdn) HALMASK imm) ,)
    571   orr) r0 rdn) rTOP rm) ,)
    572   xdrop,
    573   lbldwrite abs>rel b) ,)
    574 
    575 \ Extract 12b rotate+imm from n. Preserves r0
    576 pc to lblimmsplit \ In: rTOP=n Out: rTOP=rotate+imm r1=rest of n.
    577   mov) r2 rd) 0 imm) ,) \ r2=rotate
    578   mov) r1 rd) 0 imm) ,)
    579   cmp) rTOP rn) $100 imm) ,)
    580   return) lo) ,)
    581 pc
    582   mov) r3 rd) rTOP rm) r2 rlsr) f) ,)
    583   return) z) ,) \ rTOP is zero, nothing to do
    584   tst) r3 rn) 3 imm) ,)
    585   add) z) r2 rdn) 2 imm) ,)
    586   ( pc ) abs>rel b) z) ,)
    587   and) r3 rdn) $ff imm) ,) \ r3=8b imm
    588   sub) r1 rd) rTOP rn) r3 rm) r2 rlsl) f) ,) \ r1=rest of n
    589   rsb) r2 rdn) 0 imm) ,) \ rotate is to the *right*
    590   and) r2 rdn) $1e imm) ,) \ 0-32, even numbers
    591   orr) rTOP rd) r3 rn) r2 rm) 7 lsl) ,) \ rTOP=rotate+imm
    592   ret,
    593 
    594 \ Compile a add) of immediate "n" with target register selected in r1
    595 pc add) 0 imm) f) ,)
    596 pc to lbladdnwr ( n -- ) \ r1=Rd/Rn
    597   cmp) rTOP rn) 0 imm) ,) \ if n=0, don't write anything
    598   ldr) z) rTOP rd) rPSP rn) CELLSZ +i) post) ,)
    599   return) z) ,)
    600   ( pc ) r0 pc@>reg,
    601   orr) r0 rdn) r1 rm) 12 lsl) ,)
    602   orr) r0 rdn) r1 rm) 16 lsl) ,)
    603   tst) rTOP rn) $80000000 imm) ,)
    604   eor) ne) r0 rdn) $00c00000 imm) ,) \ add) to sub)
    605   rsb) ne) rTOP rdn) 0 imm) ,) \ negate rTOP
    606   pushret,
    607 pc
    608   lblimmsplit abs>rel bl) ,)
    609   r0 push,
    610   orr) r0 rdn) rTOP rm) ,)
    611   mov) rTOP rd) r1 rm) ,)
    612   lbldwrite abs>rel bl) ,)
    613   r0 pop,
    614   cmp) rTOP rn) 0 imm) ,)
    615   ( pc ) abs>rel b) nz) ,)
    616   xdrop, popret, ret,
    617 
    618 xcode rs+, ( n -- )
    619   r0 binstart RCNT movi2,
    620   ldr) r1 rd) r0 rn) ,)
    621   add) r1 rdn) rTOP rm) ,)
    622   str) r1 rd) r0 rn) ,)
    623   mov) r1 rd) rSP imm) ,) lbladdnwr abs>rel b) ,)
    624 
    625 xcode ps+, ( n -- )
    626   mov) r1 rd) rPSP imm) ,) lbladdnwr abs>rel b) ,)
    627 
    628 \ Compile code resulting in register Rd to contain "n"
    629 pc mov) 0 imm) ,)
    630 pc to lbllitwr ( n -- ) \ r0=Rd
    631   pushret, r0 push,
    632   lblimmsplit abs>rel bl) ,)
    633   r1 ppush, ( rest imm+rotate )
    634   ( pc ) r3 pc@>reg,
    635   orr) r0 rd) r3 rn) r0 rm) 12 lsl) ,) \ merge Rd in instr
    636   lblopwr abs>rel bl) ,)
    637   r1 pop, popret, \ r1=Rd
    638   lbladdnwr abs>rel b) ,)
    639 
    640 \ Checks if operand is i) or m). If it is, compile a write of this value to r0
    641 \ and modify operand in consequence
    642 pc to lblimmwr ( operand -- operand ) \ preserves r0
    643   tst) rTOP rn) HALMEM imm) ,)
    644   return) z) ,) \ not a m) operand
    645   r0 push,
    646   xdup, wcall, hbank@
    647   mov) r0 rd) r1 imm) ,)
    648   pushret, lbllitwr abs>rel bl) ,) popret, ( operand )
    649   setrn0) rTOP rdn) ,)
    650   orr) rTOP rdn) $10000 imm) ,) \ Rn=r1
    651   bic) rTOP rdn) HALBMASK imm) ,)
    652   r0 pop,
    653   ret,
    654 
    655 \ Move Rn to Rm in operand
    656 pc to lblrn>rm \ rTOP=operand
    657   \ move Rn to Rm
    658   bic) rTOP rdn) HALBMASK imm) ,)
    659   mov) r0 rd) rTOP rm) 16 lsr) ,)
    660   and) r0 rdn) $f imm) ,)
    661   orr) rTOP rdn) r0 rm) ,)
    662   bic) rTOP rdn) $f0000 imm) ,) \ clear Rn
    663   ret,
    664 
    665 \ Copy Rd to Rn in operand.
    666 pc to lblrdn \ rTOP=operand. preserves r0
    667   bic) rTOP rdn) $f0000 imm) ,) \ clear Rn
    668   and) r1 rd) rTOP rn) $f000 imm) ,)
    669   orr) rTOP rdn) r1 rm) 4 lsl) ,)
    670   ret,
    671 
    672 \ Swap Rd and Rn in operand
    673 pc to lblrd<>rn \ rTOP=operand
    674   and) r0 rd) rTOP rn) $f000 imm) ,)
    675   and) r1 rd) rTOP rn) $f0000 imm) ,)
    676   bic) rTOP rdn) $ff000 imm) ,)
    677   orr) rTOP rdn) r0 rm) 4 lsl) ,)
    678   orr) rTOP rdn) r1 rm) 4 lsr) ,)
    679   ret,
    680 
    681 \ Write a mov) from operand's src to operand *dereferenced* dst. If operand has
    682 \ an offset, a add) is written after the mov).
    683 pc mov) ,)
    684 pc to lblmov ( operand -- )
    685   tst) rTOP rn) HALINV imm) ,)
    686   pushret, lblrd<>rn abs>rel bl) nz) ,) popret,
    687   xdup, ( op op )
    688   lblrn>rm abscall,
    689   ( pc ) r0 pc@>reg,
    690   lblopwr abscall, ( op )
    691   tst) rTOP rn) HALOFF imm) ,)
    692   and) r1 rd) rTOP rn) $f000 imm) ,) \ Rd
    693   mov) r1 rd) r1 rm) 12 lsr) ,)
    694   wcall, hbank@
    695   lbladdnwr abs>rel b) nz) ,)
    696   xdrop, ret,
    697 
    698 \ Write an eor between operand's src and dereferenced dst.
    699 pc eor) ,)
    700 pc to L2 ( operand -- )
    701   lblrn>rm abscall,
    702   lblrdn abscall,
    703   ( pc ) r0 pc@>reg,
    704   lblopwr abs>rel b) ,)
    705 
    706 \ Write a swap between operand's src to operand *dereferenced* dst. Offsets are
    707 \ ignored. Registers only
    708 pc to lblswp ( operand -- )
    709   pushret,
    710   xdup, xdup,
    711   L2 abs>rel bl) ,)
    712   lblrd<>rn abs>rel bl) ,)
    713   L2 abs>rel bl) ,)
    714   popret,
    715   L2 abs>rel b) ,)
    716 
    717 pc rsb) rTOP rdn) 0 imm) ,)
    718 xcode -W, ( -- )
    719   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
    720 
    721 \ if HALOFF is set in operand, fetch number associated with hbank in r1, and
    722 \ if that number is negative, unset the U (up/down) bit of the instruction in
    723 \ r0. Also set HALMASK to 0 in operand.
    724 \ Z is set according to whether HALOFF was there: Z=no HALOFF NZ=HALOFF
    725 \ TODO: support numbers over 12b
    726 pc to L1 ( operand -- ) \ r0=instr r1=bank number
    727   tst) rTOP rn) HALOFF imm) ,) \ has offset?
    728   return) z) ,)
    729   rTOP push, wcall, hbank@ mov) r1 rd) rTOP rm) f) ,) rTOP pop,
    730   bic) mi) r0 rdn) $00800000 imm) ,) \ negative, unset U bit
    731   rsb) mi) r1 rdn) 0 imm) ,)
    732   bic) rTOP rdn) HALBMASK imm) f) ,) \ unset Z
    733   ret,
    734 
    735 \ conditionally merge hbank with operand, then with instr then write
    736 pc to L2 ( operand -- ) \ r0=instr
    737   L1 abscall,
    738   orr) nz) rTOP rdn) r1 rm) ,)
    739   lblopwr abs>rel b) ,)
    740 
    741 \ operand is 16b
    742 pc to L3 ( operand -- ) \ r0=base instr
    743   orr) r0 rdn) $b0 imm) ,) \ make into a ldrh/strh op
    744   bic) r0 rdn) $04000000 imm) ,)
    745   orr) r0 rdn) $00400000 imm) ,) \ immediate
    746   L1 abscall,
    747   mov) nz) r2 rd) r1 rm) 4 lsl) ,) \ imm high nibble
    748   and) nz) r1 rdn) $f imm) ,)
    749   and) nz) r2 rdn) $f00 imm) ,)
    750   orr) nz) r0 rdn) r1 rm) ,) \ apply low nibble
    751   orr) nz) r0 rdn) r2 rm) ,) \ apply high nibble
    752   lblopwr abs>rel b) ,)
    753 
    754 \ Write a ldr) or str), depending on instr
    755 pc to L4 ( operand -- ) \ r0=instr
    756   lblimmwr abscall,
    757   tst) rTOP rn) HALINV imm) ,)
    758   eor) nz) r0 rdn) $100000 imm) ,) \ toggle LDR/STR
    759   tst) rTOP rn) HAL16B imm) ,)
    760   L3 abs>rel b) z) ,)
    761   L2 abs>rel b) ,)
    762 \ Write number specified in bank as an immediate to operand's target
    763 pc to L3 ( operand -- )
    764   mov) r0 rd) rTOP rm) 12 lsr) ,)
    765   and) r0 rdn) $f imm) ,)
    766   wcall, hbank@
    767   lbllitwr abs>rel b) ,)
    768 pc ldr) 0 +i) ,)
    769 xcode @, ( operand -- ) \ Compiled code preserves r0
    770   tst) rTOP rn) HALIMM imm) ,)
    771   L3 abs>rel b) nz) ,)
    772   tst) rTOP rn) HALDEREF imm) ,)
    773   lblmov abs>rel b) nz) ,)
    774   ( pc ) r0 pc@>reg, L4 abs>rel b) ,)
    775 
    776 xcode !, ( operand -- )
    777   eor) rTOP rdn) HALINV imm) ,)
    778   wjmp, @,
    779 
    780 pc to L1 ( operand -- ) \ r0=base instr
    781   \ set offset to 4, 2, or 1
    782   mov) r1 rd) 4 imm) ,)
    783   tst) rTOP rn) HAL16B imm) ,)
    784   mov) z) r1 rd) 2 imm) ,)
    785   tst) rTOP rn) HAL8B imm) ,)
    786   mov) nz) r1 rd) 1 imm) ,)
    787   orr) r0 rdn) r1 rm) ,)
    788   L4 absb,
    789 
    790 pc ldr) 0 +i) post) ,)
    791 xcode @+, ( operand -- )
    792   ( pc ) r0 pc@>reg, L1 abs>rel b) ,)
    793 
    794 xcode !+, ( operand -- )
    795   eor) rTOP rdn) HALINV imm) ,)
    796   wjmp, @+,
    797 
    798 pc ldr) 0 -i) pre) !) ,)
    799 xcode -@, ( operand -- )
    800   ( pc ) r0 pc@>reg, L1 abs>rel b) ,)
    801 
    802 xcode -!, ( operand -- )
    803   eor) rTOP rdn) HALINV imm) ,)
    804   wjmp, -@,
    805 
    806 pc add) 0 imm) ,)
    807 pc to L1 ( operand -- )
    808   rTOP push, wcall, hbank@ mov) r0 rd) rTOP rm) ,) rTOP pop,
    809   tst) rTOP rn) HALMEM imm) ,)
    810   mov) nz) rTOP rd) r0 rm) ,)
    811   mov) nz) r0 rd) rTOP imm) ,)
    812   lbllitwr abs>rel b) nz) ,) \ m) operand
    813   ( pc ) r0 pc@>reg, L2 abs>rel b) ,)
    814 
    815 \ operand is 16b and ARM doesn't have a 16b SWP! LDR+STR+MOV...
    816 pc mov) rTOP rd) r0 rm) ,)
    817 pc to L3 ( operand -- )
    818   xdup,
    819   setrd0) rTOP rdn) ,)
    820   wcall, @, wcall, !,
    821   ( pc ) r0 pc@>reg,
    822   lbldwrite abs>rel b) ,)
    823 
    824 pc swp) rTOP rd) rTOP rm) ,)
    825 xcode @!, ( operand -- )
    826   lblimmwr abscall,
    827   tst) rTOP rn) HALDEREF imm) ,)
    828   lblswp abs>rel b) nz) ,)
    829   tst) rTOP rn) HAL16B imm) ,)
    830   L3 abs>rel b) z) ,)
    831   tst) rTOP rn) HALOFF imm) ,) \ has offset?
    832   forward b) z) ,)
    833     xdup, setrd0) rTOP rdn) ,)
    834     L1 abscall,
    835     setrn0) rTOP rdn) ,)
    836   forward!
    837   \ TODO: figure out how HALBMASK can be nonzero at this point. Theoretically,
    838   \ it's always zero, but without this line, we fail.
    839   setimm0) rTOP rdn) ,)
    840   ( pc ) r0 pc@>reg,
    841   lblopwr abs>rel b) ,)
    842 
    843 \ Handle "mul" by moving Rn to Rm, setting Rn to zero.
    844 pc to L1 ( operand -- ) \ r0=instr
    845   and) r1 rd) rTOP rn) $f000 imm) ,) \ Rn
    846   bic) rTOP rdn) $f000 imm) ,)
    847   orr) rTOP rdn) r1 rm) 4 lsr) ,)
    848   lblopwr abs>rel b) ,)
    849 
    850 \ Proxy lblopwr with this processing:
    851 \ 1. Remove OP8B which messes with arithmetic opcodes
    852 \ 2. If opcode is one of the "comparison" opcodes, forcefully set Rd to 0 before
    853 \    writing it off.
    854 \ 3. Also check for "mul".
    855 pc to L4 ( operand -- ) \ r0=instr
    856   bic) rTOP rdn) HAL8B imm) ,)
    857   and) r1 rd) r0 rn) $01900000 imm) ,)
    858   cmp) r1 rn) $01100000 imm) ,)
    859   setrd0) z) rTOP rdn) ,)
    860   and) z) r1 rd) r0 rn) $01900000 imm) ,)
    861   and) r1 rd) r0 rn) $0ff00000 imm) ,)
    862   and) r2 rd) r0 rn) $000000f0 imm) ,)
    863   orr) r1 rdn) r2 rm) ,)
    864   cmp) r1 rn) $00000090 imm) ,)
    865   L1 abs>rel b) z) ,)
    866   lblopwr abs>rel b) ,)
    867 
    868 \ Write arithmetic operation with an immediate src
    869 pc to L3 ( operand -- ) \ r0=instr
    870   \ TODO: avoid step by encoding imm) directly when possible
    871   r0 push,
    872   xdup, ( op op )
    873   setrd0) rTOP rdn) ,)
    874   wcall, @, ( op ) \ imm in r0
    875   r0 pop, \ r0=instr
    876   setimm0) rTOP rdn) ,)
    877   lblrdn abscall,
    878   L4 abs>rel b) ,) ( )
    879 
    880 \ Write inverted arithmetic operation, that is:
    881 \ 1. Load operand's src in r0
    882 \ 2. Apply instr with r0 as Rd and Rn and operand's dst as Rm.
    883 \ 3. Store r0 in operand's src
    884 pc to L2 ( operand -- ) \ r0=instr
    885   bic) rTOP rdn) HALINV imm) ,)
    886   r0 push,
    887   lblimmwr abscall,
    888   xdup, ( op op )
    889   setrd0) rTOP rdn) ,)
    890   wcall, @, ( op )
    891   xdup, ( op op )
    892   setimm0) rTOP rdn) ,)
    893   lblrd<>rn abscall,
    894   setrd0) rTOP rdn) ,)
    895   lblrn>rm abscall,
    896   r0 pop, \ r0=instr
    897   L4 abscall, ( op )
    898   setrd0) rTOP rdn) ,)
    899   wjmp, !, ( )
    900 
    901 \ Write arithmetic operation, that is:
    902 \ 1. Load operand's src in r0
    903 \ 2. Apply instr with operand's dst as Rd and Rn and r0 as Rm.
    904 pc to L1 ( operand -- ) \ r0=instr
    905   tst) rTOP rn) HALINV imm) ,)
    906   L2 abs>rel b) nz) ,)
    907   tst) rTOP rn) HALIMM imm) ,)
    908   L3 abs>rel b) nz) ,)
    909   r0 push,
    910   lblimmwr abscall,
    911   xdup, ( op op )
    912   setrd0) rTOP rdn) ,)
    913   wcall, @, ( op )
    914   r0 pop, \ r0=instr
    915   setimm0) rTOP rdn) ,)
    916   lblrdn abscall,
    917   L4 abs>rel b) ,) ( )
    918 
    919 xcode +, ( operand -- )
    920   mov) r0 rd) $00900000 imm) ,) ( add+s ) L1 abs>rel b) ,)
    921 
    922 xcode -, ( operand -- )
    923   mov) r0 rd) $00500000 imm) ,) ( sub+s ) L1 abs>rel b) ,)
    924 
    925 xcode &, ( operand -- )
    926   mov) r0 rd) $00100000 imm) ,) ( and+s ) L1 abs>rel b) ,)
    927 
    928 xcode |, ( operand -- )
    929   mov) r0 rd) $01900000 imm) ,) ( and+s ) L1 abs>rel b) ,)
    930 
    931 xcode ^, ( operand -- )
    932   mov) r0 rd) $00300000 imm) ,) ( and+s ) L1 abs>rel b) ,)
    933 
    934 xcode compare, ( operand -- )
    935   mov) r0 rd) $01500000 imm) ,) ( cmp ) L1 abs>rel b) ,)
    936 
    937 xcode *, ( operand -- )
    938   mov) r0 rd) $00000090 imm) ,) ( mul ) L1 abs>rel b) ,)
    939 
    940 \ Write << or >> in its immediate form
    941 pc to L1 ( operand -- ) \ r0=instr
    942   wcall, hbank@
    943   and) rTOP rdn) $1f imm) ,) \ 5-bit
    944   orr) r0 rdn) rTOP rm) 7 lsl) ,) \ or in b11:7
    945   xdrop,
    946   lbldwrite abs>rel b) ,)
    947 
    948 \ Write << or >> in its register form
    949 pc to L2 ( operand -- ) \ r0=instr
    950   r0 push,
    951   setrd0) rTOP rdn) ,)
    952   wcall, @,
    953   r0 pop,
    954   orr) r0 rdn) $10 imm) ,) \ register shift
    955   lbldwrite abs>rel b) ,)
    956 
    957 \ Write << or >> in either its register form or immediate form
    958 pc to L3 ( operand -- ) \ r0=instr mask
    959   orr) r0 rdn) $e0000000 imm) ,) \ always
    960   orr) r0 rdn) $01a00000 imm) ,) \ MOV
    961   and) r1 rd) rTOP rn) $f000 imm) ,) \ Rd
    962   orr) r0 rdn) r1 rm) ,)
    963   orr) r0 rdn) r1 rm) 12 lsr) ,) \ Rm
    964   \ We're set for everything except b11:6 and b4
    965   tst) rTOP rn) HALIMM imm) ,)
    966   L1 abs>rel b) nz) ,)
    967   L2 abs>rel b) ,)
    968 
    969 \ Write << or >> while handling the <>) case
    970 pc to L4 ( operand -- ) \ r0=instr mask
    971   tst) rTOP rn) HALINV imm) ,)
    972   L3 abs>rel b) z) ,) \ not <>)
    973   bic) rTOP rdn) HALINV imm) ,)
    974   r0 push, xdup, xdup, wcall, @!, r0 pop,
    975   L3 abscall,
    976   wjmp, @!,
    977 
    978 xcode <<, ( operand -- )
    979   mov) r0 rd) 0 imm) ,) L4 absb,
    980 
    981 xcode >>, ( operand -- )
    982   mov) r0 rd) $20 imm) ,) L4 absb,
    983 
    984 xcode +n, ( n operand -- )
    985   lblimmwr abscall,
    986   setrd0) rTOP rdn) ,)
    987   xdup, wcall, @,
    988   swp) rTOP rd) rPSP rn) rTOP rm) ,) ( operand n )
    989   mov) r1 rd) r0 imm) ,) lbladdnwr abscall,
    990   wjmp, !,
    991 
    992 pc pushret,
    993 xcode pushret,
    994   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
    995 
    996 pc popret,
    997 xcode popret,
    998   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
    999 
   1000 pc ret,
   1001 xcode exit,
   1002   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
   1003 
   1004 pc to L1 ( w -- ) \ r2=base instr
   1005   r1 binstart HERE movi2, ldr) r1 rdn) ,)
   1006   sub) r0 rd) rTOP rn) r1 rm) ,)
   1007   mov) r0 rd) r0 rm) 2 lsr) ,)
   1008   sub) r0 rdn) 2 imm) ,)
   1009   bic) r0 rn) $ff000000 imm) ,)
   1010   orr) r0 rdn) r2 rm) ,)
   1011   xdrop,
   1012   lbldwrite abs>rel b) ,)
   1013 
   1014 xcode branchR, ( w -- )
   1015   mov) r2 rd) $eb000000 imm) ,)
   1016   L1 abs>rel b) ,)
   1017 
   1018 xcode branch, ( a -- a )
   1019   mov) r2 rd) $ea000000 imm) ,)
   1020 pc to L2 ( a -- a ) \ r2=base instr
   1021   pushret, L1 abs>rel bl) ,) popret,
   1022   xdup, rTOP binstart HERE movi2, ldr) rTOP rdn) ,)
   1023   sub) rTOP rdn) 4 imm) ,)
   1024   ret,
   1025 
   1026 xcode branchC, ( a cond -- a )
   1027   mov) r2 rd) $0a000000 imm) ,)
   1028   orr) r2 rdn) rTOP rm) ,)
   1029   xdrop,
   1030   L2 abs>rel b) ,)
   1031 
   1032 pc mov) rPC rd) rA rm) ,)
   1033 xcode branchA,
   1034   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
   1035 
   1036 xcode branch! ( tgt a -- )
   1037   r1 ppop, \ r1=tgt
   1038   sub) r0 rd) r1 rn) rTOP rm) ,) \ r0=displacement
   1039   mov) r0 rd) r0 rm) 2 lsr) ,)
   1040   sub) r0 rdn) 2 imm) ,)
   1041   bic) r0 rn) $ff000000 imm) ,) \ r0=24-bit offset
   1042   ldr) r1 rd) rTOP rn) ,)
   1043   and) r1 rdn) $ff000000 imm) ,)
   1044   orr) r0 rdn) r1 rm) ,)
   1045   str) r0 rd) rTOP rn) ,)
   1046   xdrop, ret,
   1047 
   1048 \ a simple SWP pc, [sp] would be nice, right? but we can't...
   1049 \ In this sequence below, remember that PC is 8 bytes ahead.
   1050 pc mov) rLR rd) rPC rm) ,) add) rLR rdn) 8 imm) ,)
   1051    swp) rLR rd) rSP rn) rLR rm) ,) return) ,)
   1052 xcode yield ximm
   1053   ( pc ) r0 pc>reg,
   1054   mov) r1 rd) 16 imm) ,)
   1055   lblwriterange abs>rel b) ,)
   1056 
   1057 pc mov) rTOP rd) 0 imm) ,) add) z) ( 0 cond ) rTOP rdn) 1 imm) ,)
   1058 xcode C>W, ( cond -- )
   1059   dup ( pc ) r0 pc@>reg,
   1060   pushret, lbldwrite abs>rel bl) ,) popret,
   1061   ( pc ) 4 + r0 pc@>reg,
   1062   orr) r0 rdn) rTOP rm) ,)
   1063   xdrop,
   1064   lbldwrite abs>rel b) ,)
   1065 
   1066 pc xdup,
   1067 xcode dup,
   1068   ( pc ) r0 pc@>reg, lbldwrite abs>rel b) ,)
   1069 
   1070 xcode litn
   1071   wcall, dup,
   1072   mov) r0 rd) rTOP imm) ,) lbllitwr abs>rel b) ,)
   1073 
   1074 pc ," divide by zero" alignhere
   1075 pc to L1 \ rTOP=dividend rA=divisor
   1076   ( pc ) r0 pc>reg,
   1077   mov) r1 rd) 14 imm) ,)
   1078   cmp) rA rn) 0 imm) ,)
   1079   lblerrmsg abs>rel b) z) ,)
   1080   \ rTOP is active remainder
   1081   mov) r1 rd) 0 imm) ,) \ r1=quotient
   1082   mov) r2 rd) rA rm) ,) \ r2=tmp
   1083   \ double tmp until 2 * tmp > dividend
   1084   cmp) r2 rn) rTOP rm) 1 lsr) ,)
   1085 pc
   1086   mov) ls) r2 rd) r2 rm) 1 lsl) ,)
   1087   cmp) r2 rn) rTOP rm) 1 lsr) ,)
   1088   ( pc ) abs>rel b) ls) ,)
   1089 pc
   1090   cmp) rTOP rn) r2 rm) ,) \ can we subtract temp from dividend?
   1091   sub) cs) rTOP rdn) r2 rm) ,) \ if yes, do it
   1092   adc) r1 rdn) r1 rm) ,) \ double and add carry
   1093   mov) r2 rd) r2 rm) 1 lsr) ,)
   1094   cmp) r2 rn) rA rm) ,)
   1095   ( pc ) abs>rel b) hs) ,)
   1096   mov) rA rd) rTOP rm) ,) \ set remainder
   1097   mov) rTOP rd) r1 rm) ,) \ set quotient
   1098   ret,
   1099 
   1100 \ Write /mod with HALINV already processed
   1101 pc L1 le,
   1102 pc to L2 ( operand -- )
   1103   wcall, A>)
   1104   wcall, @,
   1105   wcall, pushret,
   1106   xdup,
   1107   ( pc ) rTOP pc@>reg,
   1108   wcall, branchR,
   1109   wjmp, popret,
   1110 
   1111 \ Write /mod with <>)
   1112 pc to L3 ( operand -- )
   1113   bic) rTOP rdn) HALINV imm) ,)
   1114   xdup, xdup, wcall, @!,
   1115   L2 abscall,
   1116   wjmp, @!,
   1117 
   1118 xcode /mod, ( operand -- )
   1119   tst) rTOP rn) HALINV imm) ,)
   1120   L3 abs>rel b) nz) ,)
   1121   L2 absb,
   1122 
   1123 \ Speed-critical words
   1124 xcode move ( src dst u -- )
   1125   r2 ppop, r0 ppop, \ r0=src r2=dst
   1126   mov) r1 rd) rTOP rm) ,) xdrop, \ r1=u
   1127   cmp) r2 rn) 0 imm) ,)
   1128   lblmoverange abs>rel b) nz) ,)
   1129   ret,
   1130 
   1131 xcode []= ( src dst u -- f )
   1132   r2 ppop, r0 ppop, \ r0=src r2=dst
   1133   cmp) rTOP rn) 0 imm) ,)
   1134   mov) z) rTOP rd) 1 imm) ,)
   1135   return) z) ,)
   1136   mov) r1 rd) rTOP rm) ,) \ r1=u
   1137   mov) rTOP rd) 0 imm) ,)
   1138 pc
   1139   ldr) r3 rd) r0 rn) 8b) 1 +i) post) ,)
   1140   ldr) r4 rd) r2 rn) 8b) 1 +i) post) ,)
   1141   cmp) r3 rn) r4 rm) ,)
   1142   return) nz) ,)
   1143   sub) r1 rdn) 1 imm) f) ,)
   1144   ( pc ) abs>rel b) ne) ,)
   1145   mov) rTOP rd) 1 imm) ,)
   1146   ret,
   1147 
   1148 xcode cidx ( c a u -- ?idx f )
   1149   r0 ppop, \ r0=a rTOP=u
   1150   ldr) r1 rd) rPSP rn) ,) \ r1=c
   1151   mov) r2 rd) 0 imm) ,) \ r2=i
   1152 pc
   1153   ldr) r3 rd) r0 rn) 8b) 1 +i) post) ,)
   1154   cmp) r3 rn) r1 rm) ,)
   1155   str) z) r2 rd) rPSP rn) ,)
   1156   mov) z) rTOP rd) 1 imm) ,)
   1157   return) z) ,)
   1158   add) r2 rdn) 1 imm) ,)
   1159   sub) rTOP rdn) 1 imm) f) ,)
   1160   ( pc ) abs>rel b) nz) ,)
   1161   xnip,
   1162   mov) rTOP rd) 0 imm) ,)
   1163   ret,
   1164 
   1165 \ Interpret loop
   1166 xcode ; ximm
   1167   wcall, popret,
   1168   wcall, exit,
   1169   wjmp, [
   1170 
   1171 pc ," stack underflow" alignhere
   1172 xcode stack?
   1173   cmp) rPSP rn) PSTOP imm) ,)
   1174   return) ls) ,)
   1175   ( pc ) r0 pc>reg,
   1176   mov) r1 rd) 15 imm) ,)
   1177   lblerrmsg abs>rel b) ,)
   1178 
   1179 pc to L1 ( str -- w ) \ find in sys dict
   1180   wcall, curword
   1181   wcall, sysdict
   1182   wcall, find
   1183   teq) rTOP rn) 0 imm) ,)
   1184   xwordlbl (wnf) abs>rel b) eq) ,)
   1185   ret,
   1186 
   1187 pc to L2 ( w -- ) \ findmod+execute
   1188   wcall, findmod
   1189   wcall, execute
   1190   wjmp, stack?
   1191 
   1192 xcode compword ( str -- )
   1193   wcall, parse
   1194   cmp) rTOP rn) 0 imm) ,)
   1195   xdrop,
   1196   xwordlbl litn abs>rel b) ne) ,) \ literal: jump to litn
   1197   L1 abscall,
   1198   ldr) r0 rd) rTOP rn) 8b) 9 -i) ,)
   1199   tst) r0 rn) $80 imm) ,)
   1200   L2 abs>rel b) ne) ,) \ immediate? execute
   1201   \ compile word
   1202   wcall, findmod
   1203   wjmp, branchR,
   1204 
   1205 xcode ]
   1206   r1 binstart COMPILING movi2,
   1207   mov) r0 rd) 1 imm) ,)
   1208   str) r0 rd) r1 rn) ,)
   1209 pc
   1210   wcall, word
   1211   wcall, compword
   1212   wcall, compiling
   1213   cmp) rTOP rn) 0 imm) ,)
   1214   xdrop,
   1215   ( pc ) abs>rel b) nz) ,)
   1216   ret,
   1217 
   1218 xcode runword ( str -- )
   1219   r0 binstart COMPILING movi2,
   1220   ldr) r0 rdn) ,)
   1221   cmp) r0 rn) 0 imm) ,)
   1222   xwordlbl compword abs>rel b) ne) ,)
   1223   wcall, parse
   1224   cmp) rTOP rn) 0 imm) ,)
   1225   xdrop,
   1226   return) ne) ,) \ literal: nothing to do
   1227   L1 abscall,
   1228   L2 abs>rel b) ,)
   1229 
   1230 xcode main pc w>e org SYSDICT + le!
   1231 lblmain forward!
   1232 pc
   1233   wcall, word
   1234   wcall, runword
   1235   abs>rel b) ,)
   1236 
   1237 pc org BOOTPTR + le!