boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

M0.hex2 (65364B)


      1 ## Copyright (C) 2017 Jeremiah Orians
      2 ## Copyright (C) 2021 Andrius Štikonas
      3 ## Copyright (C) 2021 Gabriel Wicki
      4 ## This file is part of stage0.
      5 ##
      6 ## stage0 is free software: you can redistribute it and/or modify
      7 ## it under the terms of the GNU General Public License as published by
      8 ## the Free Software Foundation, either version 3 of the License, or
      9 ## (at your option) any later version.
     10 ##
     11 ## stage0 is distributed in the hope that it will be useful,
     12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 ## GNU General Public License for more details.
     15 ##
     16 ## You should have received a copy of the GNU General Public License
     17 ## along with stage0.  If not, see <http://www.gnu.org/licenses/>.
     18 
     19 ; Where the ELF Header is going to hit
     20 ; Simply jump to _start
     21 ; Our main function
     22 
     23 ; Register use:
     24 ; s1: malloc pointer
     25 ; s2: input fd
     26 ; s3: output fd
     27 ; s4: struct HEAD
     28 ; s5: protected char
     29 ; s6: scratch
     30 
     31 ; Struct format: (size 32)
     32 ; NEXT => 0                           ; Next element in linked list
     33 ; TYPE => 8                           ; Token type
     34 ; TEXT => 16
     35 ; EXPRESSION => 24
     36 
     37 ; Types
     38 ; None => 0
     39 ; MACRO => 1
     40 ; STRING => 2
     41 
     42 :_start
     43     # rd_s4 addi
     44     .000A0000 13000000
     45 
     46     # rd_a2 rs1_sp !16 ld               ; Input file name
     47     .00060000 .00000100 .00000001 03300000
     48 
     49     ; Open input file and store FD in s2
     50     # rd_a7 !56 addi                    ; sys_openat
     51     .80080000 .00008003 13000000
     52     # rd_a0 !-100 addi                  ; AT_FDCWD
     53     .00050000 .0000C0F9 13000000
     54     # rd_a1 rs1_a2 mv                   ; file name
     55     .80050000 .00000600 13000000
     56     # rd_a2 addi                        ; read only
     57     .00060000 13000000
     58     # ecall                             ; syscall
     59     73000000
     60     # rs1_a0 @Fail bltz                 ; Error opening file
     61     .00000500 @Fail 63400000
     62     # rd_s2 rs1_a0 mv                   ; Save fd in for later
     63     .00090000 .00000500 13000000
     64 
     65     ; Set default FD for output file to stdout
     66     # rd_s3 !1 addi
     67     .80090000 .00001000 13000000
     68 
     69     ; If we only have 2 arguments, don't use the third (it's not set)
     70     # rd_t0 !2 addi
     71     .80020000 .00002000 13000000
     72     # rd_a0 rs1_sp ld                   ; Get number of the args
     73     .00050000 .00000100 03300000
     74     # rs1_a0 rs2_t0 @Fail blt           ; No input file provided
     75     .00000500 .00005000 @Fail 63400000
     76     # rs1_a0 rs2_t0 @after_open beq     ; No output file provided. Use stdout
     77     .00000500 .00005000 @after_open 63000000
     78 
     79     ; Open output file and store the FD in s3
     80     # rd_a7 !56 addi                    ; sys_openat
     81     .80080000 .00008003 13000000
     82     # rd_a0 !-100 addi                  ; AT_FDCWD
     83     .00050000 .0000C0F9 13000000
     84     # rd_a1 rs1_sp !24 ld               ; Output file (argument 3)
     85     .80050000 .00000100 .00008001 03300000
     86     # rd_a2 !577 addi                   ; octal 00001101
     87     .00060000 .00001024 13000000
     88     ; O_TRUNC   00001000
     89     ; O_CREAT   00000100
     90     ; O_WRONLY  00000001
     91     ; OCTAL!
     92     # rd_a3 !384 addi                   ; Set read and write permission on user
     93     .80060000 .00000018 13000000
     94     # ecall                             ; syscall
     95     73000000
     96     # rd_s3 rs1_a0 mv                   ; Save fd in for later
     97     .80090000 .00000500 13000000
     98 
     99 :after_open
    100     ; Prepare heap memory
    101     # rd_a7 !214 addi                   ; sys_brk
    102     .80080000 .0000600D 13000000
    103     # rd_a0 addi                        ; Get current brk
    104     .00050000 13000000
    105     # ecall                             ; syscall
    106     73000000
    107     # rd_s1 rs1_a0 mv                   ; Set our malloc pointer
    108     .80040000 .00000500 13000000
    109 
    110     # rd_a0 !512 addi                   ; Allocate scratch
    111     .00050000 .00000020 13000000
    112     # rd_ra $malloc jal                 ; Get S pointer
    113     .80000000 $malloc 6F000000
    114     # rd_s6 rs1_a0 mv                   ; Save scratch pointer
    115     .000B0000 .00000500 13000000
    116 
    117     # rd_ra $Tokenize_Line jal          ; Get all lines
    118     .80000000 $Tokenize_Line 6F000000
    119     # rd_a0 rs1_s4 mv                   ; Prepare for Reverse_List
    120     .00050000 .00000A00 13000000
    121     # rd_ra $Reverse_List jal           ; Correct order
    122     .80000000 $Reverse_List 6F000000
    123     # rd_s4 rs1_a0 mv                   ; Update HEAD
    124     .000A0000 .00000500 13000000
    125     # rd_ra $Identify_Macros jal        ; Find the DEFINEs
    126     .80000000 $Identify_Macros 6F000000
    127     # rd_ra $Line_Macro jal             ; Apply the DEFINEs
    128     .80000000 $Line_Macro 6F000000
    129     # rd_ra $Process_String jal         ; Handle strings
    130     .80000000 $Process_String 6F000000
    131     # rd_ra $Eval_Immediates jal        ; Handle numbers
    132     .80000000 $Eval_Immediates 6F000000
    133     # rd_ra $Preserve_Other jal         ; Collect the remaining
    134     .80000000 $Preserve_Other 6F000000
    135     # rd_ra $Print_Hex jal              ; Output our results
    136     .80000000 $Print_Hex 6F000000
    137 
    138     ; Terminate program with 0 return code
    139     # rd_a7 !93 addi                    ; sys_exit
    140     .80080000 .0000D005 13000000
    141     # rd_a0 mv                          ; Return code 0
    142     .00050000 13000000
    143     # ecall                             ; exit(0)
    144     73000000
    145 
    146 
    147 ; Tokenize_Line Function
    148 ; Using input file s2 and Head s4
    149 ; Creates a linked list of structs
    150 ; Uses a1 for in_set strings, a2 for Int C and a3 for Struct Token* p
    151 :Tokenize_Line
    152     # rd_sp rs1_sp !-8 addi             ; allocate stack
    153     .00010000 .00000100 .000080FF 13000000
    154     # rs1_sp rs2_ra sd                  ; protect ra
    155     .00000100 .00001000 23300000
    156 
    157 :restart
    158     # rd_ra $fgetc jal                  ; Read a char
    159     .80000000 $fgetc 6F000000
    160     # rd_t0 !-4 addi                    ; EOF
    161     .80020000 .0000C0FF 13000000
    162     # rs1_a0 rs2_t0 @done beq           ; File is collected
    163     .00000500 .00005000 @done 63000000
    164 
    165     # rd_a2 rs1_a0 mv                   ; Protect C
    166     .00060000 .00000500 13000000
    167 
    168     # rd_a1 ~comments auipc             ; Get pointer to "#;"
    169     .80050000 ~comments 17000000
    170     # rd_a1 rs1_a1 !comments addi       ; Get pointer to "#;"
    171     .80050000 .00800500 !comments 13000000
    172     # rd_ra $In_Set jal                 ; Check for comments
    173     .80000000 $In_Set 6F000000
    174     # rd_t0 !1 addi                     ; If comment
    175     .80020000 .00001000 13000000
    176     # rs1_a0 rs2_t0 @Purge_LineComment beq ; try again
    177     .00000500 .00005000 @Purge_LineComment 63000000
    178 
    179     # rd_a0 rs1_a2 mv                   ; Put C in place for check
    180     .00050000 .00000600 13000000
    181     # rd_a1 ~terminators auipc          ; Get pointer to "\n\t "
    182     .80050000 ~terminators 17000000
    183     # rd_a1 rs1_a1 !terminators addi    ; Get pointer to "\n\t "
    184     .80050000 .00800500 !terminators 13000000
    185     # rd_ra $In_Set jal                 ; Check for terminators
    186     .80000000 $In_Set 6F000000
    187     # rd_t0 !1 addi                     ; If terminator
    188     .80020000 .00001000 13000000
    189     # rs1_a0 rs2_t0 @restart beq        ; try again
    190     .00000500 .00005000 @restart 63000000
    191 
    192     # rd_a0 !32 addi                    ; malloc struct P
    193     .00050000 .00000002 13000000
    194     # rd_ra $malloc jal                 ; Get pointer to P
    195     .80000000 $malloc 6F000000
    196     # rd_a3 rs1_a0 mv                   ; Protect P
    197     .80060000 .00000500 13000000
    198     # rs1_a3 rs2_s4 sd                  ; P->NEXT = HEAD
    199     .00800600 .00004001 23300000
    200     # rd_s4 rs1_a3 mv                   ; HEAD = P
    201     .000A0000 .00800600 13000000
    202 
    203     # rd_a0 rs1_a2 mv                   ; Put C in place for check
    204     .00050000 .00000600 13000000
    205     # rd_a1 ~string_char auipc          ; Get pointer to "\"'"
    206     .80050000 ~string_char 17000000
    207     # rd_a1 rs1_a1 !string_char addi    ; Get pointer to "\"'"
    208     .80050000 .00800500 !string_char 13000000
    209     # rd_ra $In_Set jal                 ; Check for string char
    210     .80000000 $In_Set 6F000000
    211     # rd_t0 !1 addi                     ; If string char
    212     .80020000 .00001000 13000000
    213     # rs1_a0 rs2_t0 @Store_String beq   ; Get string
    214     .00000500 .00005000 @Store_String 63000000
    215 
    216     # rd_ra $Store_Atom jal             ; Get whole token
    217     .80000000 $Store_Atom 6F000000
    218     # $restart jal
    219     $restart 6F000000
    220 
    221 :done
    222     # rd_ra rs1_sp ld                   ; restore ra
    223     .80000000 .00000100 03300000
    224     # rd_sp rs1_sp !8 addi              ; deallocate stack
    225     .00010000 .00000100 .00008000 13000000
    226     # rs1_ra jalr                       ; return
    227     .00800000 67000000
    228 
    229 
    230 ; In_Set function
    231 ; Receives char C in a0 and Char* in a1
    232 ; Returns 1 if true, zero if false in a0
    233 :In_Set
    234     # rd_sp rs1_sp !-8 addi             ; allocate stack
    235     .00010000 .00000100 .000080FF 13000000
    236     # rs1_sp rs2_a1 sd                  ; protect a1
    237     .00000100 .0000B000 23300000
    238 
    239 :In_Set_loop
    240     # rd_t0 rs1_a1 lbu                  ; Read char
    241     .80020000 .00800500 03400000
    242     # rs1_a0 rs2_t0 @In_Set_True beq    ; Return true
    243     .00000500 .00005000 @In_Set_True 63000000
    244     # rs1_t0 @In_Set_False beqz         ; Return False if NULL
    245     .00800200 @In_Set_False 63000000
    246     # rd_a1 rs1_a1 !1 addi              ; s = s + 1
    247     .80050000 .00800500 .00001000 13000000
    248     # $In_Set_loop jal                  ; Continue looping
    249     $In_Set_loop 6F000000
    250 
    251 :In_Set_True
    252     # rd_a0 !1 addi                     ; Set True
    253     .00050000 .00001000 13000000
    254     # rd_a1 rs1_sp ld                   ; restore a1
    255     .80050000 .00000100 03300000
    256     # rd_sp rs1_sp !8 addi              ; deallocate stack
    257     .00010000 .00000100 .00008000 13000000
    258     # rs1_ra jalr                       ; return
    259     .00800000 67000000
    260 
    261 :In_Set_False
    262     # rd_a0 mv                          ; Set False
    263     .00050000 13000000
    264     # rd_a1 rs1_sp ld                   ; restore a1
    265     .80050000 .00000100 03300000
    266     # rd_sp rs1_sp !8 addi              ; deallocate stack
    267     .00010000 .00000100 .00008000 13000000
    268     # rs1_ra jalr                       ; return
    269     .00800000 67000000
    270 
    271 
    272 ; Purge_LineComment function
    273 ; Reads chars until LF and jumps to restart
    274 :Purge_LineComment
    275     # rd_ra $fgetc jal                  ; Get a char
    276     .80000000 $fgetc 6F000000
    277     # rd_t0 !10 addi                    ; While not LF
    278     .80020000 .0000A000 13000000
    279     # rs1_a0 rs2_t0 @Purge_LineComment bne ; Keep reading
    280     .00000500 .00005000 @Purge_LineComment 63100000
    281     # $restart jal
    282     $restart 6F000000
    283 
    284 
    285 ; Store_String Function
    286 ; Receives C in a2, HEAD in a3 and Input file in s2
    287 ; Uses a1 for terminator, a2 for C and a3 for string
    288 :Store_String
    289     # rd_sp rs1_sp !-24 addi            ; allocate stack
    290     .00010000 .00000100 .000080FE 13000000
    291     # rs1_sp rs2_a1 sd                  ; protect a1
    292     .00000100 .0000B000 23300000
    293     # rs1_sp rs2_a2 @8 sd               ; protect a2
    294     .00000100 .0000C000 .00040000 23300000
    295     # rs1_sp rs2_a3 @16 sd              ; protect a3
    296     .00000100 .0000D000 .00080000 23300000
    297 
    298     # rd_a0 !2 addi                     ; Using TYPE STRING
    299     .00050000 .00002000 13000000
    300     # rs1_a3 rs2_a0 @8 sd               ; HEAD->TYPE = STRING
    301     .00800600 .0000A000 .00040000 23300000
    302     # rd_a1 rs1_a2 mv                   ; Protect terminator
    303     .80050000 .00000600 13000000
    304     # rd_a3 rs1_s6 mv                   ; Protect string pointer
    305     .80060000 .00000B00 13000000
    306 :Store_String_Loop
    307     # rs1_a3 rs2_a2 sb                  ; write byte
    308     .00800600 .0000C000 23000000
    309     # rd_ra $fgetc jal                  ; read next char
    310     .80000000 $fgetc 6F000000
    311     # rd_a2 rs1_a0 mv                   ; Update C
    312     .00060000 .00000500 13000000
    313     # rd_a3 rs1_a3 !1 addi              ; STRING = STRING + 1
    314     .80060000 .00800600 .00001000 13000000
    315     # rs1_a1 rs2_a2 @Store_String_Loop bne ; Keep looping unless we hit terminator
    316     .00800500 .0000C000 @Store_String_Loop 63100000
    317 
    318     # rd_a0 rs1_s6 mv                   ; Prepare the string in scratch
    319     .00050000 .00000B00 13000000
    320     # rd_ra $string_length jal          ; Calculate length
    321     .80000000 $string_length 6F000000
    322     # rd_a0 rs1_a0 !1 addi              ; Add 1 for 0 terminator
    323     .00050000 .00000500 .00001000 13000000
    324     # rd_ra $malloc jal                 ; Allocate memory
    325     .80000000 $malloc 6F000000
    326     # rd_a3 rs1_sp !16 ld               ; restore a3 (HEAD)
    327     .80060000 .00000100 .00000001 03300000
    328     # rs1_a3 rs2_a0 @16 sd              ; HEAD->TEXT = STRING
    329     .00800600 .0000A000 .00080000 23300000
    330     # rd_ra $copy_string jal            ; Copy the string
    331     .80000000 $copy_string 6F000000
    332 
    333     # rd_a1 rs1_sp ld                   ; restore a1
    334     .80050000 .00000100 03300000
    335     # rd_a2 rs1_sp !8 ld                ; restore a2
    336     .00060000 .00000100 .00008000 03300000
    337     # rd_sp rs1_sp !24 addi             ; deallocate stack
    338     .00010000 .00000100 .00008001 13000000
    339     # $restart jal
    340     $restart 6F000000
    341 
    342 ; copy_string function
    343 ; Receives target in a0, and scratch s6 for source
    344 ; Uses a0, for target string T, a1 for C, a2 for source string S
    345 ; Returns nothing
    346 :copy_string
    347     # rd_sp rs1_sp !-24 addi            ; allocate stack
    348     .00010000 .00000100 .000080FE 13000000
    349     # rs1_sp rs2_ra sd                  ; protect ra
    350     .00000100 .00001000 23300000
    351     # rs1_sp rs2_a1 @8 sd               ; protect a1
    352     .00000100 .0000B000 .00040000 23300000
    353     # rs1_sp rs2_a2 @16 sd              ; protect a2
    354     .00000100 .0000C000 .00080000 23300000
    355 
    356     # rd_a2 rs1_s6 mv                   ; Get S
    357     .00060000 .00000B00 13000000
    358 
    359 :copy_string_loop
    360     # rd_a1 rs1_a2 lbu                  ; S[0]
    361     .80050000 .00000600 03400000
    362     # rs1_a1 @copy_string_done beqz     ; Check if we are done
    363     .00800500 @copy_string_done 63000000
    364 
    365     # rs1_a0 rs2_a1 sb                  ; Copy char
    366     .00000500 .0000B000 23000000
    367     # rd_a2 rs1_a2 !1 addi              ; S = S + 1
    368     .00060000 .00000600 .00001000 13000000
    369     # rd_a0 rs1_a0 !1 addi              ; T = T + 1
    370     .00050000 .00000500 .00001000 13000000
    371     # $copy_string_loop jal             ; Keep going
    372     $copy_string_loop 6F000000
    373 
    374 :copy_string_done
    375     # rd_ra $ClearScratch jal           ; Clear scratch
    376     .80000000 $ClearScratch 6F000000
    377 
    378     # rd_ra rs1_sp ld                   ; restore ra
    379     .80000000 .00000100 03300000
    380     # rd_a1 rs1_sp !8 ld                ; restore a1
    381     .80050000 .00000100 .00008000 03300000
    382     # rd_a2 rs1_sp !16 ld               ; restore a2
    383     .00060000 .00000100 .00000001 03300000
    384     # rd_sp rs1_sp !24 addi             ; deallocate stack
    385     .00010000 .00000100 .00008001 13000000
    386     # ret
    387     67800000
    388 
    389 
    390 ; Zero scratch area
    391 :ClearScratch
    392     # rd_sp rs1_sp !-24 addi            ; allocate stack
    393     .00010000 .00000100 .000080FE 13000000
    394     # rs1_sp rs2_ra sd                  ; protect ra
    395     .00000100 .00001000 23300000
    396     # rs1_sp rs2_a0 @8 sd               ; protect a0
    397     .00000100 .0000A000 .00040000 23300000
    398     # rs1_sp rs2_a1 @16 sd              ; protect a1
    399     .00000100 .0000B000 .00080000 23300000
    400 
    401     # rd_a0 rs1_s6 mv                   ; Prepare scratch
    402     .00050000 .00000B00 13000000
    403 
    404 :ClearScratch_loop
    405     # rd_a1 rs1_a0 lb                   ; Read current byte: s[i]
    406     .80050000 .00000500 03000000
    407     # rs1_a0 sb                         ; Write zero: s[i] = 0
    408     .00000500 23000000
    409     # rd_a0 rs1_a0 !1 addi              ; Increment: i = i + 1
    410     .00050000 .00000500 .00001000 13000000
    411     # rs1_a1 @ClearScratch_loop bnez    ; Keep looping
    412     .00800500 @ClearScratch_loop 63100000
    413 
    414     # rd_ra rs1_sp ld                   ; restore ra
    415     .80000000 .00000100 03300000
    416     # rd_a0 rs1_sp !8 ld                ; restore a0
    417     .00050000 .00000100 .00008000 03300000
    418     # rd_a1 rs1_sp !16 ld               ; restore a1
    419     .80050000 .00000100 .00000001 03300000
    420     # rd_sp rs1_sp !24 addi             ; deallocate stack
    421     .00010000 .00000100 .00008001 13000000
    422     # ret
    423     67800000
    424 
    425 
    426 ; Store_Atom Function
    427 ; Receives C in a2, HEAD in a3 and Input file in s2
    428 ; Uses a1 for in_set strings, a2 for C and a3 for string
    429 :Store_Atom
    430     # rd_sp rs1_sp !-32 addi            ; allocate stack
    431     .00010000 .00000100 .000000FE 13000000
    432     # rs1_sp rs2_ra sd                  ; protect ra
    433     .00000100 .00001000 23300000
    434     # rs1_sp rs2_a1 @8 sd               ; protect a1
    435     .00000100 .0000B000 .00040000 23300000
    436     # rs1_sp rs2_a2 @16 sd              ; protect a2
    437     .00000100 .0000C000 .00080000 23300000
    438     # rs1_sp rs2_a3 @24 sd              ; protect a3
    439     .00000100 .0000D000 .000C0000 23300000
    440 
    441     # rd_a1 ~terminators auipc          ; Get pointer to "\n\t "
    442     .80050000 ~terminators 17000000
    443     # rd_a1 rs1_a1 !terminators addi    ; Get pointer to "\n\t "
    444     .80050000 .00800500 !terminators 13000000
    445     # rd_a3 rs1_s6 mv                   ; Protect string pointer
    446     .80060000 .00000B00 13000000
    447 
    448 :Store_Atom_loop
    449     # rs1_a3 rs2_a2 sb                  ; write byte
    450     .00800600 .0000C000 23000000
    451     # rd_ra $fgetc jal                  ; read next char
    452     .80000000 $fgetc 6F000000
    453     # rd_a2 rs1_a0 mv                   ; Update C
    454     .00060000 .00000500 13000000
    455     # rd_a3 rs1_a3 !1 addi              ; STRING = STRING + 1
    456     .80060000 .00800600 .00001000 13000000
    457     # rd_ra $In_Set jal                 ; Check for terminators
    458     .80000000 $In_Set 6F000000
    459     # rs1_a0 @Store_Atom_loop beqz      ; Loop if not "\n\t "
    460     .00000500 @Store_Atom_loop 63000000
    461 
    462     # rd_a0 rs1_s6 mv                   ; Prepare the string in scratch
    463     .00050000 .00000B00 13000000
    464     # rd_ra $string_length jal          ; Calculate length
    465     .80000000 $string_length 6F000000
    466     # rd_a0 rs1_a0 !1 addi              ; Add 1 for 0 terminator
    467     .00050000 .00000500 .00001000 13000000
    468     # rd_ra $malloc jal                 ; Allocate memory
    469     .80000000 $malloc 6F000000
    470     # rd_a3 rs1_sp !24 ld               ; restore a3
    471     .80060000 .00000100 .00008001 03300000
    472     # rs1_a3 rs2_a0 @16 sd              ; HEAD->TEXT = STRING
    473     .00800600 .0000A000 .00080000 23300000
    474     # rd_ra $copy_string jal            ; Copy the string
    475     .80000000 $copy_string 6F000000
    476 
    477     # rd_ra rs1_sp ld                   ; restore ra
    478     .80000000 .00000100 03300000
    479     # rd_a1 rs1_sp !8 ld                ; restore a1
    480     .80050000 .00000100 .00008000 03300000
    481     # rd_a2 rs1_sp !16 ld               ; restore a2
    482     .00060000 .00000100 .00000001 03300000
    483     # rd_sp rs1_sp !32 addi             ; deallocate stack
    484     .00010000 .00000100 .00000002 13000000
    485     # rs1_ra jalr                       ; return
    486     .00800000 67000000
    487 
    488 
    489 ; Reverse_List function
    490 ; Receives list in a0
    491 ; Returns the list reversed in a0
    492 :Reverse_List
    493     # rd_sp rs1_sp !-16 addi            ; allocate stack
    494     .00010000 .00000100 .000000FF 13000000
    495     # rs1_sp rs2_a1 sd                  ; protect a1
    496     .00000100 .0000B000 23300000
    497     # rs1_sp rs2_a2 @8 sd               ; protect a2
    498     .00000100 .0000C000 .00040000 23300000
    499     # rd_a1 rs1_a0 mv                   ; Set HEAD
    500     .80050000 .00000500 13000000
    501     # rd_a0 mv                          ; ROOT = NULL
    502     .00050000 13000000
    503 :Reverse_List_Loop
    504     # rs1_a1 @Reverse_List_Done beqz    ; Stop if HEAD == NULL
    505     .00800500 @Reverse_List_Done 63000000
    506 
    507     # rd_a2 rs1_a1 ld                   ; NEXT = HEAD->NEXT
    508     .00060000 .00800500 03300000
    509     # rs1_a1 rs2_a0 sd                  ; HEAD->NEXT = ROOT
    510     .00800500 .0000A000 23300000
    511     # rd_a0 rs1_a1 mv                   ; ROOT = HEAD
    512     .00050000 .00800500 13000000
    513     # rd_a1 rs1_a2 mv                   ; HEAD = NEXT
    514     .80050000 .00000600 13000000
    515     # $Reverse_List_Loop jal            ; Continue looping
    516     $Reverse_List_Loop 6F000000
    517 
    518 :Reverse_List_Done
    519     # rd_a1 rs1_sp ld                   ; restore a1
    520     .80050000 .00000100 03300000
    521     # rd_a2 rs1_sp !8 ld                ; restore a2
    522     .00060000 .00000100 .00008000 03300000
    523     # rd_sp rs1_sp !16 addi             ; deallocate stack
    524     .00010000 .00000100 .00000001 13000000
    525     # rs1_ra jalr                       ; return
    526     .00800000 67000000
    527 
    528 
    529 ; Identify_Macros function
    530 ; Receives List in a0
    531 ; Updates the list in place; does not modify registers
    532 ; Uses a1 for DEFINE, a2 for I
    533 :Identify_Macros
    534     # rd_sp rs1_sp !-32 addi            ; allocate stack
    535     .00010000 .00000100 .000000FE 13000000
    536     # rs1_sp rs2_ra sd                  ; protect ra
    537     .00000100 .00001000 23300000
    538     # rs1_sp rs2_a0 @8 sd               ; protect a0
    539     .00000100 .0000A000 .00040000 23300000
    540     # rs1_sp rs2_a1 @16 sd              ; protect a1
    541     .00000100 .0000B000 .00080000 23300000
    542     # rs1_sp rs2_a2 @24 sd              ; protect a2
    543     .00000100 .0000C000 .000C0000 23300000
    544 
    545     # rd_a1 ~DEFINE_str auipc           ; Setup DEFINE string
    546     .80050000 ~DEFINE_str 17000000
    547     # rd_a1 rs1_a1 !DEFINE_str addi     ; Setup DEFINE string
    548     .80050000 .00800500 !DEFINE_str 13000000
    549     # rd_a2 rs1_a0 mv                   ; I = HEAD
    550     .00060000 .00000500 13000000
    551 
    552 :Identify_Macros_Loop
    553     # rd_a0 rs1_a2 !16 ld               ; I->TEXT
    554     .00050000 .00000600 .00000001 03300000
    555     # rd_ra $match jal                  ; IF "DEFINE" == I->TEXT
    556     .80000000 $match 6F000000
    557     # rs1_a0 @Identify_Macros_Next bnez ; Check if we got macro
    558     .00000500 @Identify_Macros_Next 63100000
    559 
    560     ; Deal with MACRO
    561     # rd_a0 !1 addi                     ; a0 = MACRO
    562     .00050000 .00001000 13000000
    563     # rs1_a2 rs2_a0 @8 sd               ; I->TYPE = MACRO
    564     .00000600 .0000A000 .00040000 23300000
    565 
    566     # rd_a0 rs1_a2 ld                   ; I->NEXT
    567     .00050000 .00000600 03300000
    568     # rd_a0 rs1_a0 !16 ld               ; I->NEXT->TEXT
    569     .00050000 .00000500 .00000001 03300000
    570     # rs1_a2 rs2_a0 @16 sd              ; I->TEXT = I->NEXT->TEXT
    571     .00000600 .0000A000 .00080000 23300000
    572 
    573     # rd_a0 rs1_a2 ld                   ; I->NEXT
    574     .00050000 .00000600 03300000
    575     # rd_a0 rs1_a0 ld                   ; I->NEXT->NEXT
    576     .00050000 .00000500 03300000
    577     # rd_a0 rs1_a0 !16 ld               ; I->NEXT->NEXT->TEXT
    578     .00050000 .00000500 .00000001 03300000
    579     # rs1_a2 rs2_a0 @24 sd              ; I->EXPRESSION = I->NEXT->NEXT->TEXT
    580     .00000600 .0000A000 .000C0000 23300000
    581 
    582     # rd_a0 rs1_a2 ld                   ; I->NEXT
    583     .00050000 .00000600 03300000
    584     # rd_a0 rs1_a0 ld                   ; I->NEXT->NEXT
    585     .00050000 .00000500 03300000
    586     # rd_a0 rs1_a0 ld                   ; I->NEXT->NEXT->NEXT
    587     .00050000 .00000500 03300000
    588     # rs1_a2 rs2_a0 sd                  ; I->NEXT = I->NEXT->NEXT->NEXT
    589     .00000600 .0000A000 23300000
    590 
    591 :Identify_Macros_Next
    592     # rd_a2 rs1_a2 ld                   ; I = I->NEXT
    593     .00060000 .00000600 03300000
    594     # rs1_a2 @Identify_Macros_Loop bnez ; Check if we are done
    595     .00000600 @Identify_Macros_Loop 63100000
    596 
    597     # rd_ra rs1_sp ld                   ; restore ra
    598     .80000000 .00000100 03300000
    599     # rd_a0 rs1_sp !8 ld                ; restore a0
    600     .00050000 .00000100 .00008000 03300000
    601     # rd_a1 rs1_sp !16 ld               ; restore a1
    602     .80050000 .00000100 .00000001 03300000
    603     # rd_a2 rs1_sp !24 ld               ; restore a2
    604     .00060000 .00000100 .00008001 03300000
    605     # rd_sp rs1_sp !32 addi             ; deallocate stack
    606     .00010000 .00000100 .00000002 13000000
    607     # rs1_ra jalr                       ; return
    608     .00800000 67000000
    609 
    610 
    611 ; match function
    612 ; Receives CHAR* in a0 and CHAR* in a1
    613 ; Returns 0 (TRUE) or 1 (FALSE) in a0
    614 :match
    615     # rd_sp rs1_sp !-24 addi            ; allocate stack
    616     .00010000 .00000100 .000080FE 13000000
    617     # rs1_sp rs2_a1 sd                  ; protect a1
    618     .00000100 .0000B000 23300000
    619     # rs1_sp rs2_a2 @8 sd               ; protect a2
    620     .00000100 .0000C000 .00040000 23300000
    621     # rs1_sp rs2_a3 @16 sd              ; protect a3
    622     .00000100 .0000D000 .00080000 23300000
    623 
    624     # rd_a2 rs1_a0 mv                   ; S1 in place
    625     .00060000 .00000500 13000000
    626     # rd_a3 rs1_a1 mv                   ; S2 in place
    627     .80060000 .00800500 13000000
    628 
    629 :match_Loop
    630     # rd_a0 rs1_a2 lbu                  ; S1[i]
    631     .00050000 .00000600 03400000
    632     # rd_a1 rs1_a3 lbu                  ; S2[i]
    633     .80050000 .00800600 03400000
    634     # rs1_a0 rs2_a1 @match_False bne    ; Check if they match
    635     .00000500 .0000B000 @match_False 63100000
    636 
    637     # rd_a2 rs1_a2 !1 addi              ; S1 = S1 + 1
    638     .00060000 .00000600 .00001000 13000000
    639     # rd_a3 rs1_a3 !1 addi              ; S2 = S2 + 1
    640     .80060000 .00800600 .00001000 13000000
    641     # rs1_a0 @match_Done beqz           ; Match if we reached end of string
    642     .00000500 @match_Done 63000000
    643     # $match_Loop jal                   ; Otherwise keep looping
    644     $match_Loop 6F000000
    645 
    646 :match_False
    647     # rd_a0 !1 addi                     ; Return false
    648     .00050000 .00001000 13000000
    649 :match_Done
    650     # rd_a1 rs1_sp ld                   ; restore a1
    651     .80050000 .00000100 03300000
    652     # rd_a2 rs1_sp !8 ld                ; restore a2
    653     .00060000 .00000100 .00008000 03300000
    654     # rd_a3 rs1_sp !16 ld               ; restore a3
    655     .80060000 .00000100 .00000001 03300000
    656     # rd_sp rs1_sp !24 addi             ; deallocate stack
    657     .00010000 .00000100 .00008001 13000000
    658     # rs1_ra jalr                       ; return
    659     .00800000 67000000
    660 
    661 
    662 ; Line_Macro function
    663 ; Receives List in a0
    664 ; Updates the list in place; does not modify registers
    665 ; Uses a0 for I, a1 for I->TEXT, a2 for I->EXPRESSION
    666 :Line_Macro
    667     # rd_sp rs1_sp !-32 addi            ; allocate stack
    668     .00010000 .00000100 .000000FE 13000000
    669     # rs1_sp rs2_ra sd                  ; protect ra
    670     .00000100 .00001000 23300000
    671     # rs1_sp rs2_a0 @8 sd               ; protect a0
    672     .00000100 .0000A000 .00040000 23300000
    673     # rs1_sp rs2_a1 @16 sd              ; protect a1
    674     .00000100 .0000B000 .00080000 23300000
    675     # rs1_sp rs2_a2 @24 sd              ; protect a2
    676     .00000100 .0000C000 .000C0000 23300000
    677 
    678 :Line_Macro_Loop
    679     # rd_a1 rs1_a0 !8 ld                ; I->TYPE
    680     .80050000 .00000500 .00008000 03300000
    681     # rd_t0 !1 addi                     ; t0 = MACRO
    682     .80020000 .00001000 13000000
    683     # rs1_a1 rs2_t0 @Line_Macro_Next bne ; Move on unless I->TYPE == MACRO
    684     .00800500 .00005000 @Line_Macro_Next 63100000
    685 
    686     ; Apply macro
    687     # rd_a1 rs1_a0 !16 ld               ; I->TEXT
    688     .80050000 .00000500 .00000001 03300000
    689     # rd_a2 rs1_a0 !24 ld               ; I->EXPRESSION
    690     .00060000 .00000500 .00008001 03300000
    691     # rd_a0 rs1_a0 ld                   ; I->NEXT
    692     .00050000 .00000500 03300000
    693     # rd_ra $Set_Expression jal         ; Apply it
    694     .80000000 $Set_Expression 6F000000
    695     # $Line_Macro_Loop jal              ; Move on to next
    696     $Line_Macro_Loop 6F000000
    697 
    698 :Line_Macro_Next
    699     # rd_a0 rs1_a0 ld                   ; I->NEXT
    700     .00050000 .00000500 03300000
    701     # rs1_a0 @Line_Macro_Loop bnez      ; Check if we are done
    702     .00000500 @Line_Macro_Loop 63100000
    703 
    704     # rd_ra rs1_sp ld                   ; restore ra
    705     .80000000 .00000100 03300000
    706     # rd_a0 rs1_sp !8 ld                ; restore a0
    707     .00050000 .00000100 .00008000 03300000
    708     # rd_a1 rs1_sp !16 ld               ; restore a1
    709     .80050000 .00000100 .00000001 03300000
    710     # rd_a2 rs1_sp !24 ld               ; restore a2
    711     .00060000 .00000100 .00008001 03300000
    712     # rd_sp rs1_sp !32 addi             ; deallocate stack
    713     .00010000 .00000100 .00000002 13000000
    714     # rs1_ra jalr                       ; return
    715     .00800000 67000000
    716 
    717 
    718 ; Set_Expression function
    719 ; Receives List in a0, CHAR* in a1 and CHAR* in a2
    720 ; Updates the list in place; does not modify registers
    721 ; Uses a1 for C, a2 for EXP and a3 for I
    722 :Set_Expression
    723     # rd_sp rs1_sp !-40 addi            ; allocate stack
    724     .00010000 .00000100 .000080FD 13000000
    725     # rs1_sp rs2_ra sd                  ; protect ra
    726     .00000100 .00001000 23300000
    727     # rs1_sp rs2_a0 @8 sd               ; protect a0
    728     .00000100 .0000A000 .00040000 23300000
    729     # rs1_sp rs2_a1 @16 sd              ; protect a1
    730     .00000100 .0000B000 .00080000 23300000
    731     # rs1_sp rs2_a2 @24 sd              ; protect a2
    732     .00000100 .0000C000 .000C0000 23300000
    733     # rs1_sp rs2_a3 @32 sd              ; protect a3
    734     .00000100 .0000D000 .00000002 23300000
    735 
    736     # rd_a3 rs1_a0 mv                   ; Set I
    737     .80060000 .00000500 13000000
    738 :Set_Expression_Loop
    739     # rd_a0 rs1_a3 !8 ld                ; I->TYPE
    740     .00050000 .00800600 .00008000 03300000
    741     # rd_t0 !1 addi                     ; t0 = MACRO
    742     .80020000 .00001000 13000000
    743     # rs1_a0 rs2_t0 @Set_Expression_Next beq ; If MACRO == I->Type then ignore and move on
    744     .00000500 .00005000 @Set_Expression_Next 63000000
    745 
    746     # rd_a0 rs1_a3 !16 ld               ; I->TEXT
    747     .00050000 .00800600 .00000001 03300000
    748     # rd_ra $match jal                  ; Check for match
    749     .80000000 $match 6F000000
    750     # rs1_a0 @Set_Expression_Next bnez  ; Check next if does not match
    751     .00000500 @Set_Expression_Next 63100000
    752 
    753     ; Non-macro match
    754     # rs1_a3 rs2_a2 @24 sd              ; I->EXPRESSION = EXP
    755     .00800600 .0000C000 .000C0000 23300000
    756 
    757 :Set_Expression_Next
    758     # rd_a3 rs1_a3 ld                   ; I = I->NEXT
    759     .80060000 .00800600 03300000
    760     # rs1_a3 @Set_Expression_Loop bnez  ; Check if we are done
    761     .00800600 @Set_Expression_Loop 63100000
    762     # rd_ra rs1_sp ld                   ; restore ra
    763     .80000000 .00000100 03300000
    764     # rd_a0 rs1_sp !8 ld                ; restore a0
    765     .00050000 .00000100 .00008000 03300000
    766     # rd_a1 rs1_sp !16 ld               ; restore a1
    767     .80050000 .00000100 .00000001 03300000
    768     # rd_a2 rs1_sp !24 ld               ; restore a2
    769     .00060000 .00000100 .00008001 03300000
    770     # rd_a3 rs1_sp !32 ld               ; restore a3
    771     .80060000 .00000100 .00000002 03300000
    772     # rd_sp rs1_sp !40 addi             ; deallocate stack
    773     .00010000 .00000100 .00008002 13000000
    774     # rs1_ra jalr                       ; return
    775     .00800000 67000000
    776 
    777 
    778 ; Process_String function
    779 ; Receives List in a0
    780 ; Update the list in place; does not modify registers
    781 ; Uses a1 for I->TEXT, a2 for I and RDX for S
    782 :Process_String
    783     # rd_sp rs1_sp !-40 addi            ; allocate stack
    784     .00010000 .00000100 .000080FD 13000000
    785     # rs1_sp rs2_ra sd                  ; protect ra
    786     .00000100 .00001000 23300000
    787     # rs1_sp rs2_a0 @8 sd               ; protect a0
    788     .00000100 .0000A000 .00040000 23300000
    789     # rs1_sp rs2_a1 @16 sd              ; protect a1
    790     .00000100 .0000B000 .00080000 23300000
    791     # rs1_sp rs2_a2 @24 sd              ; protect a2
    792     .00000100 .0000C000 .000C0000 23300000
    793     # rs1_sp rs2_a3 @32 sd              ; protect a3
    794     .00000100 .0000D000 .00000002 23300000
    795 
    796     # rd_a2 rs1_a0 mv                   ; I = HEAD
    797     .00060000 .00000500 13000000
    798 
    799 :Process_String_loop
    800     # rd_a0 rs1_a2 !8 ld                ; I->TYPE
    801     .00050000 .00000600 .00008000 03300000
    802     # rd_t0 !2 addi                     ; t0 = STRING
    803     .80020000 .00002000 13000000
    804     # rs1_a0 rs2_t0 @Process_String_Next bne ; Skip to next
    805     .00000500 .00005000 @Process_String_Next 63100000
    806 
    807     # rd_a1 rs1_a2 !16 ld               ; I->TEXT
    808     .80050000 .00000600 .00000001 03300000
    809     # rd_a0 rs1_a1 lbu                  ; I->TEXT[0]
    810     .00050000 .00800500 03400000
    811     # rd_t0 !39 addi                    ; t0 = \'
    812     .80020000 .00007002 13000000
    813     # rs1_a0 rs2_t0 @Process_String_Raw bne ; Deal with '"'
    814     .00000500 .00005000 @Process_String_Raw 63100000
    815 
    816     ; Deal with \'
    817     # rd_a1 rs1_a1 !1 addi              ; I->TEXT + 1
    818     .80050000 .00800500 .00001000 13000000
    819     # rs1_a2 rs2_a1 @24 sd              ; I->EXPRESSION = I->TEXT + 1
    820     .00000600 .0000B000 .000C0000 23300000
    821     # $Process_String_Next jal          ; Move on to next
    822     $Process_String_Next 6F000000
    823 
    824 :Process_String_Raw
    825     # rd_a0 rs1_a1 mv                   ; I->TEXT
    826     .00050000 .00800500 13000000
    827     # rd_ra $string_length jal          ; Get length of I->TEXT
    828     .80000000 $string_length 6F000000
    829     # rd_a0 rs1_a0 rs2_x2 srli          ; LENGTH = LENGTH >> 2
    830     .00050000 .00000500 .00002000 13500000
    831     # rd_a0 rs1_a0 !1 addi              ; LENGTH = LENGTH + 1
    832     .00050000 .00000500 .00001000 13000000
    833     # rd_a0 rs1_a0 rs2_x3 slli          ; LENGTH = LENGTH << 3
    834     .00050000 .00000500 .00003000 13100000
    835     # rd_ra $malloc jal                 ; Get string
    836     .80000000 $malloc 6F000000
    837     # rd_a3 rs1_a1 mv                   ; S = I->TEXT
    838     .80060000 .00800500 13000000
    839     # rd_a3 rs1_a3 !1 addi              ; S = S + 1
    840     .80060000 .00800600 .00001000 13000000
    841     # rs1_a2 rs2_a0 @24 sd              ; I->EXPRESSION = hexify
    842     .00000600 .0000A000 .000C0000 23300000
    843     # rd_a1 rs1_a0 mv                   ; Put hexify buffer in a1
    844     .80050000 .00000500 13000000
    845 
    846 :Process_String_Raw_Loop
    847     # rd_a0 rs1_a3 lbu                  ; Read 1 character
    848     .00050000 .00800600 03400000
    849     # rd_a3 rs1_a3 !1 addi              ; S = S + 1
    850     .80060000 .00800600 .00001000 13000000
    851     # rd_s5 rs1_a0 mv                   ; Protect character
    852     .800A0000 .00000500 13000000
    853     # rd_ra $hex8 jal                   ; write them all
    854     .80000000 $hex8 6F000000
    855     # rd_a0 rs1_s5 mv                   ; Restore character
    856     .00050000 .00800A00 13000000
    857     # rs1_a0 @Process_String_Raw_Loop bnez ; Keep looping
    858     .00000500 @Process_String_Raw_Loop 63100000
    859 
    860 :Process_String_Next
    861     # rd_a2 rs1_a2 ld                   ; I = I->NEXT
    862     .00060000 .00000600 03300000
    863     # rs1_a2 @Process_String_loop bnez  ; Check if we are done
    864     .00000600 @Process_String_loop 63100000
    865 
    866     # rd_ra rs1_sp ld                   ; restore ra
    867     .80000000 .00000100 03300000
    868     # rd_a0 rs1_sp !8 ld                ; restore a0
    869     .00050000 .00000100 .00008000 03300000
    870     # rd_a1 rs1_sp !16 ld               ; restore a1
    871     .80050000 .00000100 .00000001 03300000
    872     # rd_a2 rs1_sp !24 ld               ; restore a2
    873     .00060000 .00000100 .00008001 03300000
    874     # rd_a3 rs1_sp !32 ld               ; restore a3
    875     .80060000 .00000100 .00000002 03300000
    876     # rd_sp rs1_sp !40 addi             ; deallocate stack
    877     .00010000 .00000100 .00008002 13000000
    878     # rs1_ra jalr                       ; return
    879     .00800000 67000000
    880 
    881 
    882 ; string_length function
    883 ; Receives CHAR* in a0
    884 ; Returns INT in a0
    885 ; Uses a0 for CH, a1 for S and a2 for INDEX
    886 :string_length
    887     # rd_sp rs1_sp !-16 addi            ; allocate stack
    888     .00010000 .00000100 .000000FF 13000000
    889     # rs1_sp rs2_a1 sd                  ; protect a1
    890     .00000100 .0000B000 23300000
    891     # rs1_sp rs2_a2 @8 sd               ; protect a2
    892     .00000100 .0000C000 .00040000 23300000
    893 
    894     # rd_a1 rs1_a0 mv                   ; Set S
    895     .80050000 .00000500 13000000
    896     # rd_a2 mv                          ; INDEX = 0
    897     .00060000 13000000
    898 
    899 :string_length_loop
    900     # rd_t0 rs1_a1 rs2_a2 add           ; S + INDEX
    901     .80020000 .00800500 .0000C000 33000000
    902     # rd_a0 rs1_t0 lbu                  ; S[INDEX]
    903     .00050000 .00800200 03400000
    904     # rs1_a0 @string_length_done beqz   ; Check if we are done
    905     .00000500 @string_length_done 63000000
    906 
    907     # rd_a2 rs1_a2 !1 addi              ; INDEX = INDEX + 1
    908     .00060000 .00000600 .00001000 13000000
    909     # $string_length_loop jal           ; Keep going
    910     $string_length_loop 6F000000
    911 
    912 :string_length_done
    913     # rd_a0 rs1_a2 mv                   ; return INDEX
    914     .00050000 .00000600 13000000
    915     # rd_a1 rs1_sp ld                   ; restore a1
    916     .80050000 .00000100 03300000
    917     # rd_a2 rs1_sp !8 ld                ; restore a2
    918     .00060000 .00000100 .00008000 03300000
    919     # rd_sp rs1_sp !16 addi             ; deallocate stack
    920     .00010000 .00000100 .00000001 13000000
    921     # rs1_ra jalr                       ; return
    922     .00800000 67000000
    923 
    924 
    925 ; Eval_Immediates function
    926 ; Receives List in a0
    927 ; Updates the list in place; does not modify registers
    928 ; Uses a1 for I->TEXT[0], a2 for I->TEXT[1] and a3 for I
    929 :Eval_Immediates
    930     # rd_sp rs1_sp !-40 addi            ; allocate stack
    931     .00010000 .00000100 .000080FD 13000000
    932     # rs1_sp rs2_ra sd                  ; protect ra
    933     .00000100 .00001000 23300000
    934     # rs1_sp rs2_a0 @8 sd               ; protect a0
    935     .00000100 .0000A000 .00040000 23300000
    936     # rs1_sp rs2_a1 @16 sd              ; protect a1
    937     .00000100 .0000B000 .00080000 23300000
    938     # rs1_sp rs2_a2 @24 sd              ; protect a2
    939     .00000100 .0000C000 .000C0000 23300000
    940     # rs1_sp rs2_a3 @32 sd              ; protect a3
    941     .00000100 .0000D000 .00000002 23300000
    942 
    943     # rd_a3 rs1_a0 mv                   ; I = HEAD
    944     .80060000 .00000500 13000000
    945 
    946 :Eval_Immediates_Loop
    947     ; Check for MACRO
    948     # rd_a0 rs1_a3 !8 ld                ; I->TYPE
    949     .00050000 .00800600 .00008000 03300000
    950     # rd_t0 !1 addi                     ; t0 = MACRO
    951     .80020000 .00001000 13000000
    952     # rs1_a0 rs2_t0 @Eval_Immediates_Next beq ; Skip to next if I->TYPE == MACRO
    953     .00000500 .00005000 @Eval_Immediates_Next 63000000
    954 
    955     ; Check for NULL EXPRESSION
    956     # rd_a0 rs1_a3 !24 ld               ; I->EXPRESSION
    957     .00050000 .00800600 .00008001 03300000
    958     # rs1_a0 @Eval_Immediates_Next bnez ; Skip to next if NULL == I->EXPRESSION
    959     .00000500 @Eval_Immediates_Next 63100000
    960 
    961     ; Check if number
    962     # rd_a0 rs1_a3 !16 ld               ; I->TEXT
    963     .00050000 .00800600 .00000001 03300000
    964     # rd_a1 rs1_a0 lbu                  ; I->TEXT[0]
    965     .80050000 .00000500 03400000
    966     # rd_a0 rs1_a0 !1 addi              ; I->TEXT + 1
    967     .00050000 .00000500 .00001000 13000000
    968     # rd_a2 rs1_a0 lbu                  ; I->TEXT[1]
    969     .00060000 .00000500 03400000
    970     # rd_ra $numerate_string jal        ; Convert string to INT
    971     .80000000 $numerate_string 6F000000
    972     # rs1_a0 @Eval_Immediates_value bnez ; Has a value IF 0 != numerate_string(I->TEXT + 1)
    973     .00000500 @Eval_Immediates_value 63100000
    974 
    975     ; Last chance for Immediate
    976     # rd_t0 !48 addi                    ; If '0' = I->TEXT[1]
    977     .80020000 .00000003 13000000
    978     # rs1_a2 rs2_t0 @Eval_Immediates_Next bne ; Skip to next
    979     .00000600 .00005000 @Eval_Immediates_Next 63100000
    980 
    981 :Eval_Immediates_value
    982     # rd_ra $express_number jal         ; Convert value to hex string
    983     .80000000 $express_number 6F000000
    984     # rs1_a3 rs2_a0 @24 sd              ; I->EXPRESSION = express_number(value, I-TEXT[0])
    985     .00800600 .0000A000 .000C0000 23300000
    986 
    987 :Eval_Immediates_Next
    988     # rd_a3 rs1_a3 ld                   ; I = I->NEXT
    989     .80060000 .00800600 03300000
    990     # rs1_a3 @Eval_Immediates_Loop bnez ; Check if we are done
    991     .00800600 @Eval_Immediates_Loop 63100000
    992 
    993     # rd_ra rs1_sp ld                   ; restore ra
    994     .80000000 .00000100 03300000
    995     # rd_a0 rs1_sp !8 ld                ; restore a0
    996     .00050000 .00000100 .00008000 03300000
    997     # rd_a1 rs1_sp !16 ld               ; restore a1
    998     .80050000 .00000100 .00000001 03300000
    999     # rd_a2 rs1_sp !24 ld               ; restore a2
   1000     .00060000 .00000100 .00008001 03300000
   1001     # rd_a3 rs1_sp !32 ld               ; restore a3
   1002     .80060000 .00000100 .00000002 03300000
   1003     # rd_sp rs1_sp !40 addi             ; deallocate stack
   1004     .00010000 .00000100 .00008002 13000000
   1005     # rs1_ra jalr                       ; return
   1006     .00800000 67000000
   1007 
   1008 
   1009 ; numerate_string function
   1010 ; Receives CHAR* in a0
   1011 ; Returns value of CHAR* in a0
   1012 ; Uses a0 for VALUE, a1 for S, a2 for CH and a3 for NEGATIVE?
   1013 :numerate_string
   1014     # rd_sp rs1_sp !-24 addi            ; allocate stack
   1015     .00010000 .00000100 .000080FE 13000000
   1016     # rs1_sp rs2_a1 sd                  ; protect a1
   1017     .00000100 .0000B000 23300000
   1018     # rs1_sp rs2_a2 @8 sd               ; protect a2
   1019     .00000100 .0000C000 .00040000 23300000
   1020     # rs1_sp rs2_a3 @16 sd              ; protect a3
   1021     .00000100 .0000D000 .00080000 23300000
   1022 
   1023     # rd_a1 rs1_a0 mv                   ; put S in correct place
   1024     .80050000 .00000500 13000000
   1025     # rd_a0 mv                          ; Initialize to Zero
   1026     .00050000 13000000
   1027 :numerate_string_loop
   1028     # rd_t0 rs1_a1 !1 addi              ; S + 1
   1029     .80020000 .00800500 .00001000 13000000
   1030     # rd_a2 rs1_t0 lbu                  ; S[1]
   1031     .00060000 .00800200 03400000
   1032     # rd_t0 !120 addi                   ; 'x'
   1033     .80020000 .00008007 13000000
   1034     # rs1_a2 rs2_t0 @numerate_hex beq   ; Deal with hex_input
   1035     .00000600 .00005000 @numerate_hex 63000000
   1036 
   1037     ; Assume decimal input
   1038     # rd_a3 mv                          ; Assume no negation
   1039     .80060000 13000000
   1040     # rd_a2 rs1_a1 lbu                  ; S[0]
   1041     .00060000 .00800500 03400000
   1042     # rd_t0 !45 addi                    ; '-'
   1043     .80020000 .0000D002 13000000
   1044     # rs1_a2 rs2_t0 @numerate_decimal bne ; Skip negation
   1045     .00000600 .00005000 @numerate_decimal 63100000
   1046 
   1047     # rd_a3 !1 addi                     ; Set FLAG
   1048     .80060000 .00001000 13000000
   1049     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1050     .80050000 .00800500 .00001000 13000000
   1051 
   1052 :numerate_decimal
   1053     # rd_a2 rs1_a1 lbu                  ; S[i]
   1054     .00060000 .00800500 03400000
   1055     # rs1_a2 @numerate_decimal_done beqz ; We are done if NULL == S[i]
   1056     .00000600 @numerate_decimal_done 63000000
   1057 
   1058     ; a0 = a0 * 10 = (a0 << 3) + (a0 << 1)
   1059     # rd_t0 rs1_a0 rs2_x3 slli          ; a0 * 8
   1060     .80020000 .00000500 .00003000 13100000
   1061     # rd_t1 rs1_a0 rs2_x1 slli          ; a0 * 2
   1062     .00030000 .00000500 .00001000 13100000
   1063     # rd_a0 rs1_t0 rs2_t1 add           ; VALUE = VALUE * 10
   1064     .00050000 .00800200 .00006000 33000000
   1065     # rd_a2 rs1_a2 !-48 addi            ; CH = CH - '0'
   1066     .00060000 .00000600 .000000FD 13000000
   1067     # rd_t0 !9 addi                     ; t0 = 9
   1068     .80020000 .00009000 13000000
   1069     # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for illegal CH > 9
   1070     .00800200 .0000C000 @numerate_string_fail 63400000
   1071     # rs1_a2 @numerate_string_fail bltz ; Check for illegal CH < 0
   1072     .00000600 @numerate_string_fail 63400000
   1073     # rd_a0 rs1_a0 rs2_a2 add           ; VALUE = VALUE + CH
   1074     .00050000 .00000500 .0000C000 33000000
   1075     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1076     .80050000 .00800500 .00001000 13000000
   1077     # $numerate_decimal jal
   1078     $numerate_decimal 6F000000
   1079 
   1080 :numerate_decimal_done
   1081     # rd_t0 !1 addi                     ; Check for negative FLAG
   1082     .80020000 .00001000 13000000
   1083     # rs1_a3 rs2_t0 @numerate_string_done bne ; Nope
   1084     .00800600 .00005000 @numerate_string_done 63100000
   1085 
   1086     # rd_a0 rs2_a0 sub                  ; VALUE = -VALUE
   1087     .00050000 .0000A000 33000040
   1088     # $numerate_string_done jal         ; Done
   1089     $numerate_string_done 6F000000
   1090 
   1091 :numerate_hex
   1092     # rd_a1 rs1_a1 !2 addi              ; S = S + 2
   1093     .80050000 .00800500 .00002000 13000000
   1094 :numerate_hex_loop
   1095     # rd_a2 rs1_a1 lbu                  ; S[i]
   1096     .00060000 .00800500 03400000
   1097     # rs1_a2 @numerate_string_done beqz ; We are done if NULL == S[i]
   1098     .00000600 @numerate_string_done 63000000
   1099 
   1100     # rd_a0 rs1_a0 rs2_x4 slli          ; VALUE = VALUE << 4
   1101     .00050000 .00000500 .00004000 13100000
   1102     # rd_a2 rs1_a2 !-48 addi            ; CH = CH - '0'
   1103     .00060000 .00000600 .000000FD 13000000
   1104     # rd_t0 !10 addi                    ; t0 = 10
   1105     .80020000 .0000A000 13000000
   1106     # rs1_a2 rs2_t0 @numerate_hex_digit blt ; Check if we are dealing with number or letter
   1107     .00000600 .00005000 @numerate_hex_digit 63400000
   1108     # rd_a2 rs1_a2 !-7 addi             ; Push A-F into range
   1109     .00060000 .00000600 .000090FF 13000000
   1110 
   1111 :numerate_hex_digit
   1112     # rd_t0 !15 addi                    ; t0 = 15
   1113     .80020000 .0000F000 13000000
   1114     # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for CH > 'F'
   1115     .00800200 .0000C000 @numerate_string_fail 63400000
   1116     # rs1_a2 @numerate_string_fail bltz ; Check for CH < 0
   1117     .00000600 @numerate_string_fail 63400000
   1118     # rd_a0 rs1_a0 rs2_a2 add           ; VALUE = VALUE + CH
   1119     .00050000 .00000500 .0000C000 33000000
   1120     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1121     .80050000 .00800500 .00001000 13000000
   1122     # $numerate_hex_loop jal            ; Keep looping
   1123     $numerate_hex_loop 6F000000
   1124 
   1125 :numerate_string_fail
   1126     # rd_a0 mv                          ; return ZERO
   1127     .00050000 13000000
   1128 
   1129 :numerate_string_done
   1130     # rd_a1 rs1_sp ld                   ; restore a1
   1131     .80050000 .00000100 03300000
   1132     # rd_a2 rs1_sp !8 ld                ; restore a2
   1133     .00060000 .00000100 .00008000 03300000
   1134     # rd_a3 rs1_sp !16 ld               ; restore a3
   1135     .80060000 .00000100 .00000001 03300000
   1136     # rd_sp rs1_sp !24 addi             ; deallocate stack
   1137     .00010000 .00000100 .00008001 13000000
   1138     # rs1_ra jalr                       ; return
   1139     .00800000 67000000
   1140 
   1141 
   1142 ; express_number function
   1143 ; Receives INT in a0 and CHAR in a1
   1144 ; Allocates a string and expresses the value in appropriate RISC-V encoding
   1145 ; Returns string in a0
   1146 ; Uses a0 for VALUE, a1 for S and a2 for CH
   1147 :express_number
   1148     # rd_sp rs1_sp !-32 addi            ; allocate stack
   1149     .00010000 .00000100 .000000FE 13000000
   1150     # rs1_sp rs2_ra sd                  ; protect ra
   1151     .00000100 .00001000 23300000
   1152     # rs1_sp rs2_a1 @8 sd               ; protect a1
   1153     .00000100 .0000B000 .00040000 23300000
   1154     # rs1_sp rs2_a2 @16 sd              ; protect a2
   1155     .00000100 .0000C000 .00080000 23300000
   1156     # rs1_sp rs2_a3 @24 sd              ; protect a3
   1157     .00000100 .0000D000 .000C0000 23300000
   1158 
   1159     # rd_a2 rs1_a1 mv                   ; Put CH in right place
   1160     .00060000 .00800500 13000000
   1161     # rd_s5 rs1_a0 mv                   ; Protect VALUE
   1162     .800A0000 .00000500 13000000
   1163 
   1164     # rd_a0 !10 addi                    ; We need 10 bytes
   1165     .00050000 .0000A000 13000000
   1166     # rd_ra $malloc jal                 ; Get S pointer
   1167     .80000000 $malloc 6F000000
   1168     # rd_a1 rs1_a0 mv                   ; Put S in place
   1169     .80050000 .00000500 13000000
   1170     # rd_a0 rs1_s5 mv                   ; Restore VALUE
   1171     .00050000 .00800A00 13000000
   1172 
   1173     ; Check for %
   1174     # rd_t0 !0x25 addi
   1175     .80020000 .00005002 13000000
   1176     # rs1_a2 rs2_t0 @express_number_const beq
   1177     .00000600 .00005000 @express_number_const 63000000
   1178 
   1179     # rd_s5 rs1_a1 mv                   ; Protect S
   1180     .800A0000 .00800500 13000000
   1181     # rd_t0 !0x2E addi                  ; t0 = '.'
   1182     .80020000 .0000E002 13000000
   1183     # rs1_a1 rs2_t0 sd                  ; S[0] = '.'
   1184     .00800500 .00005000 23300000
   1185     # rd_a1 rs1_a1 !1 addi              ; Next byte
   1186     .80050000 .00800500 .00001000 13000000
   1187 
   1188     ; Check for !
   1189     # rd_t0 !0x21 addi
   1190     .80020000 .00001002 13000000
   1191     # rs1_a2 rs2_t0 @express_number_I beq
   1192     .00000600 .00005000 @express_number_I 63000000
   1193 
   1194     ; Check for @
   1195     # rd_t0 !0x40 addi
   1196     .80020000 .00000004 13000000
   1197     # rs1_a2 rs2_t0 @express_number_S beq
   1198     .00000600 .00005000 @express_number_S 63000000
   1199 
   1200     ; Check for ~
   1201     # rd_t0 !0x7E addi
   1202     .80020000 .0000E007 13000000
   1203     # rs1_a2 rs2_t0 @express_number_U beq
   1204     .00000600 .00005000 @express_number_U 63000000
   1205 
   1206     # $Fail jal                         ; Error
   1207     $Fail 6F000000
   1208 
   1209 :express_number_const
   1210     ; provides an option for 32-bit immediate constants
   1211 
   1212     # rd_t0 !2 addi
   1213     .80020000 .00002000 13000000
   1214     # rd_t0 rs1_t0 rs2_x31 slli
   1215     .80020000 .00800200 .0000F001 13100000
   1216     # rd_t0 rs1_t0 !-1 addi             ; t0 = 0xffffffff
   1217     .80020000 .00800200 .0000F0FF 13000000
   1218     # rd_a0 rs1_a0 rs2_t0 and           ; immediate = value & 0xffffffff
   1219     .00050000 .00000500 .00005000 33700000
   1220 
   1221     # rd_s5 rs1_a1 mv                   ; Protect S
   1222     .800A0000 .00800500 13000000
   1223     # rd_ra $hex32l jal                 ; Store 32-bits
   1224     .80000000 $hex32l 6F000000
   1225     # $express_number_done jal          ; done
   1226     $express_number_done 6F000000
   1227 
   1228 :express_number_I
   1229     ; Corresponds to RISC-V S format
   1230     ; (value & 0xfff) << 20
   1231     # rd_t0 !0xFFF addi
   1232     .80020000 .0000F0FF 13000000
   1233     # rd_a0 rs1_a0 rs2_t0 and           ; value & 0xfff
   1234     .00050000 .00000500 .00005000 33700000
   1235     # rd_a0 rs1_a0 rs2_x20 slli         ; (value & 0xfff) << 20
   1236     .00050000 .00000500 .00004001 13100000
   1237     # rd_ra $hex32l jal                 ; Store 32-bits
   1238     .80000000 $hex32l 6F000000
   1239     # $express_number_done jal          ; done
   1240     $express_number_done 6F000000
   1241 
   1242 :express_number_S
   1243     ; Corresponds to RISC-V S format
   1244     ; ((value & 0x1f) << 7) | ((value & 0xfe0) << (31 - 11))
   1245     # rd_t0 !0x1F addi
   1246     .80020000 .0000F001 13000000
   1247     # rd_t1 rs1_a0 rs2_t0 and           ; value & 0x1f
   1248     .00030000 .00000500 .00005000 33700000
   1249     # rd_t1 rs1_t1 rs2_x7 slli          ; (value & 0x1f) << 7
   1250     .00030000 .00000300 .00007000 13100000
   1251     # rd_t0 !0xFE0 addi
   1252     .80020000 .000000FE 13000000
   1253     # rd_t0 rs1_a0 rs2_t0 and           ; value & 0xfe0
   1254     .80020000 .00000500 .00005000 33700000
   1255     # rd_t0 rs1_t0 rs2_x20 slli         ; (value & 0xfe0) << (31 - 11)
   1256     .80020000 .00800200 .00004001 13100000
   1257     # rd_a0 rs1_t0 rs2_t1 or            ; Combine two parts
   1258     .00050000 .00800200 .00006000 33600000
   1259     # rd_ra $hex32l jal                 ; Store 32-bits
   1260     .80000000 $hex32l 6F000000
   1261     # $express_number_done jal          ; done
   1262     $express_number_done 6F000000
   1263 
   1264 :express_number_U
   1265     ; Corresponds to RISC-V U format
   1266     ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension
   1267 
   1268     # rd_t0 ~0x800 lui                  ; load higher bits
   1269     .80020000 .00100000 37000000
   1270     # rd_t0 rs1_t0 !0x800 addiw
   1271     .80020000 .00800200 .00000080 1B000000
   1272     # rd_t1 ~0xFFF lui                  ; load higher bits
   1273     .00030000 .00100000 37000000
   1274     # rd_t1 rs1_t1 !0xFFF addiw
   1275     .00030000 .00000300 .0000F0FF 1B000000
   1276     ; We are outside 31-bit that ~ can normally load
   1277     # rd_t2 ~0x100000 lui               ; load 0xfffff000
   1278     .80030000 .00001000 37000000
   1279     # rd_t2 rs1_t2 !-1 addiw            ; load 0xfffff000
   1280     .80030000 .00800300 .0000F0FF 1B000000
   1281     # rd_t2 rs1_t2 rs2_x12 slli         ; load 0xfffff000
   1282     .80030000 .00800300 .0000C000 13100000
   1283     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xfff
   1284     .00030000 .00000500 .00006000 33700000
   1285     # rd_a0 rs1_a0 rs2_t2 and           ; value & 0xfffff000
   1286     .00050000 .00000500 .00007000 33700000
   1287     # rs1_t1 rs2_t0 @express_number_U_small blt
   1288     .00000300 .00005000 @express_number_U_small 63400000
   1289 
   1290     ; Deal with sign extension: add 0x1000
   1291     # rd_t0 ~0x1000 lui
   1292     .80020000 .00100000 37000000
   1293     # rd_a0 rs1_t0 rs2_a0 addw          ; (value & 0xfffff000) + 0x1000
   1294     .00050000 .00800200 .0000A000 3B000000
   1295 :express_number_U_small
   1296     # rd_ra $hex32l jal                 ; Store 32-bits
   1297     .80000000 $hex32l 6F000000
   1298     # $express_number_done jal          ; done
   1299     $express_number_done 6F000000
   1300 
   1301 :express_number_done
   1302     # rd_a0 rs1_s5 mv                   ; Restore S
   1303     .00050000 .00800A00 13000000
   1304     # rd_ra rs1_sp ld                   ; restore ra
   1305     .80000000 .00000100 03300000
   1306     # rd_a1 rs1_sp !8 ld                ; restore a1
   1307     .80050000 .00000100 .00008000 03300000
   1308     # rd_a2 rs1_sp !16 ld               ; restore a2
   1309     .00060000 .00000100 .00000001 03300000
   1310     # rd_a3 rs1_sp !24 ld               ; restore a3
   1311     .80060000 .00000100 .00008001 03300000
   1312     # rd_sp rs1_sp !32 addi             ; deallocate stack
   1313     .00010000 .00000100 .00000002 13000000
   1314     # rs1_ra jalr                       ; return
   1315     .00800000 67000000
   1316 
   1317 
   1318 ; HEX to ascii routine
   1319 ; Receives INT in a0 and CHAR* in a1
   1320 ; Stores ascii of INT in CHAR*
   1321 ; Returns only modifying a0
   1322 :hex32l
   1323     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1324     .00010000 .00000100 .000000FF 13000000
   1325     # rs1_sp rs2_ra sd                  ; Protect ra
   1326     .00000100 .00001000 23300000
   1327     # rs1_sp rs2_a0 @8 sd               ; Protect top 16 bits
   1328     .00000100 .0000A000 .00040000 23300000
   1329     # rd_ra $hex16l jal                 ; Store it
   1330     .80000000 $hex16l 6F000000
   1331     # rd_a0 rs1_sp !8 ld                ; do high 16-bits
   1332     .00050000 .00000100 .00008000 03300000
   1333     # rd_a0 rs1_a0 rs2_x16 srli         ; do bottom 16 bits
   1334     .00050000 .00000500 .00000001 13500000
   1335     # rd_ra $hex16l jal                 ; Store it
   1336     .80000000 $hex16l 6F000000
   1337     # rd_ra rs1_sp ld                   ; restore ra
   1338     .80000000 .00000100 03300000
   1339     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1340     .00010000 .00000100 .00000001 13000000
   1341     # rs1_ra jalr                       ; return
   1342     .00800000 67000000
   1343 
   1344 :hex16l
   1345     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1346     .00010000 .00000100 .000000FF 13000000
   1347     # rs1_sp rs2_ra sd                  ; Protect ra
   1348     .00000100 .00001000 23300000
   1349     # rs1_sp rs2_a0 @8 sd               ; Protect top byte
   1350     .00000100 .0000A000 .00040000 23300000
   1351     # rd_ra $hex8 jal                   ; Store it
   1352     .80000000 $hex8 6F000000
   1353     # rd_a0 rs1_sp !8 ld                ; do high byte
   1354     .00050000 .00000100 .00008000 03300000
   1355     # rd_a0 rs1_a0 rs2_x8 srli          ; do bottom byte
   1356     .00050000 .00000500 .00008000 13500000
   1357     # rd_ra $hex8 jal                   ; Store it
   1358     .80000000 $hex8 6F000000
   1359     # rd_ra rs1_sp ld                   ; restore ra
   1360     .80000000 .00000100 03300000
   1361     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1362     .00010000 .00000100 .00000001 13000000
   1363     # rs1_ra jalr                       ; return
   1364     .00800000 67000000
   1365 
   1366 :hex8
   1367     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1368     .00010000 .00000100 .000000FF 13000000
   1369     # rs1_sp rs2_ra sd                  ; Protect ra
   1370     .00000100 .00001000 23300000
   1371     # rs1_sp rs2_a0 @8 sd               ; Protect bottom nibble
   1372     .00000100 .0000A000 .00040000 23300000
   1373     # rd_a0 rs1_a0 rs2_x4 srli          ; do high nibble first
   1374     .00050000 .00000500 .00004000 13500000
   1375     # rd_ra $hex4 jal                   ; Store it
   1376     .80000000 $hex4 6F000000
   1377     # rd_a0 rs1_sp !8 ld                ; do low nibble
   1378     .00050000 .00000100 .00008000 03300000
   1379     # rd_ra $hex4 jal                   ; Store it
   1380     .80000000 $hex4 6F000000
   1381     # rd_ra rs1_sp ld                   ; restore ra
   1382     .80000000 .00000100 03300000
   1383     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1384     .00010000 .00000100 .00000001 13000000
   1385     # rs1_ra jalr                       ; return
   1386     .00800000 67000000
   1387 
   1388 :hex4
   1389     # rd_t0 !0xF addi
   1390     .80020000 .0000F000 13000000
   1391     # rd_a0 rs1_a0 rs2_t0 and           ; isolate nibble
   1392     .00050000 .00000500 .00005000 33700000
   1393     # rd_a0 rs1_a0 !0x30 addi           ; convert to ascii
   1394     .00050000 .00000500 .00000003 13000000
   1395     # rd_t0 !0x39 addi                  ; t0 = '9'
   1396     .80020000 .00009003 13000000
   1397     # rs1_t0 rs2_a0 @hex1 bge           ; check if valid digit
   1398     .00800200 .0000A000 @hex1 63500000
   1399     # rd_a0 rs1_a0 !7 addi              ; use alpha range
   1400     .00050000 .00000500 .00007000 13000000
   1401 :hex1
   1402     # rs1_a1 rs2_a0 sb                  ; store result
   1403     .00800500 .0000A000 23000000
   1404     # rd_a1 rs1_a1 !1 addi              ; next position
   1405     .80050000 .00800500 .00001000 13000000
   1406     # rs1_ra jalr                       ; return
   1407     .00800000 67000000
   1408 
   1409 
   1410 ; Preserve_Other function
   1411 ; Receives list in a0
   1412 ; Update the list in place; does not modify registers
   1413 ; Uses a0 for I, a1 for I->TEXT
   1414 :Preserve_Other
   1415     # rd_sp rs1_sp !-32 addi            ; allocate stack
   1416     .00010000 .00000100 .000000FE 13000000
   1417     # rs1_sp rs2_a1 sd                  ; protect a1
   1418     .00000100 .0000B000 23300000
   1419     # rs1_sp rs2_a2 @8 sd               ; protect a2
   1420     .00000100 .0000C000 .00040000 23300000
   1421     # rs1_sp rs2_a3 @16 sd              ; protect a3
   1422     .00000100 .0000D000 .00080000 23300000
   1423     # rs1_sp rs2_a4 @24 sd              ; protect a4
   1424     .00000100 .0000E000 .000C0000 23300000
   1425 :Preserve_Other_Loop
   1426     # rd_a1 rs1_a0 !24 ld               ; I->EXPRESSION
   1427     .80050000 .00000500 .00008001 03300000
   1428     # rs1_a1 @Preserve_Other_Next bnez  ; IF NULL == I->EXPRESSION then preserve
   1429     .00800500 @Preserve_Other_Next 63100000
   1430 
   1431     # rd_a1 rs1_a0 !16 ld               ; I->TEXT
   1432     .80050000 .00000500 .00000001 03300000
   1433     # rs1_a0 rs2_a1 @24 sd              ; I->EXPRESSION = I->TEXT
   1434     .00000500 .0000B000 .000C0000 23300000
   1435 
   1436 :Preserve_Other_Next
   1437     # rd_a0 rs1_a0 ld                   ; I = I->NEXT
   1438     .00050000 .00000500 03300000
   1439     # rs1_a0 @Preserve_Other_Loop bnez  ; Keep looping until I == NULL
   1440     .00000500 @Preserve_Other_Loop 63100000
   1441 
   1442     # rd_a1 rs1_sp ld                   ; restore a1
   1443     .80050000 .00000100 03300000
   1444     # rd_a2 rs1_sp !8 ld                ; restore a2
   1445     .00060000 .00000100 .00008000 03300000
   1446     # rd_a3 rs1_sp !16 ld               ; restore a3
   1447     .80060000 .00000100 .00000001 03300000
   1448     # rd_a4 rs1_sp !24 ld               ; restore a4
   1449     .00070000 .00000100 .00008001 03300000
   1450     # rd_sp rs1_sp !32 addi             ; deallocate stack
   1451     .00010000 .00000100 .00000002 13000000
   1452     # rs1_ra jalr                       ; return
   1453     .00800000 67000000
   1454 
   1455 
   1456 ; Print_Hex function
   1457 ; Receives list in a0
   1458 ; walks the list and prints the I->EXPRESSION for all nodes followed by newline
   1459 ; Uses a1 for I
   1460 :Print_Hex
   1461     # rd_sp rs1_sp !-24 addi            ; allocate stack
   1462     .00010000 .00000100 .000080FE 13000000
   1463     # rs1_sp rs2_ra sd                  ; protect ra
   1464     .00000100 .00001000 23300000
   1465     # rs1_sp rs2_a1 @8 sd               ; protect a1
   1466     .00000100 .0000B000 .00040000 23300000
   1467     # rs1_sp rs2_a2 @16 sd              ; protect a2
   1468     .00000100 .0000C000 .00080000 23300000
   1469 
   1470     # rd_a1 rs1_s4 mv                   ; I = HEAD
   1471     .80050000 .00000A00 13000000
   1472 
   1473 :Print_Hex_Loop
   1474     # rd_a0 rs1_a1 !8 ld                ; I->TYPE
   1475     .00050000 .00800500 .00008000 03300000
   1476     # rd_t0 !1 addi                     ; t0 = MACRO
   1477     .80020000 .00001000 13000000
   1478     # rs1_a0 rs2_t0 @Print_Hex_Next beq ; Skip if MACRO = I->TYPE
   1479     .00000500 .00005000 @Print_Hex_Next 63000000
   1480 
   1481     # rd_a0 rs1_a1 !24 ld               ; Using EXPRESSION
   1482     .00050000 .00800500 .00008001 03300000
   1483     # rd_ra $File_Print jal             ; Print it
   1484     .80000000 $File_Print 6F000000
   1485     # rd_a0 !10 addi                    ; \n
   1486     .00050000 .0000A000 13000000
   1487     # rd_ra $fputc jal                  ; Print newline
   1488     .80000000 $fputc 6F000000
   1489 
   1490 :Print_Hex_Next
   1491     # rd_a1 rs1_a1 ld                   ; Iterate to next Token
   1492     .80050000 .00800500 03300000
   1493     # rs1_a1 @Print_Hex_Loop bnez       ; Stop if NULL, otherwise keep looping
   1494     .00800500 @Print_Hex_Loop 63100000
   1495 
   1496     # rd_ra rs1_sp ld                   ; restore ra
   1497     .80000000 .00000100 03300000
   1498     # rd_a1 rs1_sp !8 ld                ; restore a1
   1499     .80050000 .00000100 .00008000 03300000
   1500     # rd_a2 rs1_sp !16 ld               ; restore a2
   1501     .00060000 .00000100 .00000001 03300000
   1502     # rd_sp rs1_sp !24 addi             ; deallocate stack
   1503     .00010000 .00000100 .00008001 13000000
   1504     # rs1_ra jalr                       ; return
   1505     .00800000 67000000
   1506 
   1507 
   1508 ; File_Print function
   1509 ; Receives CHAR* in a0
   1510 ; calls fputc for every non-null char
   1511 :File_Print
   1512     # rd_sp rs1_sp !-24 addi            ; allocate stack
   1513     .00010000 .00000100 .000080FE 13000000
   1514     # rs1_sp rs2_ra sd                  ; protect ra
   1515     .00000100 .00001000 23300000
   1516     # rs1_sp rs2_a1 @8 sd               ; protect a1
   1517     .00000100 .0000B000 .00040000 23300000
   1518     # rs1_sp rs2_a2 @16 sd              ; protect a2
   1519     .00000100 .0000C000 .00080000 23300000
   1520     # rd_a1 rs1_a0 mv                   ; protect a0
   1521     .80050000 .00000500 13000000
   1522 
   1523     # rs1_a0 @File_Print_Done beqz      ; Protect against nulls
   1524     .00000500 @File_Print_Done 63000000
   1525 
   1526 :File_Print_Loop
   1527     # rd_a0 rs1_a1 lbu                  ; Read byte
   1528     .00050000 .00800500 03400000
   1529     # rs1_a0 @File_Print_Done beqz      ; Stop at NULL
   1530     .00000500 @File_Print_Done 63000000
   1531 
   1532     # rd_ra $fputc jal                  ; print it
   1533     .80000000 $fputc 6F000000
   1534     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1535     .80050000 .00800500 .00001000 13000000
   1536     # $File_Print_Loop jal              ; Keep printing
   1537     $File_Print_Loop 6F000000
   1538 
   1539 :File_Print_Done
   1540     # rd_ra rs1_sp ld                   ; restore ra
   1541     .80000000 .00000100 03300000
   1542     # rd_a1 rs1_sp !8 ld                ; restore a1
   1543     .80050000 .00000100 .00008000 03300000
   1544     # rd_a2 rs1_sp !16 ld               ; restore a2
   1545     .00060000 .00000100 .00000001 03300000
   1546     # rd_sp rs1_sp !24 addi             ; deallocate stack
   1547     .00010000 .00000100 .00008001 13000000
   1548     # rs1_ra jalr                       ; return
   1549     .00800000 67000000
   1550 
   1551 
   1552 ; fgetc function
   1553 ; Loads FILE* from s2
   1554 ; Returns -4 (EOF) or char in a0
   1555 :fgetc
   1556     # rd_sp rs1_sp !-32 addi            ; allocate stack
   1557     .00010000 .00000100 .000000FE 13000000
   1558     # rs1_sp rs2_ra @8 sd               ; protect ra
   1559     .00000100 .00001000 .00040000 23300000
   1560     # rs1_sp rs2_a1 @16 sd              ; protect a1
   1561     .00000100 .0000B000 .00080000 23300000
   1562     # rs1_sp rs2_a2 @24 sd              ; protect a2
   1563     .00000100 .0000C000 .000C0000 23300000
   1564 
   1565     # rd_a7 !63 addi                    ; sys_read
   1566     .80080000 .0000F003 13000000
   1567     # rd_a1 rs1_sp mv                   ; Get stack address for buffer
   1568     .80050000 .00000100 13000000
   1569     # rd_a0 rs1_s2 mv                   ; read from input file
   1570     .00050000 .00000900 13000000
   1571     # rd_a2 !1 addi                     ; read 1 character
   1572     .00060000 .00001000 13000000
   1573     # ecall                             ; syscall
   1574     73000000
   1575 
   1576     # rs1_a0 @fgetc_done bnez           ; Check if nothing was read
   1577     .00000500 @fgetc_done 63100000
   1578     # rd_a2 !-4 addi                    ; Use -4 as EOF
   1579     .00060000 .0000C0FF 13000000
   1580     # rs1_a1 rs2_a2 sb                  ; Store EOF in *a1
   1581     .00800500 .0000C000 23000000
   1582 
   1583 :fgetc_done
   1584     # rd_a0 rs1_a1 lb                   ; return char in a0
   1585     .00050000 .00800500 03000000
   1586     # rd_ra rs1_sp !8 ld                ; restore ra
   1587     .80000000 .00000100 .00008000 03300000
   1588     # rd_a1 rs1_sp !16 ld               ; restore a1
   1589     .80050000 .00000100 .00000001 03300000
   1590     # rd_a2 rs1_sp !24 ld               ; restore a2
   1591     .00060000 .00000100 .00008001 03300000
   1592     # rd_sp rs1_sp !32 addi             ; deallocate stack
   1593     .00010000 .00000100 .00000002 13000000
   1594     # rs1_ra jalr                       ; return
   1595     .00800000 67000000
   1596 
   1597 
   1598 ; Malloc isn't actually required if the program being built fits in the initial memory
   1599 ; However, it doesn't take much to add it.
   1600 ; Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes
   1601 :malloc
   1602     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1603     .00010000 .00000100 .000000FF 13000000
   1604     # rs1_sp rs2_ra sd                  ; protect ra
   1605     .00000100 .00001000 23300000
   1606     # rs1_sp rs2_a1 @8 sd               ; protect a1
   1607     .00000100 .0000B000 .00040000 23300000
   1608 
   1609     # rd_a1 rs1_s1 mv                   ; Store the current pointer
   1610     .80050000 .00800400 13000000
   1611     # rd_a0 rs1_a0 rs2_s1 add           ; Request the number of desired bytes
   1612     .00050000 .00000500 .00009000 33000000
   1613     # rd_a7 !214 addi                   ; sys_brk
   1614     .80080000 .0000600D 13000000
   1615     # ecall                             ; syscall
   1616     73000000
   1617     # rd_s1 rs1_a0 mv                   ; Set our malloc pointer
   1618     .80040000 .00000500 13000000
   1619     # rd_a0 rs1_a1 mv                   ; Return the pointer
   1620     .00050000 .00800500 13000000
   1621 
   1622     # rd_ra rs1_sp ld                   ; restore ra
   1623     .80000000 .00000100 03300000
   1624     # rd_a1 rs1_sp !8 ld                ; restore a1
   1625     .80050000 .00000100 .00008000 03300000
   1626     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1627     .00010000 .00000100 .00000001 13000000
   1628     # rs1_ra jalr                       ; return
   1629     .00800000 67000000
   1630 
   1631 
   1632 ; fputc function
   1633 ; receives CHAR in a0 and load FILE* from s3
   1634 ; writes char and returns
   1635 :fputc
   1636     # rd_sp rs1_sp !-32 addi            ; allocate stack
   1637     .00010000 .00000100 .000000FE 13000000
   1638     # rs1_sp rs2_a0 sd                  ; protect a0
   1639     .00000100 .0000A000 23300000
   1640     # rs1_sp rs2_ra @8 sd               ; protect ra
   1641     .00000100 .00001000 .00040000 23300000
   1642     # rs1_sp rs2_a1 @16 sd              ; protect a1
   1643     .00000100 .0000B000 .00080000 23300000
   1644     # rs1_sp rs2_a2 @24 sd              ; protect a2
   1645     .00000100 .0000C000 .000C0000 23300000
   1646 
   1647     # rd_a7 !64 addi                    ; sys_write
   1648     .80080000 .00000004 13000000
   1649     # rd_a0 rs1_s3 mv                   ; write to output
   1650     .00050000 .00800900 13000000
   1651     # rd_a1 rs1_sp mv                   ; Get stack address
   1652     .80050000 .00000100 13000000
   1653     # rd_a2 !1 addi                     ; write 1 character
   1654     .00060000 .00001000 13000000
   1655     # ecall                             ; syscall
   1656     73000000
   1657 
   1658     # rd_a0 rs1_sp ld                   ; restore a0
   1659     .00050000 .00000100 03300000
   1660     # rd_ra rs1_sp !8 ld                ; restore ra
   1661     .80000000 .00000100 .00008000 03300000
   1662     # rd_a1 rs1_sp !16 ld               ; restore a1
   1663     .80050000 .00000100 .00000001 03300000
   1664     # rd_a2 rs1_sp !24 ld               ; restore a2
   1665     .00060000 .00000100 .00008001 03300000
   1666     # rd_sp rs1_sp !32 addi             ; deallocate stack
   1667     .00010000 .00000100 .00000002 13000000
   1668     # rs1_ra jalr                       ; return
   1669     .00800000 67000000
   1670 
   1671 
   1672 :Fail
   1673     ; Terminate program with 1 return code
   1674     # rd_a7 !93 addi                    ; sys_exit
   1675     .80080000 .0000D005 13000000
   1676     # rd_a0 !1 addi                     ; Return code 1
   1677     .00050000 .00001000 13000000
   1678     # ecall                             ; exit(1)
   1679     73000000
   1680 
   1681 ; PROGRAM END
   1682 
   1683 :terminators
   1684 #	"
   1685 #	 "
   1686 0A 09 20 00
   1687 
   1688 :comments
   1689 #	"#;"
   1690 23 3B 00
   1691 
   1692 :string_char
   1693 #	'22 27 00'
   1694 22 27 00
   1695 
   1696 :DEFINE_str
   1697 #	"DEFINE"
   1698 44 45 46 49 4E 45 00
   1699 
   1700 :ELF_end