boot2

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

hex2.hex1 (39860B)


      1 ## Copyright (C) 2021 Andrius Štikonas
      2 ## This file is part of stage0.
      3 ##
      4 ## stage0 is free software: you can redistribute it and/or modify
      5 ## it under the terms of the GNU General Public License as published by
      6 ## the Free Software Foundation, either version 3 of the License, or
      7 ## (at your option) any later version.
      8 ##
      9 ## stage0 is distributed in the hope that it will be useful,
     10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 ## GNU General Public License for more details.
     13 ##
     14 ## You should have received a copy of the GNU General Public License
     15 ## along with stage0.  If not, see <http://www.gnu.org/licenses/>.
     16 
     17 ## ELF Header
     18 
     19 #:ELF_base
     20 7F 45 4C 46        ## e_ident[EI_MAG0-3] ELF's magic number
     21 
     22 02                 ## e_ident[EI_CLASS] Indicating 64 bit
     23 01                 ## e_ident[EI_DATA] Indicating little endianness
     24 01                 ## e_ident[EI_VERSION] Indicating original elf
     25 
     26 03                 ## e_ident[EI_OSABI] Set at 3 because FreeBSD is strict
     27 00                 ## e_ident[EI_ABIVERSION] Set at 0 because none cares
     28 
     29 00 00 00 00 00 00 00 ## e_ident[EI_PAD]
     30 02 00              ## e_type Indicating Executable
     31 F3 00              ## e_machine Indicating RISC-V
     32 01 00 00 00        ## e_version Indicating original elf
     33 
     34 78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address)
     35 40 00 00 00 00 00 00 00 ## e_phoff Address of program header table
     36 00 00 00 00 00 00 00 00 ## e_shoff Address of section header table
     37 
     38 00 00 00 00        ## e_flags
     39 40 00              ## e_ehsize Indicating our 64 Byte header
     40 
     41 38 00              ## e_phentsize size of a program header table
     42 01 00              ## e_phnum number of entries in program table
     43 
     44 00 00              ## e_shentsize size of a section header table
     45 00 00              ## e_shnum number of entries in section table
     46 
     47 00 00              ## e_shstrndx index of the section names
     48 
     49 ## Program Header
     50 #:ELF_program_headers
     51 01 00 00 00             ## p_type
     52 07 00 00 00             ## ph_flags: PF-X|PF-W|PF-R = 7
     53 00 00 00 00 00 00 00 00 ## p_offset
     54 
     55 00 00 60 00 00 00 00 00 ## p_vaddr
     56 00 00 60 00 00 00 00 00 ## p_physaddr
     57 
     58 EC 07 00 00 00 00 00 00 ## p_filesz
     59 EC 07 00 00 00 00 00 00 ## p_memsz
     60 
     61 01 00 00 00 00 00 00 00 ## Required alignment
     62 
     63 #:ELF_text
     64 ; Register use:
     65 ; s1: jump table
     66 ; s2: input fd
     67 ; s3: output fd
     68 ; s4: toggle
     69 ; s5: hold
     70 ; s6: ip
     71 ; s7: tempword
     72 ; s8: shiftregister
     73 ; s9: malloc pointer
     74 ; s10: updates
     75 
     76 ; Struct format: (size 24)
     77 ; next => 0                      ; Next element in linked list
     78 ; target => 8                    ; Target (ip)
     79 ; name => 16                     ; Label name
     80 
     81 ; Our main function
     82 #:_start
     83 
     84     03 36 01 01     # rd_a2 rs1_sp !16 ld               ; Input file name
     85 
     86     ; Initialize globals
     87     13 0A F0 FF     # rd_s4 !-1 addi                    ; Toggle
     88     93 0A 00 00     # rd_s5 addi                        ; Hold
     89     37 0B 60 00     # rd_s6 ~0x600000 lui               ; Instruction Pointer
     90 
     91     ; Open input file and store FD in s2
     92     93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
     93     13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
     94     93 05 06 00     # rd_a1 rs1_a2 mv                   ; file name
     95     13 06 00 00     # rd_a2 addi                        ; read only
     96     73 00 00 00     # ecall                             ; syscall
     97     @F 63 40 05 00  # rs1_a0 @Fail bltz                 ; Error opening file
     98     13 09 05 00     # rd_s2 rs1_a0 mv                   ; Save fd in for later
     99 
    100     ; Set default FD for output file to stdout
    101     93 09 10 00     # rd_s3 !1 addi
    102 
    103     ; If we only have 2 arguments, don't use the third (it's not set)
    104     93 02 20 00     # rd_t0 !2 addi
    105     03 35 01 00     # rd_a0 rs1_sp ld                   ; Get number of the args
    106     @F 63 40 55 00  # rs1_a0 rs2_t0 @Fail blt           ; No input file provided
    107     @a 63 00 55 00  # rs1_a0 rs2_t0 @after_open beq     ; No output file provided. Use stdout
    108 
    109     ; Open output file and store the FD in s3
    110     93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
    111     13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
    112     83 35 81 01     # rd_a1 rs1_sp !24 ld               ; Output file (argument 3)
    113     13 06 10 24     # rd_a2 !00001101 addi              ; decimal 577
    114     ; O_TRUNC   00001000
    115     ; O_CREAT   00000100
    116     ; O_WRONLY  00000001
    117     ; OCTAL!
    118     93 06 00 1C     # rd_a3 !00700 addi                 ; Set read, write, execute permission on user
    119     ; S_IRWXU  00700
    120     ; OCTAL!
    121     73 00 00 00     # ecall                             ; syscall
    122     93 09 05 00     # rd_s3 rs1_a0 mv                   ; Save fd in for later
    123 
    124 :a ;after_open
    125     ; Prepare heap memory
    126     93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    127     13 05 00 00     # rd_a0 addi                        ; Get current brk
    128     73 00 00 00     # ecall                             ; syscall
    129     93 0C 05 00     # rd_s9 rs1_a0 addi                 ; Set our malloc pointer
    130 
    131     B7 05 10 00     # rd_a1 ~0x100000 lui
    132     33 05 B5 00     # rd_a0 rs1_a0 rs2_a1 add           ; Request the 1 MiB
    133     93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    134     73 00 00 00     # ecall                             ; syscall
    135 
    136     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Zero scratch
    137     $f EF 00 00 00  # rd_ra $First_pass jal             ; First pass
    138 
    139     ; Rewind input file
    140     93 08 E0 03     # rd_a7 !62 addi                    ; sys_lseek
    141     13 05 09 00     # rd_a0 rs1_s2 mv                   ; Input file descriptor
    142     93 05 00 00     # rd_a1 mv                          ; Set offset to zero
    143     13 06 00 00     # rd_a2 mv                          ; Set whence to zero
    144     73 00 00 00     # ecall                             ; syscall
    145 
    146     ; Initialize globals
    147     13 0A F0 FF     # rd_s4 !-1 addi                    ; Toggle
    148     93 0A 00 00     # rd_s5 addi                        ; Hold
    149     37 0B 60 00     # rd_s6 ~0x600000 lui               ; Instruction Pointer
    150     93 0B 00 00     # rd_s7 addi                        ; tempword
    151     13 0C 00 00     # rd_s8 addi                        ; Shift register
    152 
    153     $X EF 00 00 00  # rd_ra $Second_pass jal            ; Now do the second pass
    154 
    155     ; Terminate program with 0 return code
    156     93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    157     13 05 00 00     # rd_a0 mv                          ; Return code 0
    158     73 00 00 00     # ecall                             ; exit(0)
    159 
    160 ; First pass loop to determine addresses of labels
    161 :f ;First_pass
    162     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    163     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    164 
    165 :1 ;First_pass_loop
    166     $R EF 00 00 00  # rd_ra $Read_byte jal              ; Get another byte
    167 
    168     ; Deal with EOF
    169     13 03 C0 FF     # rd_t1 !-4 addi
    170     @3 63 00 65 00  # rs1_a0 rs2_t1 @First_pass_done beq
    171 
    172     ; Check for :
    173     13 03 A0 03     # rd_t1 !0x3a addi
    174     @L 63 00 65 00  # rs1_a0 rs2_t1 @StoreLabel beq ; Store this label
    175 
    176     ; Check for .
    177     13 03 E0 02     # rd_t1 !0x2e addi
    178     @w 63 00 65 00  # rs1_a0 rs2_t1 @First_pass_UpdateWord beq
    179 
    180     ; Check for %
    181     13 03 50 02     # rd_t1 !0x25 addi
    182     @p 63 00 65 00  # rs1_a0 rs2_t1 @First_pass_pointer beq
    183 
    184     ; Check for &
    185     13 03 60 02     # rd_t1 !0x26 addi
    186     @p 63 00 65 00  # rs1_a0 rs2_t1 @First_pass_pointer beq
    187 
    188     ; Check for !
    189     13 03 10 02     # rd_t1 !0x21 addi
    190     @T 63 00 65 00  # rs1_a0 rs2_t1 @Throwaway_token beq
    191 
    192     ; Check for @
    193     13 03 00 04     # rd_t1 !0x40 addi
    194     @T 63 00 65 00  # rs1_a0 rs2_t1 @Throwaway_token beq
    195 
    196     ; Check for $
    197     13 03 40 02     # rd_t1 !0x24 addi
    198     @T 63 00 65 00  # rs1_a0 rs2_t1 @Throwaway_token beq
    199 
    200     ; Check for ~
    201     13 03 E0 07     # rd_t1 !0x7e addi
    202     @T 63 00 65 00  # rs1_a0 rs2_t1 @Throwaway_token beq
    203 
    204     ; Check for <
    205     13 03 C0 03     # rd_t1 !0x3c addi
    206     93 05 F0 FF     # rd_a1 !-1 addi                    ; write = false
    207     @A 63 00 65 00  # rs1_a0 rs2_t1 @PadToAlign beq
    208 
    209     93 05 F0 FF     # rd_a1 !-1 addi                    ; write = false
    210     13 06 F0 FF     # rd_a2 !-1 addi                    ; update = false
    211     $D EF 00 00 00  # rd_ra $DoByte jal                 ; Deal with everything else
    212 
    213     13 03 C0 FF     # rd_t1 !-4 addi                    ; Deal with EOF
    214     @3 63 00 65 00  # rs1_a0 rs2_t1 @First_pass_done beq
    215 
    216     $1 6F 00 00 00  # $First_pass_loop jal              ; Keep looping
    217 
    218 :T ;Throwaway_token
    219     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    220     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; get scratch
    221     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read token
    222     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Throw away token
    223     $1 6F 00 00 00  # $First_pass_loop jal              ; Loop again
    224 
    225 :p ;First_pass_pointer
    226     13 0B 4B 00     # rd_s6 rs1_s6 !4 addi              ; Update ip
    227     ; Deal with Pointer to label
    228     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    229     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Using scratch
    230     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read token
    231     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Throw away token
    232     13 03 E0 03     # rd_t1 !0x3e addi                  ; Check for '>'
    233     @1 63 10 65 00  # rs1_a0 rs2_t1 @First_pass_loop bne ; Loop again
    234 
    235     ; Deal with %label>label case
    236     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    237     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Using scratch
    238     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read token
    239     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Throw away token
    240     $1 6F 00 00 00  # $First_pass_loop jal ; Loop again
    241 
    242 :w ;First_pass_UpdateWord
    243     13 0D 00 00     # rd_s10 addi                       ; updates = 0
    244     93 0B 00 00     # rd_s7 addi                        ; tempword = 0
    245     93 07 40 00     # rd_a5 !4 addi                     ; a5 = 4
    246 :4 ;First_pass_UpdateWord_loop
    247     $R EF 00 00 00  # rd_ra $Read_byte jal              ; Read another byte into a0
    248 
    249     93 05 F0 FF     # rd_a1 !-1 addi                    ; write = false
    250     13 06 00 00     # rd_a2 addi                        ; update = true
    251     $D EF 00 00 00  # rd_ra $DoByte jal                 ; Process byte
    252     @4 63 40 FD 00  # rs1_s10 rs2_a5 @First_pass_UpdateWord_loop blt ; loop 4 times
    253 
    254     13 0B CB FF     # rd_s6 rs1_s6 !-4 addi             ; ip = ip - 4
    255 
    256     $1 6F 00 00 00  # $First_pass_loop jal              ; Loop again
    257 
    258 :3 ;First_pass_done
    259     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    260     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    261     67 80 00 00     # rs1_ra jalr                       ; return
    262 
    263 :X ;Second_pass
    264     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    265     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    266 
    267 :5 ;Second_pass_loop
    268     $R EF 00 00 00  # rd_ra $Read_byte jal              ; Read another byte
    269 
    270     ; Deal with EOF
    271     13 03 C0 FF     # rd_t1 !-4 addi                    ; Deal with EOF
    272     @6 63 00 65 00  # rs1_a0 rs2_t1 @Second_pass_done beq
    273 
    274     ; Drop the label
    275     13 03 A0 03     # rd_t1 !0x3a addi
    276     @7 63 10 65 00  # rs1_a0 rs2_t1 @Second_pass_0 bne
    277 
    278     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    279     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Using scratch
    280     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read the label
    281     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Throw away token
    282 
    283     $5 6F 00 00 00  # $Second_pass_loop jal             ; Continue looping
    284 
    285 :7 ;Second_pass_0
    286     ; Check for .
    287     13 03 E0 02     # rd_t1 !0x2e addi
    288     @8 63 00 65 00  # rs1_a0 rs2_t1 @Second_pass_UpdateWord beq
    289 
    290     ; Check for %
    291     13 03 50 02     # rd_t1 !0x25 addi
    292     @S 63 00 65 00  # rs1_a0 rs2_t1 @StorePointer beq
    293 
    294     ; Check for &
    295     13 03 60 02     # rd_t1 !0x26 addi
    296     @S 63 00 65 00  # rs1_a0 rs2_t1 @StorePointer beq
    297 
    298     ; Check for !
    299     13 03 10 02     # rd_t1 !0x21 addi
    300     @Y 63 00 65 00  # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    301 
    302     ; Check for @
    303     13 03 00 04     # rd_t1 !0x40 addi
    304     @Y 63 00 65 00  # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    305 
    306     ; Check for $
    307     13 03 40 02     # rd_t1 !0x24 addi
    308     @Y 63 00 65 00  # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    309 
    310     ; Check for ~
    311     13 03 E0 07     # rd_t1 !0x7e addi
    312     @Y 63 00 65 00  # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    313 
    314     ; Check for <
    315     13 03 C0 03     # rd_t1 !0x3c addi
    316     93 05 00 00     # rd_a1 addi                        ; write = true
    317     @A 63 00 65 00  # rs1_a0 rs2_t1 @PadToAlign beq
    318 
    319     ; Deal with everything else
    320     93 05 00 00     # rd_a1 addi                        ; write = true
    321     13 06 F0 FF     # rd_a2 !-1 addi                    ; update = false
    322     $D EF 00 00 00  # rd_ra $DoByte jal                 ; Process our char
    323 
    324     # Deal with EOF
    325     13 03 C0 FF     # rd_t1 !-4 addi
    326     @6 63 00 65 00  # rs1_a0 rs2_t1 @Second_pass_done beq ; We are done
    327 
    328     $5 6F 00 00 00  # $Second_pass_loop jal ; continue looping
    329 
    330 :8 ;Second_pass_UpdateWord
    331     13 0D 00 00     # rd_s10 addi                       ; updates = 0
    332     93 0B 00 00     # rd_s7 addi                        ; tempword = 0
    333     93 07 40 00     # rd_a5 !4 addi                     ; a5 = 4
    334 
    335 :9 ;Second_pass_UpdateWord_loop
    336     $R EF 00 00 00  # rd_ra $Read_byte jal       ; Read another byte into a0
    337 
    338     93 05 F0 FF     # rd_a1 !-1 addi                    ; write = false
    339     13 06 00 00     # rd_a2 addi                        ; update = true
    340     $D EF 00 00 00  # rd_ra $DoByte jal             ; Process our char
    341     @9 63 40 FD 00  # rs1_s10 rs2_a5 @Second_pass_UpdateWord_loop blt ; loop 4 times
    342 
    343     13 85 0B 00     # rd_a0 rs1_s7 mv                   ; tempword
    344     $d 6F 00 00 00  # $UpdateShiftRegister_DOT jal ; UpdateShiftRegister('.', tempword)
    345 
    346 :Y ;UpdateShiftRegister
    347     13 06 05 00     # rd_a2 rs1_a0 mv                   ; Store label prefix
    348     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    349     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Get scratch
    350     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; Clear scratch
    351     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read token
    352     $G EF 00 00 00  # rd_ra $GetTarget jal              ; Get target
    353     03 35 05 00     # rd_a0 rs1_a0 ld                   ; Dereference pointer
    354     33 05 65 41     # rd_a0 rs1_a0 rs2_s6 sub           ; target - ip
    355 
    356     ; Check for !
    357     13 03 10 02     # rd_t1 !0x21 addi
    358     @I 63 00 66 00  # rs1_a2 rs2_t1 @UpdateShiftRegister_I beq
    359 
    360     ; Check for @
    361     13 03 00 04     # rd_t1 !0x40 addi
    362     @B 63 00 66 00  # rs1_a2 rs2_t1 @UpdateShiftRegister_B beq
    363 
    364     ; Check for $
    365     13 03 40 02     # rd_t1 !0x24 addi
    366     @J 63 00 66 00  # rs1_a2 rs2_t1 @UpdateShiftRegister_J beq
    367 
    368     ; Check for ~
    369     13 03 E0 07     # rd_t1 !0x7e addi
    370     @U 63 00 66 00  # rs1_a2 rs2_t1 @UpdateShiftRegister_U beq
    371 
    372     $5 6F 00 00 00  # $Second_pass_loop jal ; continue looping
    373 
    374 :d ;UpdateShiftRegister_DOT
    375     ; . before instruction means it has to be added to the final word
    376 
    377     ; swap = (((value >> 24) & 0xff) |
    378     ;        ((value << 8) & 0xff0000) |
    379     ;        ((value >> 8) & 0xff00) |
    380     ;        ((value << 24) & 0xff000000))
    381 
    382     9B 53 85 01     # rd_t2 rs1_a0 rs2_x24 srliw        ; value >> 24
    383     13 03 F0 0F     # rd_t1 !0xff addi                  ; t1 = 0xff
    384     B3 72 73 00     # rd_t0 rs1_t1 rs2_t2 and           ; (value >> 24) & 0xff
    385 
    386     9B 13 85 00     # rd_t2 rs1_a0 rs2_x8 slliw         ; value << 8
    387     37 03 FF 00     # rd_t1 ~0xff0000 lui               ; t1 = 0xff0000
    388     B3 73 73 00     # rd_t2 rs1_t1 rs2_t2 and           ; (value << 8) & 0xff0000
    389     B3 E2 72 00     # rd_t0 rs1_t0 rs2_t2 or            ; logical or with the previous expression
    390 
    391     9B 53 85 00     # rd_t2 rs1_a0 rs2_x8 srliw         ; value >> 8
    392     37 03 01 00     # rd_t1 ~0xff00 lui                 ; t1 = 0xff00
    393     1B 03 03 F0     # rd_t1 rs1_t1 !0xff00 addiw        ; t1 = 0xff00
    394     B3 73 73 00     # rd_t2 rs1_t1 rs2_t2 and           ; (value << 8) & 0xff00
    395     B3 E2 72 00     # rd_t0 rs1_t0 rs2_t2 or            ; logical or with the previous expression
    396 
    397     9B 13 85 01     # rd_t2 rs1_a0 rs2_x24 slliw        ; value << 24
    398     13 03 F0 0F     # rd_t1 !0xff addi
    399     13 13 83 01     # rd_t1 rs1_t1 rs2_x24 slli         ; t1 = 0xff000000
    400     B3 73 73 00     # rd_t2 rs1_t1 rs2_t2 and           ; (value << 24) & 0xff000000
    401     B3 E2 72 00     # rd_t0 rs1_t0 rs2_t2 or            ; swap
    402 
    403     33 4C 5C 00     # rd_s8 rs1_s8 rs2_t0 xor           ; shiftregister = shiftregister ^ swap
    404 
    405     13 0B CB FF     # rd_s6 rs1_s6 !-4 addi             ; ip = ip - 4
    406     $5 6F 00 00 00  # $Second_pass_loop jal             ; continue looping
    407 
    408 :I ;UpdateShiftRegister_I
    409     ; Corresponds to RISC-V I format
    410     1B 05 45 00     # rd_a0 rs1_a0 !4 addiw             ; add 4 due to this being 2nd part of auipc combo
    411 
    412     37 13 00 00     # rd_t1 ~0xfff lui                  ; load higher bits
    413     1B 03 F3 FF     # rd_t1 rs1_t1 !0xfff addiw
    414     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; (value & 0xfff)
    415     9B 1B 43 01     # rd_s7 rs1_t1 rs2_x20 slliw        ; tempword = (value & 0xfff) << 20
    416     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    417 
    418     $5 6F 00 00 00  # $Second_pass_loop jal             ; continue looping
    419 
    420 :B ;UpdateShiftRegister_B
    421     ; Corresponds to RISC-V B format
    422 
    423     ; tempword = ((value & 0x1e) << 7)            ; imm[4:1]
    424     ;          | ((value & 0x7e0) << (31 - 11))   ; imm[10:5]
    425     ;          | ((value & 0x800) >> 4)           ; imm[11]
    426     ;          | ((value & 0x1000) << (31 - 12))  ; imm[12]
    427 
    428     13 03 E0 01     # rd_t1 !0x1e addi
    429     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x1e
    430     9B 12 73 00     # rd_t0 rs1_t1 rs2_x7 slliw         ; tempword = (value & 0x1e) << 7
    431 
    432     13 03 00 7E     # rd_t1 !0x7e0 addi
    433     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x7e0
    434     1B 13 43 01     # rd_t1 rs1_t1 rs2_x20 slliw        ; (value & 0x7e0) << (31 - 11)
    435     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    436 
    437     37 13 00 00     # rd_t1 ~0x800 lui                  ; load higher bits
    438     1B 03 03 80     # rd_t1 rs1_t1 !0x800 addiw
    439     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x800
    440     1B 53 43 00     # rd_t1 rs1_t1 rs2_x4 srliw         ; (value & 0x800) >> 4
    441     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    442 
    443     37 13 00 00     # rd_t1 ~0x1000 lui                 ; load higher bits
    444     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x1000
    445     1B 13 33 01     # rd_t1 rs1_t1 rs2_x19 slliw        ; (value & 0x1000) << (31 - 12)
    446     B3 EB 62 00     # rd_s7 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    447 
    448     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    449 
    450     $5 6F 00 00 00  # $Second_pass_loop jal             ; continue looping
    451 
    452 :J ;UpdateShiftRegister_J
    453     ; Corresponds to RISC-V J format
    454 
    455     ; tempword = ((value & 0x7fe) << (30 - 10))    ; imm[10:1]
    456     ;          | ((value & 0x800) << (20 - 11))    ; imm[11]
    457     ;          | ((value & 0xff000))               ; imm[19:12]
    458     ;          | ((value & 0x100000) << (31 - 20)) ; imm[20]
    459 
    460     13 03 E0 7F     # rd_t1 !0x7fe addi
    461     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x7fe
    462     9B 12 43 01     # rd_t0 rs1_t1 rs2_x20 slliw        ; tempword = (value & 0x7fe) << 20
    463 
    464     37 13 00 00     # rd_t1 ~0x800 lui                  ; load higher bits
    465     1B 03 03 80     # rd_t1 rs1_t1 !0x800 addiw
    466     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x800
    467     1B 13 93 00     # rd_t1 rs1_t1 rs2_x9 slliw         ; (value & 0x800) << (20 - 11)
    468     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    469 
    470     37 F3 0F 00     # rd_t1 ~0xff000 lui                ; load higher bits
    471     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xff000
    472     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    473 
    474     37 03 10 00     # rd_t1 ~0x100000 lui               ; load higher bits
    475     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x100000
    476     1B 13 B3 00     # rd_t1 rs1_t1 rs2_x11 slliw        ; (value & 0x100000) << (31 - 20)
    477     B3 EB 62 00     # rd_s7 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    478 
    479     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    480 
    481     $5 6F 00 00 00  # $Second_pass_loop jal             ; continue looping
    482 
    483 :U ;UpdateShiftRegister_U
    484     ; Corresponds to RISC-V U format
    485     ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension
    486 
    487     B7 12 00 00     # rd_t0 ~0x800 lui                  ; load higher bits
    488     9B 82 02 80     # rd_t0 rs1_t0 !0x800 addiw
    489     37 13 00 00     # rd_t1 ~0xfff lui                  ; load higher bits
    490     1B 03 F3 FF     # rd_t1 rs1_t1 !0xfff addiw
    491 
    492     ; We are outside 31-bit that ~ can normally load
    493     B7 03 10 00     # rd_t2 ~0x100000 lui               ; load 0xfffff000
    494     9B 83 F3 FF     # rd_t2 rs1_t2 !-1 addiw            ; load 0xfffff000
    495     93 93 C3 00     # rd_t2 rs1_t2 rs2_x12 slli         ; load 0xfffff000
    496     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xfff
    497     B3 7B 75 00     # rd_s7 rs1_a0 rs2_t2 and           ; value & 0xfffff000
    498     @u 63 40 53 00  # rs1_t1 rs2_t0 @UpdateShiftRegister_U_small blt
    499 
    500     # Deal with sign extension: add 0x1000
    501     B7 12 00 00     # rd_t0 ~0x1000 lui                 ; load higher bits
    502     BB 8B 72 01     # rd_s7 rs1_t0 rs2_s7 addw          ; (value & 0xfffff000) + 0x1000
    503 
    504 :u ;UpdateShiftRegister_U_small
    505     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    506 
    507     $5 6F 00 00 00  # $Second_pass_loop jal             ; continue looping
    508 
    509 :S ;StorePointer
    510     13 0B 4B 00     # rd_s6 rs1_s6 !4 addi              ; update ip
    511     13 06 05 00     # rd_a2 rs1_a0 mv                   ; Store label prefix
    512 
    513     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    514     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Get scratch
    515     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; clear scratch
    516     $c EF 00 00 00  # rd_ra $consume_token jal          ; Read token
    517     93 07 05 00     # rd_a5 rs1_a0 mv                   ; save char
    518     $G EF 00 00 00  # rd_ra $GetTarget jal              ; Get target
    519     83 35 05 00     # rd_a1 rs1_a0 ld                   ; Dereference pointer
    520 
    521     ; If char is > then change relative base address to ip
    522     13 03 E0 03     # rd_t1 !0x3e addi                  ; t1 = 0x3e
    523     @P 63 00 F3 00  # rs1_t1 rs2_a5 @StorePointer_1 beq
    524 
    525     ; Check for &
    526     13 03 60 02     # rd_t1 !0x26 addi
    527     @0 63 00 66 00  # rs1_a2 rs2_t1 @StorePointer_0 beq
    528 
    529     ; Check for %
    530     13 03 50 02     # rd_t1 !0x25 addi
    531     @F 63 10 66 00  # rs1_a2 rs2_t1 @Fail bne
    532     B3 85 65 41     # rd_a1 rs1_a1 rs2_s6 sub           ; displacement = target - ip
    533 
    534 :0 ;StorePointer_0
    535     ; Output pointer
    536     93 07 40 00     # rd_a5 !4 addi                     ; number of bytes
    537 :l ;StorePointer_loop
    538     13 D3 85 00     # rd_t1 rs1_a1 rs2_x8 srli          ; value / 256
    539     13 15 83 00     # rd_a0 rs1_t1 rs2_x8 slli
    540     33 85 A5 40     # rd_a0 rs1_a1 rs2_a0 sub           ; byte = value % 256
    541 
    542     93 05 03 00     # rd_a1 rs1_t1 mv                   ; value = value / 256
    543     $t EF 00 00 00  # rd_ra $fputc jal                  ; write value
    544     93 87 F7 FF     # rd_a5 rs1_a5 !-1 addi             ; decrease number of bytes to write
    545     @l 63 90 07 00  # rs1_a5 @StorePointer_loop bnez    ; continue looping
    546 
    547     $5 6F 00 00 00  # $Second_pass_loop jal             ; Continue looping
    548 
    549 :P ;StorePointer_1
    550     13 86 05 00     # rd_a2 rs1_a1 mv                   ; save target
    551     ~s 97 05 00 00  # rd_a1 ~scratch auipc
    552     !s 93 85 05 00  # rd_a1 rs1_a1 !scratch addi        ; Get scratch
    553     $C EF 00 00 00  # rd_ra $ClearScratch jal           ; clear scratch
    554     $c EF 00 00 00  # rd_ra $consume_token jal          ; consume token
    555     $G EF 00 00 00  # rd_ra $GetTarget jal              ; Get target
    556     83 35 05 00     # rd_a1 rs1_a0 ld                   ; Dereference pointer
    557     B3 05 B6 40     # rd_a1 rs1_a2 rs2_a1 sub           ; displacement = target - ip
    558 
    559     $0 6F 00 00 00  # $StorePointer_0 jal               ; Continue looping
    560 
    561 :6 ;Second_pass_done
    562     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    563     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    564     67 80 00 00     # rs1_ra jalr                       ; return
    565 
    566 ; Pad with zeros to align to word size
    567 ;   bool write in a1
    568 :A ;PadToAlign
    569     13 03 10 00     # rd_t1 !1 addi                     ; t1 = 1
    570     33 75 6B 00     # rd_a0 rs1_s6 rs2_t1 and           ; ip & 0x1
    571     @b 63 10 65 00  # rs1_a0 rs2_t1 @PadToAlign_1 bne   ; check if ip & 0x1 == 1
    572     33 0B 6B 00     # rd_s6 rs1_s6 rs2_t1 add           ; ip = ip + 1
    573 
    574     @b 63 90 05 00  # rs1_a1 @PadToAlign_1 bnez         ; check if we have to write
    575     13 05 00 00     # rd_a0 mv                          ; a0 = 0
    576     $t EF 00 00 00  # rd_ra $fputc jal                  ; write 0
    577 
    578 :b ;PadToAlign_1
    579     13 03 20 00     # rd_t1 !2 addi                     ; t1 = 2
    580     33 75 6B 00     # rd_a0 rs1_s6 rs2_t1 and           ; ip & 0x1
    581     @e 63 10 65 00  # rs1_a0 rs2_t1 @PadToAlign_2 bne   ; check if ip & 0x2 == 2
    582     33 0B 6B 00     # rd_s6 rs1_s6 rs2_t1 add           ; ip = ip + 2
    583 
    584     @e 63 90 05 00  # rs1_a1 @PadToAlign_2 bnez         ; check if we have to write
    585     13 05 00 00     # rd_a0 mv                          ; a0 = 0
    586     $t EF 00 00 00  # rd_ra $fputc jal                  ; write 0
    587     13 05 00 00     # rd_a0 mv                          ; a0 = 0
    588     $t EF 00 00 00  # rd_ra $fputc jal                  ; write 0
    589 
    590 :e ;PadToAlign_2
    591     @5 63 80 05 00  # rs1_a1 @Second_pass_loop beqz     ; return to Second_pass
    592     $1 6F 00 00 00  # $First_pass_loop jal              ; return to First_pass
    593 
    594 ; Zero scratch area
    595 :C ;ClearScratch
    596     13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; Allocate stack
    597     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    598     23 34 A1 00     # rs1_sp rs2_a0 @8 sd               ; protect a0
    599     23 38 B1 00     # rs1_sp rs2_a1 @16 sd              ; protect a1
    600 
    601     ~s 17 05 00 00  # rd_a0 ~scratch auipc
    602     !s 13 05 05 00  # rd_a0 rs1_a0 !scratch addi        ; Find where our scratch area is
    603 
    604 :g ;ClearScratch_loop
    605     83 05 05 00     # rd_a1 rs1_a0 lb                   ; Read current byte: s[i]
    606     23 00 05 00     # rs1_a0 sb                         ; Write zero: s[i] = 0
    607     13 05 15 00     # rd_a0 rs1_a0 !1 addi              ; Increment: i = i + 1
    608     @g 63 90 05 00  # rs1_a1 @ClearScratch_loop bnez    ; Keep looping
    609 
    610     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    611     03 35 81 00     # rd_a0 rs1_sp !8 ld                ; restore a0
    612     83 35 01 01     # rd_a1 rs1_sp !16 ld               ; restore a1
    613     13 01 81 01     # rd_sp rs1_sp !24 addi             ; Deallocate stack
    614     67 80 00 00     # rs1_ra jalr                       ; return
    615 
    616 ; Receives pointer in a1
    617 ; Writes our token and updates pointer in a1
    618 :c ;consume_token
    619     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    620     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    621 
    622 :h ;consume_token_0
    623     $R EF 00 00 00  # rd_ra $Read_byte jal              ; Read byte into a0
    624 
    625     ; Check for \t
    626     13 03 90 00     # rd_t1 !0x09 addi
    627     @j 63 00 65 00  # rs1_a0 rs2_t1 @consume_token_done beq
    628 
    629     ; Check for \n
    630     13 03 A0 00     # rd_t1 !0x0a addi
    631     @j 63 00 65 00  # rs1_a0 rs2_t1 @consume_token_done beq
    632 
    633     ; Check for ' '
    634     13 03 00 02     # rd_t1 !0x20 addi
    635     @j 63 00 65 00  # rs1_a0 rs2_t1 @consume_token_done beq
    636 
    637     ; Check for >
    638     13 03 E0 03     # rd_t1 !0x3e addi
    639     @j 63 00 65 00  # rs1_a0 rs2_t1 @consume_token_done beq
    640 
    641     23 80 A5 00     # rs1_a1 rs2_a0 sb                  ; Store char
    642     93 85 15 00     # rd_a1 rs1_a1 !1 addi              ; Point to next spot
    643     $h 6F 00 00 00  # $consume_token_0 jal ; Continue looping
    644 
    645 :j ;consume_token_done
    646     23 B0 05 00     # rs1_a1 sd                         ; Pad with nulls
    647     93 85 85 00     # rd_a1 rs1_a1 !8 addi              ; Update the pointer
    648 
    649     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    650     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    651     67 80 00 00     # rs1_ra jalr                       ; return
    652 
    653 ; DoByte function
    654 ; Receives:
    655 ;   character in a0
    656 ;   bool write in a1
    657 ;   bool update in a2
    658 ; Does not return anything
    659 :D ;DoByte
    660     13 01 01 FF     # rd_sp rs1_sp !-16 addi            ; Allocate stack
    661     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    662     23 34 01 01     # rs1_sp rs2_a6 @8 sd               ; protect a6
    663 
    664     $H EF 00 00 00  # rd_ra $hex jal                    ; Process hex, store it in a6
    665 
    666     @k 63 40 08 00  # rs1_a6 @DoByte_Done bltz          ; Deal with EOF and unrecognized characters
    667 
    668     @2 63 10 0A 00  # rs1_s4 @DoByte_NotToggle bnez     ; Check if toggle is set
    669 
    670     ; toggle = true
    671     @m 63 90 05 00  # rs1_a1 @DoByte_1 bnez             ; check if we have to write
    672 
    673     ; write = true
    674     ; We calculate (hold * 16) + hex(c) ^ sr_nextb()
    675     ; First, calculate new shiftregister
    676     93 02 F0 0F     # rd_t0 !0xff addi
    677     B3 72 5C 00     # rd_t0 rs1_s8 rs2_t0 and           ; sr_nextb = shiftregister & 0xff
    678     1B 5C 8C 00     # rd_s8 rs1_s8 rs2_x8 srliw         ; shiftregister >> 8
    679 
    680     B3 C2 02 01     # rd_t0 rs1_t0 rs2_a6 xor           ; hex(c) ^ sr_nextb
    681     13 93 4A 00     # rd_t1 rs1_s5 rs2_x4 slli          ; hold << 4
    682     33 85 62 00     # rd_a0 rs1_t0 rs2_t1 add           ; (hold << 4) + hex(c) ^ sr_nextb()
    683     $t EF 00 00 00  # rd_ra $fputc jal                  ; print it
    684     @F 63 00 05 00  # rs1_a0 @Fail beqz                 ; Fail if nothing was written
    685 
    686 :m ;DoByte_1
    687     13 0B 1B 00     # rd_s6 rs1_s6 !1 addi              ; Increment IP
    688     @o 63 00 06 00  # rs1_a2 @DoByte_2 beqz             ; check if we have to update
    689 :n ;DoByte_2b
    690     93 0A 00 00     # rd_s5 mv                          ; hold = 0
    691     $q 6F 00 00 00  # $DoByte_FlipToggle jal            ; return
    692 
    693 :2 ;DoByte_NotToggle
    694     93 0A 08 00     # rd_s5 rs1_a6 mv                   ; hold = hex(c)
    695 
    696 :q ;DoByte_FlipToggle
    697     13 4A FA FF     # rd_s4 rs1_s4 not                  ; Flip the toggle
    698 
    699 :k ;DoByte_Done
    700     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    701     03 38 81 00     # rd_a6 rs1_sp !8 ld                ; restore a6
    702     13 01 01 01     # rd_sp rs1_sp !16 addi             ; Deallocate stack
    703     67 80 00 00     # rs1_ra jalr                       ; return
    704 
    705 :o ;DoByte_2
    706     13 93 4A 00     # rd_t1 rs1_s5 rs2_x4 slli          ; hold * 16
    707     B3 0A 03 01     # rd_s5 rs1_t1 rs2_a6 add           ; hold = hold * 16 + hex(c)
    708     13 93 8B 00     # rd_t1 rs1_s7 rs2_x8 slli          ; tempword << 8
    709     B3 4B 53 01     # rd_s7 rs1_t1 rs2_s5 xor           ; tempword = (tempword << 8) ^ hold
    710     13 0D 1D 00     # rd_s10 rs1_s10 !1 addi            ; updates = updates + 1
    711     $n 6F 00 00 00  # $DoByte_2b jal
    712 
    713 ; Convert ASCII hex characters into binary representation, e.g. 'a' -> 0xA
    714 ; Receives:
    715 ;   character in a0
    716 ; Returns:
    717 ;   a6 with character's hex value.
    718 :H ;hex
    719     13 01 01 FF     # rd_sp rs1_sp !-16 addi            ; Allocate stack
    720     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    721     23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    722 
    723     ; Deal with EOF
    724     13 03 C0 FF     # rd_t1 !-4 addi
    725     @r 63 00 65 00  # rs1_a0 rs2_t1 @hex_return beq
    726 
    727     ; deal with line comments starting with #
    728     13 03 30 02     # rd_t1 !0x23 addi
    729     @x 63 00 65 00  # rs1_a0 rs2_t1 @ascii_comment beq  ; a0 eq to '#'
    730 
    731     ; deal with line comments starting with ;
    732     13 03 B0 03     # rd_t1 !0x3b addi
    733     @x 63 00 65 00  # rs1_a0 rs2_t1 @ascii_comment beq  ; a0 eq to ';'
    734 
    735     ; deal all ascii less than 0
    736     13 03 00 03     # rd_t1 !0x30 addi
    737     @y 63 40 65 00  # rs1_a0 rs2_t1 @ascii_other blt
    738 
    739     ; deal with 0-9
    740     13 03 A0 03     # rd_t1 !0x3a addi
    741     @N 63 40 65 00  # rs1_a0 rs2_t1 @ascii_num blt
    742 
    743     ; deal with all ascii less than A
    744     13 03 10 04     # rd_t1 !0x41 addi
    745     @y 63 40 65 00  # rs1_a0 rs2_t1 @ascii_other blt
    746 
    747     ; deal with A-F
    748     13 03 70 04     # rd_t1 !0x47 addi
    749     @z 63 40 65 00  # rs1_a0 rs2_t1 @ascii_high blt
    750 
    751     ; deal with all ascii less than a
    752     13 03 10 06     # rd_t1 !0x61 addi
    753     @y 63 40 65 00  # rs1_a0 rs2_t1 @ascii_other blt
    754 
    755     ; deal with a-f
    756     13 03 70 06     # rd_t1 !0x67 addi
    757     @Z 63 40 65 00  # rs1_a0 rs2_t1 @ascii_low blt
    758 
    759     ; The rest that remains needs to be ignored
    760     $y 6F 00 00 00  # $ascii_other jal
    761 
    762 :N ;ascii_num
    763     13 03 00 03     # rd_t1 !0x30 addi                  ; '0' -> 0
    764     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    765     $r 6F 00 00 00  # $hex_return jal                   ; return
    766 :Z ;ascii_low
    767     13 03 70 05     # rd_t1 !0x57 addi                  ; 'a' -> 0xA
    768     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    769     $r 6F 00 00 00  # $hex_return jal                   ; return
    770 :z ;ascii_high
    771     13 03 70 03     # rd_t1 !0x37 addi                  ; 'A' -> 0xA
    772     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    773     $r 6F 00 00 00 # $hex_return jal                    ; return
    774 :y ;ascii_other
    775     13 08 F0 FF     # rd_a6 !-1 addi                    ; Return -1
    776     $r 6F 00 00 00  # $hex_return jal                   ; return
    777 :x ;ascii_comment                        ; Read the comment until newline
    778     $R EF 00 00 00  # rd_ra $Read_byte jal
    779     13 03 D0 00     # rd_t1 !0xd addi                   ; CR
    780     @E 63 00 65 00  # rs1_a0 rs2_t1 @ascii_comment_cr beq
    781     13 03 A0 00     # rd_t1 !0xa addi                   ; LF
    782     @x 63 10 65 00  # rs1_a0 rs2_t1 @ascii_comment bne  ; Keep reading comment
    783 :E ;ascii_comment_cr
    784     13 08 F0 FF     # rd_a6 !-1 addi                    ; Return -1
    785 :r ;hex_return
    786     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    787     83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    788     13 01 01 01     # rd_sp rs1_sp !16 addi             ; Deallocate stack
    789     67 80 00 00     # rs1_ra jalr                       ; return
    790 
    791 ; Read byte into a0
    792 :R ;Read_byte
    793     13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; Allocate stack
    794     23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    795     23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2
    796 
    797     93 08 F0 03     # rd_a7 !63 addi                    ; sys_read
    798     13 05 09 00     # rd_a0 rs1_s2 mv                   ; File descriptor
    799     93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address for buffer
    800     13 06 10 00     # rd_a2 !1 addi                     ; Size of what we want to read
    801     73 00 00 00     # ecall                             ; syscall
    802 
    803     @K 63 00 05 00  # rs1_a0 @Read_byte_1 beqz          ; Deal with EOF
    804     03 C5 05 00     # rd_a0 rs1_a1 lbu                  ; return char in a0
    805 
    806     $M 6F 00 00 00  # $Read_byte_done jal               ; return
    807 
    808 :K ;Read_byte_1
    809     13 05 C0 FF     # rd_a0 !-4 addi                    ; Put EOF in a0
    810 :M ;Read_byte_done
    811     83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    812     03 36 01 01     # rd_a2 rs1_sp !16 ld               ; restore a2
    813     13 01 81 01     # rd_sp rs1_sp !24 addi             ; Deallocate stack
    814     67 80 00 00     # rs1_ra jalr                       ; return
    815 
    816 ; Find a label matching pointer in scratch
    817 ; Returns a pointer in a0
    818 :G ;GetTarget
    819     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    820     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    821 
    822     93 82 04 00     # rd_t0 rs1_s1 mv                   ; grab jump_table
    823 
    824 :O ;GetTarget_loop_0
    825     ; Compare the strings
    826     ~s 17 03 00 00  # rd_t1 ~scratch auipc
    827     !s 13 03 03 00  # rd_t1 rs1_t1 !scratch addi        ; reset scratch
    828     83 B3 02 01     # rd_t2 rs1_t0 !16 ld               ; I->name
    829 :Q ;GetTarget_loop
    830     83 CE 03 00     # rd_t4 rs1_t2 lbu                  ; I->name[i]
    831     03 4E 03 00     # rd_t3 rs1_t1 lbu                  ; scratch[i]
    832     @v 63 10 DE 01  # rs1_t3 rs2_t4 @GetTarget_miss bne ; strings don't match
    833 
    834     ; Look at the next char
    835     13 03 13 00     # rd_t1 rs1_t1 !1 addi
    836     93 83 13 00     # rd_t2 rs1_t2 !1 addi
    837     @Q 63 90 0E 00  # rs1_t4 @GetTarget_loop bnez       ; Loop until zero (end of string)
    838     $V 6F 00 00 00  # $GetTarget_done jal   ; We have a match
    839 
    840 :v ;GetTarget_miss
    841     83 B2 02 00     # rd_t0 rs1_t0 ld                   ; I = I->next
    842     @F 63 80 02 00  # rs1_t0 @Fail beqz                 ; Abort, no match found
    843 
    844     $O 6F 00 00 00  # $GetTarget_loop_0 jal             ; Try another label
    845 
    846 :V ;GetTarget_done
    847     13 85 82 00     # rd_a0 rs1_t0 !8 addi              ; Get target address
    848 
    849     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    850     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    851     67 80 00 00     # rs1_ra jalr                       ; return
    852 
    853 :L ;StoreLabel
    854     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    855     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    856 
    857     13 85 0C 00     # rd_a0 rs1_s9 mv                   ; struct entry
    858     93 8C 8C 01     # rd_s9 rs1_s9 !24 addi             ; calloc
    859     23 34 65 01     # rs1_a0 rs2_s6 @8 sd               ; entry->target = ip
    860     23 30 95 00     # rs1_a0 rs2_s1 sd                  ; entry->next = jump_table
    861     93 04 05 00     # rd_s1 rs1_a0 mv                   ; jump_table = entry
    862     23 38 95 01     # rs1_a0 rs2_s9 @16 sd              ; entry->name = token
    863     93 85 0C 00     # rd_a1 rs1_s9 mv                   ; Write after struct
    864     $c EF 00 00 00  # rd_ra $consume_token jal          ; Collect string
    865     93 8C 05 00     # rd_s9 rs1_a1 mv                   ; update HEAP
    866 
    867     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    868     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    869     $1 6F 00 00 00  # $First_pass_loop jal              ; return
    870 
    871 ; fputc function
    872 ; Receives CHAR in a0
    873 ; Writes and returns number of bytes written in a0
    874 :t ;fputc
    875     13 01 01 FE     # rd_sp rs1_sp !-32 addi            ; allocate stack
    876     23 30 A1 00     # rs1_sp rs2_a0 sd                  ; protect a0
    877     23 34 11 00     # rs1_sp rs2_ra @8 sd               ; protect ra
    878     23 38 B1 00     # rs1_sp rs2_a1 @16 sd              ; protect a1
    879     23 3C C1 00     # rs1_sp rs2_a2 @24 sd              ; protect a2
    880 
    881     93 08 00 04     # rd_a7 !64 addi                    ; sys_write
    882     13 85 09 00     # rd_a0 rs1_s3 mv                   ; write to output
    883     93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    884     13 06 10 00     # rd_a2 !1 addi                     ; write 1 character
    885     73 00 00 00     # ecall                             ; syscall
    886 
    887     83 30 81 00     # rd_ra rs1_sp !8 ld                ; restore ra
    888     83 35 01 01     # rd_a1 rs1_sp !16 ld               ; restore a1
    889     03 36 81 01     # rd_a2 rs1_sp !24 ld               ; restore a2
    890     13 01 01 02     # rd_sp rs1_sp !32 addi             ; Deallocate stack
    891     67 80 00 00     # rs1_ra jalr                       ; return
    892 
    893 :F ;Fail
    894     ; Terminate program with 1 return code
    895     93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    896     13 05 10 00     # rd_a0 !1 addi                     ; Return code 1
    897     73 00 00 00     # ecall                             ; exit(1)
    898 # PROGRAM END
    899 
    900 :s ;scratch
    901     00 00 00 00
    902 
    903 #:ELF_end