boot2

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

M0.hex2 (65307B)


      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 16)
     32 ; NEXT => 0                           ; Next element in linked list
     33 ; TYPE => 4                           ; Token type
     34 ; TEXT => 8
     35 ; EXPRESSION => 12
     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 !8 lw                ; Input file name
     47     .00060000 .00000100 .00008000 03200000
     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 lw                   ; Get number of the args
     73     .00050000 .00000100 03200000
     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 !12 lw               ; Output file (argument 3)
     85     .80050000 .00000100 .0000C000 03200000
     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 !-4 addi             ; allocate stack
    153     .00010000 .00000100 .0000C0FF 13000000
    154     # rs1_sp rs2_ra sw                  ; protect ra
    155     .00000100 .00001000 23200000
    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 !16 addi                    ; malloc struct P
    193     .00050000 .00000001 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 sw                  ; P->NEXT = HEAD
    199     .00800600 .00004001 23200000
    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 lw                   ; restore ra
    223     .80000000 .00000100 03200000
    224     # rd_sp rs1_sp !4 addi              ; deallocate stack
    225     .00010000 .00000100 .00004000 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 !-4 addi             ; allocate stack
    235     .00010000 .00000100 .0000C0FF 13000000
    236     # rs1_sp rs2_a1 sw                  ; protect a1
    237     .00000100 .0000B000 23200000
    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 lw                   ; restore a1
    255     .80050000 .00000100 03200000
    256     # rd_sp rs1_sp !4 addi              ; deallocate stack
    257     .00010000 .00000100 .00004000 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 lw                   ; restore a1
    265     .80050000 .00000100 03200000
    266     # rd_sp rs1_sp !4 addi              ; deallocate stack
    267     .00010000 .00000100 .00004000 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 !-12 addi            ; allocate stack
    290     .00010000 .00000100 .000040FF 13000000
    291     # rs1_sp rs2_a1 sw                  ; protect a1
    292     .00000100 .0000B000 23200000
    293     # rs1_sp rs2_a2 @4 sw               ; protect a2
    294     .00000100 .0000C000 .00020000 23200000
    295     # rs1_sp rs2_a3 @8 sw               ; protect a3
    296     .00000100 .0000D000 .00040000 23200000
    297 
    298     # rd_a0 !2 addi                     ; Using TYPE STRING
    299     .00050000 .00002000 13000000
    300     # rs1_a3 rs2_a0 @4 sw               ; HEAD->TYPE = STRING
    301     .00800600 .0000A000 .00020000 23200000
    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 !8 lw                ; restore a3 (HEAD)
    327     .80060000 .00000100 .00008000 03200000
    328     # rs1_a3 rs2_a0 @8 sw               ; HEAD->TEXT = STRING
    329     .00800600 .0000A000 .00040000 23200000
    330     # rd_ra $copy_string jal            ; Copy the string
    331     .80000000 $copy_string 6F000000
    332 
    333     # rd_a1 rs1_sp lw                   ; restore a1
    334     .80050000 .00000100 03200000
    335     # rd_a2 rs1_sp !4 lw                ; restore a2
    336     .00060000 .00000100 .00004000 03200000
    337     # rd_sp rs1_sp !12 addi             ; deallocate stack
    338     .00010000 .00000100 .0000C000 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 !-12 addi            ; allocate stack
    348     .00010000 .00000100 .000040FF 13000000
    349     # rs1_sp rs2_ra sw                  ; protect ra
    350     .00000100 .00001000 23200000
    351     # rs1_sp rs2_a1 @4 sw               ; protect a1
    352     .00000100 .0000B000 .00020000 23200000
    353     # rs1_sp rs2_a2 @8 sw               ; protect a2
    354     .00000100 .0000C000 .00040000 23200000
    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 lw                   ; restore ra
    379     .80000000 .00000100 03200000
    380     # rd_a1 rs1_sp !4 lw                ; restore a1
    381     .80050000 .00000100 .00004000 03200000
    382     # rd_a2 rs1_sp !8 lw                ; restore a2
    383     .00060000 .00000100 .00008000 03200000
    384     # rd_sp rs1_sp !12 addi             ; deallocate stack
    385     .00010000 .00000100 .0000C000 13000000
    386     # ret
    387     67800000
    388 
    389 
    390 ; Zero scratch area
    391 :ClearScratch
    392     # rd_sp rs1_sp !-12 addi            ; allocate stack
    393     .00010000 .00000100 .000040FF 13000000
    394     # rs1_sp rs2_ra sw                  ; protect ra
    395     .00000100 .00001000 23200000
    396     # rs1_sp rs2_a0 @4 sw               ; protect a0
    397     .00000100 .0000A000 .00020000 23200000
    398     # rs1_sp rs2_a1 @8 sw              ; protect a1
    399     .00000100 .0000B000 .00040000 23200000
    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 lw                   ; restore ra
    415     .80000000 .00000100 03200000
    416     # rd_a0 rs1_sp !4 lw                ; restore a0
    417     .00050000 .00000100 .00004000 03200000
    418     # rd_a1 rs1_sp !8 lw                ; restore a1
    419     .80050000 .00000100 .00008000 03200000
    420     # rd_sp rs1_sp !12 addi             ; deallocate stack
    421     .00010000 .00000100 .0000C000 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 !-16 addi            ; allocate stack
    431     .00010000 .00000100 .000000FF 13000000
    432     # rs1_sp rs2_ra sw                  ; protect ra
    433     .00000100 .00001000 23200000
    434     # rs1_sp rs2_a1 @4 sw               ; protect a1
    435     .00000100 .0000B000 .00020000 23200000
    436     # rs1_sp rs2_a2 @8 sw               ; protect a2
    437     .00000100 .0000C000 .00040000 23200000
    438     # rs1_sp rs2_a3 @12 sw              ; protect a3
    439     .00000100 .0000D000 .00060000 23200000
    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 !12 lw               ; restore a3
    471     .80060000 .00000100 .0000C000 03200000
    472     # rs1_a3 rs2_a0 @8 sw               ; HEAD->TEXT = STRING
    473     .00800600 .0000A000 .00040000 23200000
    474     # rd_ra $copy_string jal            ; Copy the string
    475     .80000000 $copy_string 6F000000
    476 
    477     # rd_ra rs1_sp lw                   ; restore ra
    478     .80000000 .00000100 03200000
    479     # rd_a1 rs1_sp !4 lw                ; restore a1
    480     .80050000 .00000100 .00004000 03200000
    481     # rd_a2 rs1_sp !8 lw                ; restore a2
    482     .00060000 .00000100 .00008000 03200000
    483     # rd_sp rs1_sp !16 addi             ; deallocate stack
    484     .00010000 .00000100 .00000001 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 !-8 addi             ; allocate stack
    494     .00010000 .00000100 .000080FF 13000000
    495     # rs1_sp rs2_a1 sw                  ; protect a1
    496     .00000100 .0000B000 23200000
    497     # rs1_sp rs2_a2 @4 sw               ; protect a2
    498     .00000100 .0000C000 .00020000 23200000
    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 lw                   ; NEXT = HEAD->NEXT
    508     .00060000 .00800500 03200000
    509     # rs1_a1 rs2_a0 sw                  ; HEAD->NEXT = ROOT
    510     .00800500 .0000A000 23200000
    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 lw                   ; restore a1
    520     .80050000 .00000100 03200000
    521     # rd_a2 rs1_sp !4 lw                ; restore a2
    522     .00060000 .00000100 .00004000 03200000
    523     # rd_sp rs1_sp !8 addi              ; deallocate stack
    524     .00010000 .00000100 .00008000 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 !-16 addi            ; allocate stack
    535     .00010000 .00000100 .000000FF 13000000
    536     # rs1_sp rs2_ra sw                  ; protect ra
    537     .00000100 .00001000 23200000
    538     # rs1_sp rs2_a0 @4 sw               ; protect a0
    539     .00000100 .0000A000 .00020000 23200000
    540     # rs1_sp rs2_a1 @8 sw               ; protect a1
    541     .00000100 .0000B000 .00040000 23200000
    542     # rs1_sp rs2_a2 @12 sw              ; protect a2
    543     .00000100 .0000C000 .00060000 23200000
    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 !8 lw                ; I->TEXT
    554     .00050000 .00000600 .00008000 03200000
    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 @4 sw               ; I->TYPE = MACRO
    564     .00000600 .0000A000 .00020000 23200000
    565 
    566     # rd_a0 rs1_a2 lw                   ; I->NEXT
    567     .00050000 .00000600 03200000
    568     # rd_a0 rs1_a0 !8 lw                ; I->NEXT->TEXT
    569     .00050000 .00000500 .00008000 03200000
    570     # rs1_a2 rs2_a0 @8 sw               ; I->TEXT = I->NEXT->TEXT
    571     .00000600 .0000A000 .00040000 23200000
    572 
    573     # rd_a0 rs1_a2 lw                   ; I->NEXT
    574     .00050000 .00000600 03200000
    575     # rd_a0 rs1_a0 lw                   ; I->NEXT->NEXT
    576     .00050000 .00000500 03200000
    577     # rd_a0 rs1_a0 !8 lw                ; I->NEXT->NEXT->TEXT
    578     .00050000 .00000500 .00008000 03200000
    579     # rs1_a2 rs2_a0 @12 sw              ; I->EXPRESSION = I->NEXT->NEXT->TEXT
    580     .00000600 .0000A000 .00060000 23200000
    581 
    582     # rd_a0 rs1_a2 lw                   ; I->NEXT
    583     .00050000 .00000600 03200000
    584     # rd_a0 rs1_a0 lw                   ; I->NEXT->NEXT
    585     .00050000 .00000500 03200000
    586     # rd_a0 rs1_a0 lw                   ; I->NEXT->NEXT->NEXT
    587     .00050000 .00000500 03200000
    588     # rs1_a2 rs2_a0 sw                  ; I->NEXT = I->NEXT->NEXT->NEXT
    589     .00000600 .0000A000 23200000
    590 
    591 :Identify_Macros_Next
    592     # rd_a2 rs1_a2 lw                   ; I = I->NEXT
    593     .00060000 .00000600 03200000
    594     # rs1_a2 @Identify_Macros_Loop bnez ; Check if we are done
    595     .00000600 @Identify_Macros_Loop 63100000
    596 
    597     # rd_ra rs1_sp lw                   ; restore ra
    598     .80000000 .00000100 03200000
    599     # rd_a0 rs1_sp !4 lw                ; restore a0
    600     .00050000 .00000100 .00004000 03200000
    601     # rd_a1 rs1_sp !8 lw                ; restore a1
    602     .80050000 .00000100 .00008000 03200000
    603     # rd_a2 rs1_sp !12 lw               ; restore a2
    604     .00060000 .00000100 .0000C000 03200000
    605     # rd_sp rs1_sp !16 addi             ; deallocate stack
    606     .00010000 .00000100 .00000001 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 !-12 addi            ; allocate stack
    616     .00010000 .00000100 .000040FF 13000000
    617     # rs1_sp rs2_a1 sw                  ; protect a1
    618     .00000100 .0000B000 23200000
    619     # rs1_sp rs2_a2 @4 sw               ; protect a2
    620     .00000100 .0000C000 .00020000 23200000
    621     # rs1_sp rs2_a3 @8 sw              ; protect a3
    622     .00000100 .0000D000 .00040000 23200000
    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 lw                   ; restore a1
    651     .80050000 .00000100 03200000
    652     # rd_a2 rs1_sp !4 lw                ; restore a2
    653     .00060000 .00000100 .00004000 03200000
    654     # rd_a3 rs1_sp !8 lw               ; restore a3
    655     .80060000 .00000100 .00008000 03200000
    656     # rd_sp rs1_sp !12 addi             ; deallocate stack
    657     .00010000 .00000100 .0000C000 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 !-16 addi            ; allocate stack
    668     .00010000 .00000100 .000000FF 13000000
    669     # rs1_sp rs2_ra sw                  ; protect ra
    670     .00000100 .00001000 23200000
    671     # rs1_sp rs2_a0 @4 sw               ; protect a0
    672     .00000100 .0000A000 .00020000 23200000
    673     # rs1_sp rs2_a1 @8 sw               ; protect a1
    674     .00000100 .0000B000 .00040000 23200000
    675     # rs1_sp rs2_a2 @12 sw              ; protect a2
    676     .00000100 .0000C000 .00060000 23200000
    677 
    678 :Line_Macro_Loop
    679     # rd_a1 rs1_a0 !4 lw                ; I->TYPE
    680     .80050000 .00000500 .00004000 03200000
    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 !8 lw                ; I->TEXT
    688     .80050000 .00000500 .00008000 03200000
    689     # rd_a2 rs1_a0 !12 lw               ; I->EXPRESSION
    690     .00060000 .00000500 .0000C000 03200000
    691     # rd_a0 rs1_a0 lw                   ; I->NEXT
    692     .00050000 .00000500 03200000
    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 lw                   ; I->NEXT
    700     .00050000 .00000500 03200000
    701     # rs1_a0 @Line_Macro_Loop bnez      ; Check if we are done
    702     .00000500 @Line_Macro_Loop 63100000
    703 
    704     # rd_ra rs1_sp lw                   ; restore ra
    705     .80000000 .00000100 03200000
    706     # rd_a0 rs1_sp !4 lw                ; restore a0
    707     .00050000 .00000100 .00004000 03200000
    708     # rd_a1 rs1_sp !8 lw                ; restore a1
    709     .80050000 .00000100 .00008000 03200000
    710     # rd_a2 rs1_sp !12 lw               ; restore a2
    711     .00060000 .00000100 .0000C000 03200000
    712     # rd_sp rs1_sp !16 addi             ; deallocate stack
    713     .00010000 .00000100 .00000001 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 !-20 addi            ; allocate stack
    724     .00010000 .00000100 .0000C0FE 13000000
    725     # rs1_sp rs2_ra sw                  ; protect ra
    726     .00000100 .00001000 23200000
    727     # rs1_sp rs2_a0 @4 sw               ; protect a0
    728     .00000100 .0000A000 .00020000 23200000
    729     # rs1_sp rs2_a1 @8 sw               ; protect a1
    730     .00000100 .0000B000 .00040000 23200000
    731     # rs1_sp rs2_a2 @12 sw              ; protect a2
    732     .00000100 .0000C000 .00060000 23200000
    733     # rs1_sp rs2_a3 @16 sw              ; protect a3
    734     .00000100 .0000D000 .00080000 23200000
    735 
    736     # rd_a3 rs1_a0 mv                   ; Set I
    737     .80060000 .00000500 13000000
    738 :Set_Expression_Loop
    739     # rd_a0 rs1_a3 !4 lw                ; I->TYPE
    740     .00050000 .00800600 .00004000 03200000
    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 !8 lw                ; I->TEXT
    747     .00050000 .00800600 .00008000 03200000
    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 @12 sw              ; I->EXPRESSION = EXP
    755     .00800600 .0000C000 .00060000 23200000
    756 
    757 :Set_Expression_Next
    758     # rd_a3 rs1_a3 lw                   ; I = I->NEXT
    759     .80060000 .00800600 03200000
    760     # rs1_a3 @Set_Expression_Loop bnez  ; Check if we are done
    761     .00800600 @Set_Expression_Loop 63100000
    762 
    763     # rd_ra rs1_sp lw                   ; restore ra
    764     .80000000 .00000100 03200000
    765     # rd_a0 rs1_sp !4 lw                ; restore a0
    766     .00050000 .00000100 .00004000 03200000
    767     # rd_a1 rs1_sp !8 lw                ; restore a1
    768     .80050000 .00000100 .00008000 03200000
    769     # rd_a2 rs1_sp !12 lw               ; restore a2
    770     .00060000 .00000100 .0000C000 03200000
    771     # rd_a3 rs1_sp !16 lw               ; restore a3
    772     .80060000 .00000100 .00000001 03200000
    773     # rd_sp rs1_sp !20 addi             ; deallocate stack
    774     .00010000 .00000100 .00004001 13000000
    775     # rs1_ra jalr                       ; return
    776     .00800000 67000000
    777 
    778 
    779 ; Process_String function
    780 ; Receives List in a0
    781 ; Update the list in place; does not modify registers
    782 ; Uses a1 for I->TEXT, a2 for I and RDX for S
    783 :Process_String
    784     # rd_sp rs1_sp !-20 addi            ; allocate stack
    785     .00010000 .00000100 .0000C0FE 13000000
    786     # rs1_sp rs2_ra sw                  ; protect ra
    787     .00000100 .00001000 23200000
    788     # rs1_sp rs2_a0 @4 sw               ; protect a0
    789     .00000100 .0000A000 .00020000 23200000
    790     # rs1_sp rs2_a1 @8 sw               ; protect a1
    791     .00000100 .0000B000 .00040000 23200000
    792     # rs1_sp rs2_a2 @12 sw              ; protect a2
    793     .00000100 .0000C000 .00060000 23200000
    794     # rs1_sp rs2_a3 @16 sw              ; protect a3
    795     .00000100 .0000D000 .00080000 23200000
    796 
    797     # rd_a2 rs1_a0 mv                   ; I = HEAD
    798     .00060000 .00000500 13000000
    799 
    800 :Process_String_loop
    801     # rd_a0 rs1_a2 !4 lw                ; I->TYPE
    802     .00050000 .00000600 .00004000 03200000
    803     # rd_t0 !2 addi                     ; t0 = STRING
    804     .80020000 .00002000 13000000
    805     # rs1_a0 rs2_t0 @Process_String_Next bne ; Skip to next
    806     .00000500 .00005000 @Process_String_Next 63100000
    807 
    808     # rd_a1 rs1_a2 !8 lw                ; I->TEXT
    809     .80050000 .00000600 .00008000 03200000
    810     # rd_a0 rs1_a1 lbu                  ; I->TEXT[0]
    811     .00050000 .00800500 03400000
    812     # rd_t0 !39 addi                    ; t0 = \'
    813     .80020000 .00007002 13000000
    814     # rs1_a0 rs2_t0 @Process_String_Raw bne ; Deal with '"'
    815     .00000500 .00005000 @Process_String_Raw 63100000
    816 
    817     ; Deal with \'
    818     # rd_a1 rs1_a1 !1 addi              ; I->TEXT + 1
    819     .80050000 .00800500 .00001000 13000000
    820     # rs1_a2 rs2_a1 @12 sw              ; I->EXPRESSION = I->TEXT + 1
    821     .00000600 .0000B000 .00060000 23200000
    822     # $Process_String_Next jal          ; Move on to next
    823     $Process_String_Next 6F000000
    824 
    825 :Process_String_Raw
    826     # rd_a0 rs1_a1 mv                   ; I->TEXT
    827     .00050000 .00800500 13000000
    828     # rd_ra $string_length jal          ; Get length of I->TEXT
    829     .80000000 $string_length 6F000000
    830     # rd_a0 rs1_a0 rs2_x2 srli          ; LENGTH = LENGTH >> 2
    831     .00050000 .00000500 .00002000 13500000
    832     # rd_a0 rs1_a0 !1 addi              ; LENGTH = LENGTH + 1
    833     .00050000 .00000500 .00001000 13000000
    834     # rd_a0 rs1_a0 rs2_x3 slli          ; LENGTH = LENGTH << 3
    835     .00050000 .00000500 .00003000 13100000
    836     # rd_ra $malloc jal                 ; Get string
    837     .80000000 $malloc 6F000000
    838     # rd_a3 rs1_a1 mv                   ; S = I->TEXT
    839     .80060000 .00800500 13000000
    840     # rd_a3 rs1_a3 !1 addi              ; S = S + 1
    841     .80060000 .00800600 .00001000 13000000
    842     # rs1_a2 rs2_a0 @12 sw              ; I->EXPRESSION = hexify
    843     .00000600 .0000A000 .00060000 23200000
    844     # rd_a1 rs1_a0 mv                   ; Put hexify buffer in a1
    845     .80050000 .00000500 13000000
    846 
    847 :Process_String_Raw_Loop
    848     # rd_a0 rs1_a3 lbu                  ; Read 1 character
    849     .00050000 .00800600 03400000
    850     # rd_a3 rs1_a3 !1 addi              ; S = S + 1
    851     .80060000 .00800600 .00001000 13000000
    852     # rd_s5 rs1_a0 mv                   ; Protect character
    853     .800A0000 .00000500 13000000
    854     # rd_ra $hex8 jal                   ; write them all
    855     .80000000 $hex8 6F000000
    856     # rd_a0 rs1_s5 mv                   ; Restore character
    857     .00050000 .00800A00 13000000
    858     # rs1_a0 @Process_String_Raw_Loop bnez ; Keep looping
    859     .00000500 @Process_String_Raw_Loop 63100000
    860 
    861 :Process_String_Next
    862     # rd_a2 rs1_a2 lw                   ; I = I->NEXT
    863     .00060000 .00000600 03200000
    864     # rs1_a2 @Process_String_loop bnez  ; Check if we are done
    865     .00000600 @Process_String_loop 63100000
    866 
    867     # rd_ra rs1_sp lw                   ; restore ra
    868     .80000000 .00000100 03200000
    869     # rd_a0 rs1_sp !4 lw                ; restore a0
    870     .00050000 .00000100 .00004000 03200000
    871     # rd_a1 rs1_sp !8 lw                ; restore a1
    872     .80050000 .00000100 .00008000 03200000
    873     # rd_a2 rs1_sp !12 lw               ; restore a2
    874     .00060000 .00000100 .0000C000 03200000
    875     # rd_a3 rs1_sp !16 lw               ; restore a3
    876     .80060000 .00000100 .00000001 03200000
    877     # rd_sp rs1_sp !20 addi             ; deallocate stack
    878     .00010000 .00000100 .00004001 13000000
    879     # rs1_ra jalr                       ; return
    880     .00800000 67000000
    881 
    882 
    883 ; string_length function
    884 ; Receives CHAR* in a0
    885 ; Returns INT in a0
    886 ; Uses a0 for CH, a1 for S and a2 for INDEX
    887 :string_length
    888     # rd_sp rs1_sp !-8 addi            ; allocate stack
    889     .00010000 .00000100 .000080FF 13000000
    890     # rs1_sp rs2_a1 sw                  ; protect a1
    891     .00000100 .0000B000 23200000
    892     # rs1_sp rs2_a2 @4 sw               ; protect a2
    893     .00000100 .0000C000 .00020000 23200000
    894 
    895     # rd_a1 rs1_a0 mv                   ; Set S
    896     .80050000 .00000500 13000000
    897     # rd_a2 mv                          ; INDEX = 0
    898     .00060000 13000000
    899 
    900 :string_length_loop
    901     # rd_t0 rs1_a1 rs2_a2 add           ; S + INDEX
    902     .80020000 .00800500 .0000C000 33000000
    903     # rd_a0 rs1_t0 lbu                  ; S[INDEX]
    904     .00050000 .00800200 03400000
    905     # rs1_a0 @string_length_done beqz   ; Check if we are done
    906     .00000500 @string_length_done 63000000
    907 
    908     # rd_a2 rs1_a2 !1 addi              ; INDEX = INDEX + 1
    909     .00060000 .00000600 .00001000 13000000
    910     # $string_length_loop jal           ; Keep going
    911     $string_length_loop 6F000000
    912 
    913 :string_length_done
    914     # rd_a0 rs1_a2 mv                   ; return INDEX
    915     .00050000 .00000600 13000000
    916     # rd_a1 rs1_sp lw                   ; restore a1
    917     .80050000 .00000100 03200000
    918     # rd_a2 rs1_sp !4 lw                ; restore a2
    919     .00060000 .00000100 .00004000 03200000
    920     # rd_sp rs1_sp !8 addi              ; deallocate stack
    921     .00010000 .00000100 .00008000 13000000
    922     # rs1_ra jalr                       ; return
    923     .00800000 67000000
    924 
    925 
    926 ; Eval_Immediates function
    927 ; Receives List in a0
    928 ; Updates the list in place; does not modify registers
    929 ; Uses a1 for I->TEXT[0], a2 for I->TEXT[1] and a3 for I
    930 :Eval_Immediates
    931     # rd_sp rs1_sp !-20 addi            ; allocate stack
    932     .00010000 .00000100 .0000C0FE 13000000
    933     # rs1_sp rs2_ra sw                  ; protect ra
    934     .00000100 .00001000 23200000
    935     # rs1_sp rs2_a0 @4 sw               ; protect a0
    936     .00000100 .0000A000 .00020000 23200000
    937     # rs1_sp rs2_a1 @8 sw               ; protect a1
    938     .00000100 .0000B000 .00040000 23200000
    939     # rs1_sp rs2_a2 @12 sw              ; protect a2
    940     .00000100 .0000C000 .00060000 23200000
    941     # rs1_sp rs2_a3 @16 sw              ; protect a3
    942     .00000100 .0000D000 .00080000 23200000
    943 
    944     # rd_a3 rs1_a0 mv                   ; I = HEAD
    945     .80060000 .00000500 13000000
    946 
    947 :Eval_Immediates_Loop
    948     ; Check for MACRO
    949     # rd_a0 rs1_a3 !4 lw                ; I->TYPE
    950     .00050000 .00800600 .00004000 03200000
    951     # rd_t0 !1 addi                     ; t0 = MACRO
    952     .80020000 .00001000 13000000
    953     # rs1_a0 rs2_t0 @Eval_Immediates_Next beq ; Skip to next if I->TYPE == MACRO
    954     .00000500 .00005000 @Eval_Immediates_Next 63000000
    955 
    956     ; Check for NULL EXPRESSION
    957     # rd_a0 rs1_a3 !12 lw               ; I->EXPRESSION
    958     .00050000 .00800600 .0000C000 03200000
    959     # rs1_a0 @Eval_Immediates_Next bnez ; Skip to next if NULL == I->EXPRESSION
    960     .00000500 @Eval_Immediates_Next 63100000
    961 
    962     ; Check if number
    963     # rd_a0 rs1_a3 !8 lw                ; I->TEXT
    964     .00050000 .00800600 .00008000 03200000
    965     # rd_a1 rs1_a0 lbu                  ; I->TEXT[0]
    966     .80050000 .00000500 03400000
    967     # rd_a0 rs1_a0 !1 addi              ; I->TEXT + 1
    968     .00050000 .00000500 .00001000 13000000
    969     # rd_a2 rs1_a0 lbu                  ; I->TEXT[1]
    970     .00060000 .00000500 03400000
    971     # rd_ra $numerate_string jal        ; Convert string to INT
    972     .80000000 $numerate_string 6F000000
    973     # rs1_a0 @Eval_Immediates_value bnez ; Has a value IF 0 != numerate_string(I->TEXT + 1)
    974     .00000500 @Eval_Immediates_value 63100000
    975 
    976     ; Last chance for Immediate
    977     # rd_t0 !48 addi                    ; If '0' = I->TEXT[1]
    978     .80020000 .00000003 13000000
    979     # rs1_a2 rs2_t0 @Eval_Immediates_Next bne ; Skip to next
    980     .00000600 .00005000 @Eval_Immediates_Next 63100000
    981 
    982 :Eval_Immediates_value
    983     # rd_ra $express_number jal         ; Convert value to hex string
    984     .80000000 $express_number 6F000000
    985     # rs1_a3 rs2_a0 @12 sw              ; I->EXPRESSION = express_number(value, I-TEXT[0])
    986     .00800600 .0000A000 .00060000 23200000
    987 
    988 :Eval_Immediates_Next
    989     # rd_a3 rs1_a3 lw                   ; I = I->NEXT
    990     .80060000 .00800600 03200000
    991     # rs1_a3 @Eval_Immediates_Loop bnez ; Check if we are done
    992     .00800600 @Eval_Immediates_Loop 63100000
    993 
    994     # rd_ra rs1_sp lw                   ; restore ra
    995     .80000000 .00000100 03200000
    996     # rd_a0 rs1_sp !4 lw                ; restore a0
    997     .00050000 .00000100 .00004000 03200000
    998     # rd_a1 rs1_sp !8 lw                ; restore a1
    999     .80050000 .00000100 .00008000 03200000
   1000     # rd_a2 rs1_sp !12 lw               ; restore a2
   1001     .00060000 .00000100 .0000C000 03200000
   1002     # rd_a3 rs1_sp !16 lw               ; restore a3
   1003     .80060000 .00000100 .00000001 03200000
   1004     # rd_sp rs1_sp !20 addi             ; deallocate stack
   1005     .00010000 .00000100 .00004001 13000000
   1006     # rs1_ra jalr                       ; return
   1007     .00800000 67000000
   1008 
   1009 
   1010 ; numerate_string function
   1011 ; Receives CHAR* in a0
   1012 ; Returns value of CHAR* in a0
   1013 ; Uses a0 for VALUE, a1 for S, a2 for CH and a3 for NEGATIVE?
   1014 :numerate_string
   1015     # rd_sp rs1_sp !-12 addi            ; allocate stack
   1016     .00010000 .00000100 .000040FF 13000000
   1017     # rs1_sp rs2_a1 sw                  ; protect a1
   1018     .00000100 .0000B000 23200000
   1019     # rs1_sp rs2_a2 @4 sw               ; protect a2
   1020     .00000100 .0000C000 .00020000 23200000
   1021     # rs1_sp rs2_a3 @8 sw               ; protect a3
   1022     .00000100 .0000D000 .00040000 23200000
   1023 
   1024     # rd_a1 rs1_a0 mv                   ; put S in correct place
   1025     .80050000 .00000500 13000000
   1026     # rd_a0 mv                          ; Initialize to Zero
   1027     .00050000 13000000
   1028 :numerate_string_loop
   1029     # rd_t0 rs1_a1 !1 addi              ; S + 1
   1030     .80020000 .00800500 .00001000 13000000
   1031     # rd_a2 rs1_t0 lbu                  ; S[1]
   1032     .00060000 .00800200 03400000
   1033     # rd_t0 !120 addi                   ; 'x'
   1034     .80020000 .00008007 13000000
   1035     # rs1_a2 rs2_t0 @numerate_hex beq   ; Deal with hex_input
   1036     .00000600 .00005000 @numerate_hex 63000000
   1037 
   1038     ; Assume decimal input
   1039     # rd_a3 mv                          ; Assume no negation
   1040     .80060000 13000000
   1041     # rd_a2 rs1_a1 lbu                  ; S[0]
   1042     .00060000 .00800500 03400000
   1043     # rd_t0 !45 addi                    ; '-'
   1044     .80020000 .0000D002 13000000
   1045     # rs1_a2 rs2_t0 @numerate_decimal bne ; Skip negation
   1046     .00000600 .00005000 @numerate_decimal 63100000
   1047 
   1048     # rd_a3 !1 addi                     ; Set FLAG
   1049     .80060000 .00001000 13000000
   1050     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1051     .80050000 .00800500 .00001000 13000000
   1052 
   1053 :numerate_decimal
   1054     # rd_a2 rs1_a1 lbu                  ; S[i]
   1055     .00060000 .00800500 03400000
   1056     # rs1_a2 @numerate_decimal_done beqz ; We are done if NULL == S[i]
   1057     .00000600 @numerate_decimal_done 63000000
   1058 
   1059     ; a0 = a0 * 10 = (a0 << 3) + (a0 << 1)
   1060     # rd_t0 rs1_a0 rs2_x3 slli          ; a0 * 8
   1061     .80020000 .00000500 .00003000 13100000
   1062     # rd_t1 rs1_a0 rs2_x1 slli          ; a0 * 2
   1063     .00030000 .00000500 .00001000 13100000
   1064     # rd_a0 rs1_t0 rs2_t1 add           ; VALUE = VALUE * 10
   1065     .00050000 .00800200 .00006000 33000000
   1066     # rd_a2 rs1_a2 !-48 addi            ; CH = CH - '0'
   1067     .00060000 .00000600 .000000FD 13000000
   1068     # rd_t0 !9 addi                     ; t0 = 9
   1069     .80020000 .00009000 13000000
   1070     # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for illegal CH > 9
   1071     .00800200 .0000C000 @numerate_string_fail 63400000
   1072     # rs1_a2 @numerate_string_fail bltz ; Check for illegal CH < 0
   1073     .00000600 @numerate_string_fail 63400000
   1074     # rd_a0 rs1_a0 rs2_a2 add           ; VALUE = VALUE + CH
   1075     .00050000 .00000500 .0000C000 33000000
   1076     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1077     .80050000 .00800500 .00001000 13000000
   1078     # $numerate_decimal jal
   1079     $numerate_decimal 6F000000
   1080 
   1081 :numerate_decimal_done
   1082     # rd_t0 !1 addi                     ; Check for negative FLAG
   1083     .80020000 .00001000 13000000
   1084     # rs1_a3 rs2_t0 @numerate_string_done bne ; Nope
   1085     .00800600 .00005000 @numerate_string_done 63100000
   1086 
   1087     # rd_a0 rs2_a0 sub                  ; VALUE = -VALUE
   1088     .00050000 .0000A000 33000040
   1089     # $numerate_string_done jal         ; Done
   1090     $numerate_string_done 6F000000
   1091 
   1092 :numerate_hex
   1093     # rd_a1 rs1_a1 !2 addi              ; S = S + 2
   1094     .80050000 .00800500 .00002000 13000000
   1095 :numerate_hex_loop
   1096     # rd_a2 rs1_a1 lbu                  ; S[i]
   1097     .00060000 .00800500 03400000
   1098     # rs1_a2 @numerate_string_done beqz ; We are done if NULL == S[i]
   1099     .00000600 @numerate_string_done 63000000
   1100 
   1101     # rd_a0 rs1_a0 rs2_x4 slli          ; VALUE = VALUE << 4
   1102     .00050000 .00000500 .00004000 13100000
   1103     # rd_a2 rs1_a2 !-48 addi            ; CH = CH - '0'
   1104     .00060000 .00000600 .000000FD 13000000
   1105     # rd_t0 !10 addi                    ; t0 = 10
   1106     .80020000 .0000A000 13000000
   1107     # rs1_a2 rs2_t0 @numerate_hex_digit blt ; Check if we are dealing with number or letter
   1108     .00000600 .00005000 @numerate_hex_digit 63400000
   1109     # rd_a2 rs1_a2 !-7 addi             ; Push A-F into range
   1110     .00060000 .00000600 .000090FF 13000000
   1111 
   1112 :numerate_hex_digit
   1113     # rd_t0 !15 addi                    ; t0 = 15
   1114     .80020000 .0000F000 13000000
   1115     # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for CH > 'F'
   1116     .00800200 .0000C000 @numerate_string_fail 63400000
   1117     # rs1_a2 @numerate_string_fail bltz ; Check for CH < 0
   1118     .00000600 @numerate_string_fail 63400000
   1119     # rd_a0 rs1_a0 rs2_a2 add           ; VALUE = VALUE + CH
   1120     .00050000 .00000500 .0000C000 33000000
   1121     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1122     .80050000 .00800500 .00001000 13000000
   1123     # $numerate_hex_loop jal            ; Keep looping
   1124     $numerate_hex_loop 6F000000
   1125 
   1126 :numerate_string_fail
   1127     # rd_a0 mv                          ; return ZERO
   1128     .00050000 13000000
   1129 
   1130 :numerate_string_done
   1131     # rd_a1 rs1_sp lw                   ; restore a1
   1132     .80050000 .00000100 03200000
   1133     # rd_a2 rs1_sp !4 lw                ; restore a2
   1134     .00060000 .00000100 .00004000 03200000
   1135     # rd_a3 rs1_sp !8 lw                ; restore a3
   1136     .80060000 .00000100 .00008000 03200000
   1137     # rd_sp rs1_sp !12 addi             ; deallocate stack
   1138     .00010000 .00000100 .0000C000 13000000
   1139     # rs1_ra jalr                       ; return
   1140     .00800000 67000000
   1141 
   1142 
   1143 ; express_number function
   1144 ; Receives INT in a0 and CHAR in a1
   1145 ; Allocates a string and expresses the value in appropriate RISC-V encoding
   1146 ; Returns string in a0
   1147 ; Uses a0 for VALUE, a1 for S and a2 for CH
   1148 :express_number
   1149     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1150     .00010000 .00000100 .000000FF 13000000
   1151     # rs1_sp rs2_ra sw                  ; protect ra
   1152     .00000100 .00001000 23200000
   1153     # rs1_sp rs2_a1 @4 sw               ; protect a1
   1154     .00000100 .0000B000 .00020000 23200000
   1155     # rs1_sp rs2_a2 @8 sw               ; protect a2
   1156     .00000100 .0000C000 .00040000 23200000
   1157     # rs1_sp rs2_a3 @12 sw              ; protect a3
   1158     .00000100 .0000D000 .00060000 23200000
   1159 
   1160     # rd_a2 rs1_a1 mv                   ; Put CH in right place
   1161     .00060000 .00800500 13000000
   1162     # rd_s5 rs1_a0 mv                   ; Protect VALUE
   1163     .800A0000 .00000500 13000000
   1164 
   1165     # rd_a0 !10 addi                    ; We need 10 bytes
   1166     .00050000 .0000A000 13000000
   1167     # rd_ra $malloc jal                 ; Get S pointer
   1168     .80000000 $malloc 6F000000
   1169     # rd_a1 rs1_a0 mv                   ; Put S in place
   1170     .80050000 .00000500 13000000
   1171     # rd_a0 rs1_s5 mv                   ; Restore VALUE
   1172     .00050000 .00800A00 13000000
   1173 
   1174     ; Check for %
   1175     # rd_t0 !0x25 addi
   1176     .80020000 .00005002 13000000
   1177     # rs1_a2 rs2_t0 @express_number_const beq
   1178     .00000600 .00005000 @express_number_const 63000000
   1179 
   1180     # rd_s5 rs1_a1 mv                   ; Protect S
   1181     .800A0000 .00800500 13000000
   1182     # rd_t0 !0x2E addi                  ; t0 = '.'
   1183     .80020000 .0000E002 13000000
   1184     # rs1_a1 rs2_t0 sw                  ; S[0] = '.'
   1185     .00800500 .00005000 23200000
   1186     # rd_a1 rs1_a1 !1 addi              ; Next byte
   1187     .80050000 .00800500 .00001000 13000000
   1188 
   1189     ; Check for !
   1190     # rd_t0 !0x21 addi
   1191     .80020000 .00001002 13000000
   1192     # rs1_a2 rs2_t0 @express_number_I beq
   1193     .00000600 .00005000 @express_number_I 63000000
   1194 
   1195     ; Check for @
   1196     # rd_t0 !0x40 addi
   1197     .80020000 .00000004 13000000
   1198     # rs1_a2 rs2_t0 @express_number_S beq
   1199     .00000600 .00005000 @express_number_S 63000000
   1200 
   1201     ; Check for ~
   1202     # rd_t0 !0x7E addi
   1203     .80020000 .0000E007 13000000
   1204     # rs1_a2 rs2_t0 @express_number_U beq
   1205     .00000600 .00005000 @express_number_U 63000000
   1206 
   1207     # $Fail jal                         ; Error
   1208     $Fail 6F000000
   1209 
   1210 :express_number_const
   1211     ; provides an option for 32-bit immediate constants
   1212 
   1213     # rd_t0 !2 addi
   1214     .80020000 .00002000 13000000
   1215     # rd_t0 rs1_t0 rs2_x31 slli
   1216     .80020000 .00800200 .0000F001 13100000
   1217     # rd_t0 rs1_t0 !-1 addi             ; t0 = 0xffffffff
   1218     .80020000 .00800200 .0000F0FF 13000000
   1219     # rd_a0 rs1_a0 rs2_t0 and           ; immediate = value & 0xffffffff
   1220     .00050000 .00000500 .00005000 33700000
   1221 
   1222     # rd_s5 rs1_a1 mv                   ; Protect S
   1223     .800A0000 .00800500 13000000
   1224     # rd_ra $hex32l jal                 ; Store 32-bits
   1225     .80000000 $hex32l 6F000000
   1226     # $express_number_done jal          ; done
   1227     $express_number_done 6F000000
   1228 
   1229 :express_number_I
   1230     ; Corresponds to RISC-V S format
   1231     ; (value & 0xfff) << 20
   1232     # rd_t0 !0xFFF addi
   1233     .80020000 .0000F0FF 13000000
   1234     # rd_a0 rs1_a0 rs2_t0 and           ; value & 0xfff
   1235     .00050000 .00000500 .00005000 33700000
   1236     # rd_a0 rs1_a0 rs2_x20 slli         ; (value & 0xfff) << 20
   1237     .00050000 .00000500 .00004001 13100000
   1238     # rd_ra $hex32l jal                 ; Store 32-bits
   1239     .80000000 $hex32l 6F000000
   1240     # $express_number_done jal          ; done
   1241     $express_number_done 6F000000
   1242 
   1243 :express_number_S
   1244     ; Corresponds to RISC-V S format
   1245     ; ((value & 0x1f) << 7) | ((value & 0xfe0) << (31 - 11))
   1246     # rd_t0 !0x1F addi
   1247     .80020000 .0000F001 13000000
   1248     # rd_t1 rs1_a0 rs2_t0 and           ; value & 0x1f
   1249     .00030000 .00000500 .00005000 33700000
   1250     # rd_t1 rs1_t1 rs2_x7 slli          ; (value & 0x1f) << 7
   1251     .00030000 .00000300 .00007000 13100000
   1252     # rd_t0 !0xFE0 addi
   1253     .80020000 .000000FE 13000000
   1254     # rd_t0 rs1_a0 rs2_t0 and           ; value & 0xfe0
   1255     .80020000 .00000500 .00005000 33700000
   1256     # rd_t0 rs1_t0 rs2_x20 slli         ; (value & 0xfe0) << (31 - 11)
   1257     .80020000 .00800200 .00004001 13100000
   1258     # rd_a0 rs1_t0 rs2_t1 or            ; Combine two parts
   1259     .00050000 .00800200 .00006000 33600000
   1260     # rd_ra $hex32l jal                 ; Store 32-bits
   1261     .80000000 $hex32l 6F000000
   1262     # $express_number_done jal          ; done
   1263     $express_number_done 6F000000
   1264 
   1265 :express_number_U
   1266     ; Corresponds to RISC-V U format
   1267     ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension
   1268 
   1269     # rd_t0 ~0x800 lui                  ; load higher bits
   1270     .80020000 .00100000 37000000
   1271     # rd_t0 rs1_t0 !0x800 addi
   1272     .80020000 .00800200 .00000080 13000000
   1273     # rd_t1 ~0xFFF lui                  ; load higher bits
   1274     .00030000 .00100000 37000000
   1275     # rd_t1 rs1_t1 !0xFFF addi
   1276     .00030000 .00000300 .0000F0FF 13000000
   1277     ; We are outside 31-bit that ~ can normally load
   1278     # rd_t2 ~0x100000 lui               ; load 0xfffff000
   1279     .80030000 .00001000 37000000
   1280     # rd_t2 rs1_t2 !-1 addi             ; load 0xfffff000
   1281     .80030000 .00800300 .0000F0FF 13000000
   1282     # rd_t2 rs1_t2 rs2_x12 slli         ; load 0xfffff000
   1283     .80030000 .00800300 .0000C000 13100000
   1284     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xfff
   1285     .00030000 .00000500 .00006000 33700000
   1286     # rd_a0 rs1_a0 rs2_t2 and           ; value & 0xfffff000
   1287     .00050000 .00000500 .00007000 33700000
   1288     # rs1_t1 rs2_t0 @express_number_U_small blt
   1289     .00000300 .00005000 @express_number_U_small 63400000
   1290 
   1291     ; Deal with sign extension: add 0x1000
   1292     # rd_t0 ~0x1000 lui
   1293     .80020000 .00100000 37000000
   1294     # rd_a0 rs1_t0 rs2_a0 add           ; (value & 0xfffff000) + 0x1000
   1295     .00050000 .00800200 .0000A000 33000000
   1296 :express_number_U_small
   1297     # rd_ra $hex32l jal                 ; Store 32-bits
   1298     .80000000 $hex32l 6F000000
   1299     # $express_number_done jal          ; done
   1300     $express_number_done 6F000000
   1301 
   1302 :express_number_done
   1303     # rd_a0 rs1_s5 mv                   ; Restore S
   1304     .00050000 .00800A00 13000000
   1305     # rd_ra rs1_sp lw                   ; restore ra
   1306     .80000000 .00000100 03200000
   1307     # rd_a1 rs1_sp !4 lw                ; restore a1
   1308     .80050000 .00000100 .00004000 03200000
   1309     # rd_a2 rs1_sp !8 lw                ; restore a2
   1310     .00060000 .00000100 .00008000 03200000
   1311     # rd_a3 rs1_sp !12 lw               ; restore a3
   1312     .80060000 .00000100 .0000C000 03200000
   1313     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1314     .00010000 .00000100 .00000001 13000000
   1315     # rs1_ra jalr                       ; return
   1316     .00800000 67000000
   1317 
   1318 
   1319 ; HEX to ascii routine
   1320 ; Receives INT in a0 and CHAR* in a1
   1321 ; Stores ascii of INT in CHAR*
   1322 ; Returns only modifying a0
   1323 :hex32l
   1324     # rd_sp rs1_sp !-8 addi            ; allocate stack
   1325     .00010000 .00000100 .000080FF 13000000
   1326     # rs1_sp rs2_ra sw                  ; Protect ra
   1327     .00000100 .00001000 23200000
   1328     # rs1_sp rs2_a0 @4 sw               ; Protect top 16 bits
   1329     .00000100 .0000A000 .00020000 23200000
   1330     # rd_ra $hex16l jal                 ; Store it
   1331     .80000000 $hex16l 6F000000
   1332     # rd_a0 rs1_sp !4 lw                ; do high 16-bits
   1333     .00050000 .00000100 .00004000 03200000
   1334     # rd_a0 rs1_a0 rs2_x16 srli         ; do bottom 16 bits
   1335     .00050000 .00000500 .00000001 13500000
   1336     # rd_ra $hex16l jal                 ; Store it
   1337     .80000000 $hex16l 6F000000
   1338     # rd_ra rs1_sp lw                   ; restore ra
   1339     .80000000 .00000100 03200000
   1340     # rd_sp rs1_sp !8 addi              ; deallocate stack
   1341     .00010000 .00000100 .00008000 13000000
   1342     # rs1_ra jalr                       ; return
   1343     .00800000 67000000
   1344 
   1345 :hex16l
   1346     # rd_sp rs1_sp !-8 addi             ; allocate stack
   1347     .00010000 .00000100 .000080FF 13000000
   1348     # rs1_sp rs2_ra sw                  ; Protect ra
   1349     .00000100 .00001000 23200000
   1350     # rs1_sp rs2_a0 @4 sw               ; Protect top byte
   1351     .00000100 .0000A000 .00020000 23200000
   1352     # rd_ra $hex8 jal                   ; Store it
   1353     .80000000 $hex8 6F000000
   1354     # rd_a0 rs1_sp !4 lw                ; do high byte
   1355     .00050000 .00000100 .00004000 03200000
   1356     # rd_a0 rs1_a0 rs2_x8 srli          ; do bottom byte
   1357     .00050000 .00000500 .00008000 13500000
   1358     # rd_ra $hex8 jal                   ; Store it
   1359     .80000000 $hex8 6F000000
   1360     # rd_ra rs1_sp lw                   ; restore ra
   1361     .80000000 .00000100 03200000
   1362     # rd_sp rs1_sp !8 addi              ; deallocate stack
   1363     .00010000 .00000100 .00008000 13000000
   1364     # rs1_ra jalr                       ; return
   1365     .00800000 67000000
   1366 
   1367 :hex8
   1368     # rd_sp rs1_sp !-8 addi             ; allocate stack
   1369     .00010000 .00000100 .000080FF 13000000
   1370     # rs1_sp rs2_ra sw                  ; Protect ra
   1371     .00000100 .00001000 23200000
   1372     # rs1_sp rs2_a0 @4 sw               ; Protect bottom nibble
   1373     .00000100 .0000A000 .00020000 23200000
   1374     # rd_a0 rs1_a0 rs2_x4 srli          ; do high nibble first
   1375     .00050000 .00000500 .00004000 13500000
   1376     # rd_ra $hex4 jal                   ; Store it
   1377     .80000000 $hex4 6F000000
   1378     # rd_a0 rs1_sp !4 lw                ; do low nibble
   1379     .00050000 .00000100 .00004000 03200000
   1380     # rd_ra $hex4 jal                   ; Store it
   1381     .80000000 $hex4 6F000000
   1382     # rd_ra rs1_sp lw                   ; restore ra
   1383     .80000000 .00000100 03200000
   1384     # rd_sp rs1_sp !8 addi              ; deallocate stack
   1385     .00010000 .00000100 .00008000 13000000
   1386     # rs1_ra jalr                       ; return
   1387     .00800000 67000000
   1388 
   1389 :hex4
   1390     # rd_t0 !0xF addi
   1391     .80020000 .0000F000 13000000
   1392     # rd_a0 rs1_a0 rs2_t0 and           ; isolate nibble
   1393     .00050000 .00000500 .00005000 33700000
   1394     # rd_a0 rs1_a0 !0x30 addi           ; convert to ascii
   1395     .00050000 .00000500 .00000003 13000000
   1396     # rd_t0 !0x39 addi                  ; t0 = '9'
   1397     .80020000 .00009003 13000000
   1398     # rs1_t0 rs2_a0 @hex1 bge           ; check if valid digit
   1399     .00800200 .0000A000 @hex1 63500000
   1400     # rd_a0 rs1_a0 !7 addi              ; use alpha range
   1401     .00050000 .00000500 .00007000 13000000
   1402 :hex1
   1403     # rs1_a1 rs2_a0 sb                  ; store result
   1404     .00800500 .0000A000 23000000
   1405     # rd_a1 rs1_a1 !1 addi              ; next position
   1406     .80050000 .00800500 .00001000 13000000
   1407     # rs1_ra jalr                       ; return
   1408     .00800000 67000000
   1409 
   1410 
   1411 ; Preserve_Other function
   1412 ; Receives list in a0
   1413 ; Update the list in place; does not modify registers
   1414 ; Uses a0 for I, a1 for I->TEXT
   1415 :Preserve_Other
   1416     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1417     .00010000 .00000100 .000000FF 13000000
   1418     # rs1_sp rs2_a1 sw                  ; protect a1
   1419     .00000100 .0000B000 23200000
   1420     # rs1_sp rs2_a2 @4 sw               ; protect a2
   1421     .00000100 .0000C000 .00020000 23200000
   1422     # rs1_sp rs2_a3 @8 sw               ; protect a3
   1423     .00000100 .0000D000 .00040000 23200000
   1424     # rs1_sp rs2_a4 @21 sw              ; protect a4
   1425     .00000100 .0000E000 .00060000 23200000
   1426 :Preserve_Other_Loop
   1427     # rd_a1 rs1_a0 !12 lw               ; I->EXPRESSION
   1428     .80050000 .00000500 .0000C000 03200000
   1429     # rs1_a1 @Preserve_Other_Next bnez  ; IF NULL == I->EXPRESSION then preserve
   1430     .00800500 @Preserve_Other_Next 63100000
   1431 
   1432     # rd_a1 rs1_a0 !8 lw                ; I->TEXT
   1433     .80050000 .00000500 .00008000 03200000
   1434     # rs1_a0 rs2_a1 @12 sw              ; I->EXPRESSION = I->TEXT
   1435     .00000500 .0000B000 .00060000 23200000
   1436 
   1437 :Preserve_Other_Next
   1438     # rd_a0 rs1_a0 lw                   ; I = I->NEXT
   1439     .00050000 .00000500 03200000
   1440     # rs1_a0 @Preserve_Other_Loop bnez  ; Keep looping until I == NULL
   1441     .00000500 @Preserve_Other_Loop 63100000
   1442 
   1443     # rd_a1 rs1_sp lw                   ; restore a1
   1444     .80050000 .00000100 03200000
   1445     # rd_a2 rs1_sp !4 lw                ; restore a2
   1446     .00060000 .00000100 .00004000 03200000
   1447     # rd_a3 rs1_sp !8 lw                ; restore a3
   1448     .80060000 .00000100 .00008000 03200000
   1449     # rd_a4 rs1_sp !12 lw               ; restore a4
   1450     .00070000 .00000100 .0000C000 03200000
   1451     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1452     .00010000 .00000100 .00000001 13000000
   1453     # rs1_ra jalr                       ; return
   1454     .00800000 67000000
   1455 
   1456 
   1457 ; Print_Hex function
   1458 ; Receives list in a0
   1459 ; walks the list and prints the I->EXPRESSION for all nodes followed by newline
   1460 ; Uses a1 for I
   1461 :Print_Hex
   1462     # rd_sp rs1_sp !-12 addi            ; allocate stack
   1463     .00010000 .00000100 .000040FF 13000000
   1464     # rs1_sp rs2_ra sw                  ; protect ra
   1465     .00000100 .00001000 23200000
   1466     # rs1_sp rs2_a1 @4 sw               ; protect a1
   1467     .00000100 .0000B000 .00020000 23200000
   1468     # rs1_sp rs2_a2 @8 sw               ; protect a2
   1469     .00000100 .0000C000 .00040000 23200000
   1470 
   1471     # rd_a1 rs1_s4 mv                   ; I = HEAD
   1472     .80050000 .00000A00 13000000
   1473 
   1474 :Print_Hex_Loop
   1475     # rd_a0 rs1_a1 !4 lw                ; I->TYPE
   1476     .00050000 .00800500 .00004000 03200000
   1477     # rd_t0 !1 addi                     ; t0 = MACRO
   1478     .80020000 .00001000 13000000
   1479     # rs1_a0 rs2_t0 @Print_Hex_Next beq ; Skip if MACRO = I->TYPE
   1480     .00000500 .00005000 @Print_Hex_Next 63000000
   1481 
   1482     # rd_a0 rs1_a1 !12 lw               ; Using EXPRESSION
   1483     .00050000 .00800500 .0000C000 03200000
   1484     # rd_ra $File_Print jal             ; Print it
   1485     .80000000 $File_Print 6F000000
   1486     # rd_a0 !10 addi                    ; \n
   1487     .00050000 .0000A000 13000000
   1488     # rd_ra $fputc jal                  ; Print newline
   1489     .80000000 $fputc 6F000000
   1490 
   1491 :Print_Hex_Next
   1492     # rd_a1 rs1_a1 lw                   ; Iterate to next Token
   1493     .80050000 .00800500 03200000
   1494     # rs1_a1 @Print_Hex_Loop bnez       ; Stop if NULL, otherwise keep looping
   1495     .00800500 @Print_Hex_Loop 63100000
   1496 
   1497     # rd_ra rs1_sp lw                   ; restore ra
   1498     .80000000 .00000100 03200000
   1499     # rd_a1 rs1_sp !4 lw                ; restore a1
   1500     .80050000 .00000100 .00004000 03200000
   1501     # rd_a2 rs1_sp !8 lw                ; restore a2
   1502     .00060000 .00000100 .00008000 03200000
   1503     # rd_sp rs1_sp !12 addi             ; deallocate stack
   1504     .00010000 .00000100 .0000C000 13000000
   1505     # ret
   1506     67800000
   1507 
   1508 
   1509 ; File_Print function
   1510 ; Receives CHAR* in a0
   1511 ; calls fputc for every non-null char
   1512 :File_Print
   1513     # rd_sp rs1_sp !-12 addi            ; allocate stack
   1514     .00010000 .00000100 .000040FF 13000000
   1515     # rs1_sp rs2_ra sw                  ; protect ra
   1516     .00000100 .00001000 23200000
   1517     # rs1_sp rs2_a1 @4 sw               ; protect a1
   1518     .00000100 .0000B000 .00020000 23200000
   1519     # rs1_sp rs2_a2 @8 sw               ; protect a2
   1520     .00000100 .0000C000 .00040000 23200000
   1521     # rd_a1 rs1_a0 mv                   ; protect a0
   1522     .80050000 .00000500 13000000
   1523 
   1524     # rs1_a0 @File_Print_Done beqz      ; Protect against nulls
   1525     .00000500 @File_Print_Done 63000000
   1526 
   1527 :File_Print_Loop
   1528     # rd_a0 rs1_a1 lbu                  ; Read byte
   1529     .00050000 .00800500 03400000
   1530     # rs1_a0 @File_Print_Done beqz      ; Stop at NULL
   1531     .00000500 @File_Print_Done 63000000
   1532 
   1533     # rd_ra $fputc jal                  ; print it
   1534     .80000000 $fputc 6F000000
   1535     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
   1536     .80050000 .00800500 .00001000 13000000
   1537     # $File_Print_Loop jal              ; Keep printing
   1538     $File_Print_Loop 6F000000
   1539 
   1540 :File_Print_Done
   1541     # rd_ra rs1_sp lw                   ; restore ra
   1542     .80000000 .00000100 03200000
   1543     # rd_a1 rs1_sp !4 lw                ; restore a1
   1544     .80050000 .00000100 .00004000 03200000
   1545     # rd_a2 rs1_sp !8 lw                ; restore a2
   1546     .00060000 .00000100 .00008000 03200000
   1547     # rd_sp rs1_sp !12 addi             ; deallocate stack
   1548     .00010000 .00000100 .0000C000 13000000
   1549     # rs1_ra jalr                       ; return
   1550     .00800000 67000000
   1551 
   1552 
   1553 ; fgetc function
   1554 ; Loads FILE* from s2
   1555 ; Returns -4 (EOF) or char in a0
   1556 :fgetc
   1557     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1558     .00010000 .00000100 .000000FF 13000000
   1559     # rs1_sp rs2_ra @4 sw               ; protect ra
   1560     .00000100 .00001000 .00020000 23200000
   1561     # rs1_sp rs2_a1 @8 sw               ; protect a1
   1562     .00000100 .0000B000 .00040000 23200000
   1563     # rs1_sp rs2_a2 @12 sw              ; protect a2
   1564     .00000100 .0000C000 .00060000 23200000
   1565 
   1566     # rd_a7 !63 addi                    ; sys_read
   1567     .80080000 .0000F003 13000000
   1568     # rd_a1 rs1_sp mv                   ; Get stack address for buffer
   1569     .80050000 .00000100 13000000
   1570     # rd_a0 rs1_s2 mv                   ; read from input file
   1571     .00050000 .00000900 13000000
   1572     # rd_a2 !1 addi                     ; read 1 character
   1573     .00060000 .00001000 13000000
   1574     # ecall                             ; syscall
   1575     73000000
   1576 
   1577     # rs1_a0 @fgetc_done bnez           ; Check if nothing was read
   1578     .00000500 @fgetc_done 63100000
   1579     # rd_a2 !-4 addi                    ; Use -4 as EOF
   1580     .00060000 .0000C0FF 13000000
   1581     # rs1_a1 rs2_a2 sb                  ; Store EOF in *a1
   1582     .00800500 .0000C000 23000000
   1583 
   1584 :fgetc_done
   1585     # rd_a0 rs1_a1 lb                   ; return char in a0
   1586     .00050000 .00800500 03000000
   1587     # rd_ra rs1_sp !4 lw                ; restore ra
   1588     .80000000 .00000100 .00004000 03200000
   1589     # rd_a1 rs1_sp !8 lw               ; restore a1
   1590     .80050000 .00000100 .00008000 03200000
   1591     # rd_a2 rs1_sp !12 lw               ; restore a2
   1592     .00060000 .00000100 .0000C000 03200000
   1593     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1594     .00010000 .00000100 .00000001 13000000
   1595     # rs1_ra jalr                       ; return
   1596     .00800000 67000000
   1597 
   1598 
   1599 ; Malloc isn't actually required if the program being built fits in the initial memory
   1600 ; However, it doesn't take much to add it.
   1601 ; Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes
   1602 :malloc
   1603     # rd_sp rs1_sp !-8 addi             ; allocate stack
   1604     .00010000 .00000100 .000080FF 13000000
   1605     # rs1_sp rs2_ra sw                  ; protect ra
   1606     .00000100 .00001000 23200000
   1607     # rs1_sp rs2_a1 @4 sw               ; protect a1
   1608     .00000100 .0000B000 .00020000 23200000
   1609 
   1610     # rd_a1 rs1_s1 mv                   ; Store the current pointer
   1611     .80050000 .00800400 13000000
   1612     # rd_a0 rs1_a0 rs2_s1 add           ; Request the number of desired bytes
   1613     .00050000 .00000500 .00009000 33000000
   1614     # rd_a7 !214 addi                   ; sys_brk
   1615     .80080000 .0000600D 13000000
   1616     # ecall                             ; syscall
   1617     73000000
   1618     # rd_s1 rs1_a0 mv                   ; Set our malloc pointer
   1619     .80040000 .00000500 13000000
   1620     # rd_a0 rs1_a1 mv                   ; Return the pointer
   1621     .00050000 .00800500 13000000
   1622 
   1623     # rd_ra rs1_sp lw                   ; restore ra
   1624     .80000000 .00000100 03200000
   1625     # rd_a1 rs1_sp !4 lw                ; restore a1
   1626     .80050000 .00000100 .00004000 03200000
   1627     # rd_sp rs1_sp !8 addi              ; deallocate stack
   1628     .00010000 .00000100 .00008000 13000000
   1629     # rs1_ra jalr                       ; return
   1630     .00800000 67000000
   1631 
   1632 
   1633 ; fputc function
   1634 ; receives CHAR in a0 and load FILE* from s3
   1635 ; writes char and returns
   1636 :fputc
   1637     # rd_sp rs1_sp !-16 addi            ; allocate stack
   1638     .00010000 .00000100 .000000FF 13000000
   1639     # rs1_sp rs2_a0 sw                  ; protect a0
   1640     .00000100 .0000A000 23200000
   1641     # rs1_sp rs2_ra @4 sw               ; protect ra
   1642     .00000100 .00001000 .00020000 23200000
   1643     # rs1_sp rs2_a1 @8 sw               ; protect a1
   1644     .00000100 .0000B000 .00040000 23200000
   1645     # rs1_sp rs2_a2 @12 sw              ; protect a2
   1646     .00000100 .0000C000 .00060000 23200000
   1647 
   1648     # rd_a7 !64 addi                    ; sys_write
   1649     .80080000 .00000004 13000000
   1650     # rd_a0 rs1_s3 mv                   ; write to output
   1651     .00050000 .00800900 13000000
   1652     # rd_a1 rs1_sp mv                   ; Get stack address
   1653     .80050000 .00000100 13000000
   1654     # rd_a2 !1 addi                     ; write 1 character
   1655     .00060000 .00001000 13000000
   1656     # ecall                             ; syscall
   1657     73000000
   1658 
   1659     # rd_a0 rs1_sp lw                   ; restore a0
   1660     .00050000 .00000100 03200000
   1661     # rd_ra rs1_sp !4 lw                ; restore ra
   1662     .80000000 .00000100 .00004000 03200000
   1663     # rd_a1 rs1_sp !8 lw                ; restore a1
   1664     .80050000 .00000100 .00008000 03200000
   1665     # rd_a2 rs1_sp !12 lw               ; restore a2
   1666     .00060000 .00000100 .0000C000 03200000
   1667     # rd_sp rs1_sp !16 addi             ; deallocate stack
   1668     .00010000 .00000100 .00000001 13000000
   1669     # rs1_ra jalr                       ; return
   1670     .00800000 67000000
   1671 
   1672 
   1673 :Fail
   1674     ; Terminate program with 1 return code
   1675     # rd_a7 !93 addi                    ; sys_exit
   1676     .80080000 .0000D005 13000000
   1677     # rd_a0 !1 addi                     ; Return code 1
   1678     .00050000 .00001000 13000000
   1679     # ecall                             ; exit(1)
   1680     73000000
   1681 
   1682 ; PROGRAM END
   1683 
   1684 :terminators
   1685 #	"
   1686 #	 "
   1687 0A 09 20 00
   1688 
   1689 :comments
   1690 #	"#;"
   1691 23 3B 00
   1692 
   1693 :string_char
   1694 #	'22 27 00'
   1695 22 27 00
   1696 
   1697 :DEFINE_str
   1698 #	"DEFINE"
   1699 44 45 46 49 4E 45 00
   1700 
   1701 :ELF_end