boot2

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

hex1.hex0 (27080B)


      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 # :ELF_base ; (0x600000)
     19 7F 45 4C 46        ## e_ident[EI_MAG0-3] ELF's magic number
     20 
     21 02                 ## e_ident[EI_CLASS] Indicating 64 bit
     22 01                 ## e_ident[EI_DATA] Indicating little endianness
     23 01                 ## e_ident[EI_VERSION] Indicating original elf
     24 
     25 03                 ## e_ident[EI_OSABI] Set at 3 for Linux
     26 00                 ## e_ident[EI_ABIVERSION] Ignored for Statically linked executables
     27 
     28 00 00 00 00 00 00 00 ## e_ident[EI_PAD]
     29 02 00              ## e_type Indicating Executable
     30 F3 00              ## e_machine Indicating RISC-V
     31 01 00 00 00        ## e_version Indicating original elf
     32 
     33 78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address) # TODO
     34 40 00 00 00 00 00 00 00 ## e_phoff Address of program header table
     35 00 00 00 00 00 00 00 00 ## e_shoff Address of section header table
     36 
     37 00 00 00 00        ## e_flags
     38 40 00              ## e_ehsize Indicating our 64 Byte header
     39 
     40 38 00              ## e_phentsize size of a program header table
     41 01 00              ## e_phnum number of entries in program table
     42 
     43 00 00              ## e_shentsize size of a section header table
     44 00 00              ## e_shnum number of entries in section table
     45 
     46 00 00              ## e_shstrndx index of the section names
     47 
     48 ## Program Header
     49 #:ELF_program_headers
     50 01 00 00 00             ## p_type
     51 07 00 00 00             ## Flags
     52 00 00 00 00 00 00 00 00 ## p_offset
     53 
     54 00 00 60 00 00 00 00 00 ## p_vaddr
     55 00 00 60 00 00 00 00 00 ## p_physaddr
     56 
     57 C1 04 00 00 00 00 00 00 ## p_filesz
     58 C1 04 00 00 00 00 00 00 ## p_memsz
     59 
     60 01 00 00 00 00 00 00 00 ## Required alignment
     61 
     62 #:ELF_text
     63 
     64 ; Register use:
     65 ; s2: input fd
     66 ; s3: output fd
     67 ; s4: toggle
     68 ; s5: hold
     69 ; s6: ip
     70 ; s7: tempword
     71 ; s8: shiftregister
     72 
     73 ; Our main function
     74 # :_start ; (0x0600078)
     75 
     76     03 36 01 01     # rd_a2 rs1_sp !16 ld               ; Input file name
     77 
     78     ; Initialize globals
     79     13 0A F0 FF     # rd_s4 !-1 addi                    ; Toggle
     80     93 0A 00 00     # rd_s5 addi                        ; Hold
     81     13 0B 00 00     # rd_s6 addi                        ; Instruction Pointer
     82 
     83     ; Open input file and store FD in s2
     84     93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
     85     13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
     86     93 05 06 00     # rd_a1 rs1_a2 mv                   ; file name
     87     13 06 00 00     # rd_a2 addi                        ; read only
     88     73 00 00 00     # ecall                             ; syscall
     89     63 4C 05 40     # rs1_a0 @Fail bltz                 ; Error opening file
     90                     # +1048
     91     13 09 05 00     # rd_s2 rs1_a0 mv                   ; Save fd in for later
     92 
     93     ; Set default FD for output file to stdout
     94     93 09 10 00     # rd_s3 !1 addi
     95 
     96     ; If we only have 2 arguments, don't use the third (it's not set)
     97     93 02 20 00     # rd_t0 !2 addi
     98     03 35 01 00     # rd_a0 rs1_sp ld                   ; Get number of the args
     99     63 42 55 40     # rs1_a0 rs2_t0 @Fail blt           ; No input file provided
    100                     # +1028B
    101     63 00 55 02     # rs1_a0 rs2_t0 @after_open beq     ; No output file provided. Use stdout
    102                     # +32B
    103 
    104     ; Open output file and store the FD in s3
    105     93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
    106     13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
    107     83 35 81 01     # rd_a1 rs1_sp !24 ld               ; Output file (argument 3)
    108     13 06 10 24     # rd_a2 !00001101 addi              ; decimal 577
    109     ; O_TRUNC   00001000
    110     ; O_CREAT   00000100
    111     ; O_WRONLY  00000001
    112     ; OCTAL!
    113     93 06 00 1C     # rd_a3 !00700 addi                 ; Set read, write, execute permission on user
    114     ; S_IRWXU  00700
    115     ; OCTAL!
    116     73 00 00 00     # ecall                             ; syscall
    117     93 09 05 00     # rd_s3 rs1_a0 mv                   ; Save fd in for later
    118 
    119 # :after_open ; (0x06000D4)
    120     EF 00 40 03     # rd_ra $First_pass jal             ; First pass
    121                     # +52B
    122 
    123     ; Rewind input file
    124     93 08 E0 03     # rd_a7 !62 addi                    ; sys_lseek
    125     13 05 09 00     # rd_a0 rs1_s2 mv                   ; Input file descriptor
    126     93 05 00 00     # rd_a1 mv                          ; Set offset to zero
    127     13 06 00 00     # rd_a2 mv                          ; Set whence to zero
    128     73 00 00 00     # ecall                             ; syscall
    129 
    130     ; Initialize globals
    131     13 0A F0 FF     # rd_s4 !-1 addi                    ; Toggle
    132     93 0A 00 00     # rd_s5 addi                        ; Hold
    133     13 0B 00 00     # rd_s6 addi                        ; Instruction Pointer
    134     93 0B 00 00     # rd_s7 addi                        ; tempword
    135     13 0C 00 00     # rd_s8 addi                        ; Shift register
    136 
    137     EF 00 00 07     # rd_ra $Second_pass jal            ; Now do the second pass
    138                     # +112B
    139 
    140     6F 00 40 3A     # $Done jal                         ; We are done
    141                     # +392B
    142 
    143 ; First pass loop to determine addresses of labels
    144 # :First_pass ; (0x0600108)
    145     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    146     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    147 
    148 # :First_pass_loop ; (0x0600110)
    149     EF 00 C0 2D     # rd_ra $Read_byte jal              ; Get another byte
    150                     # +732B
    151 
    152     ; Deal with EOF
    153     13 03 C0 FF     # rd_t1 !-4 addi
    154     63 06 65 04     # rs1_a0 rs2_t1 @First_pass_done beq
    155                     # +76B
    156 
    157     ; Check for :
    158     13 03 A0 03     # rd_t1 !0x3a addi
    159     63 14 65 00     # rs1_a0 rs2_t1 @First_pass_0 bne
    160                     # +8B
    161     EF 00 C0 32     # rd_ra $StoreLabel jal             ; Store this label
    162                     # +812B
    163 
    164 # :First_pass_0 ; (0x0600128)
    165     ; Check for !
    166     13 03 10 02     # rd_t1 !0x21 addi
    167     63 08 65 02     # rs1_a0 rs2_t1 @Throwaway_token beq
    168                     # +48B
    169 
    170     ; Check for @
    171     13 03 00 04     # rd_t1 !0x40 addi
    172     63 04 65 02     # rs1_a0 rs2_t1 @Throwaway_token beq
    173                     # +40B
    174 
    175     ; Check for $
    176     13 03 40 02     # rd_t1 !0x24 addi
    177     63 00 65 02     # rs1_a0 rs2_t1 @Throwaway_token beq
    178                     # +32B
    179 
    180     ; Check for ~
    181     13 03 E0 07     # rd_t1 !0x7e addi
    182     63 0C 65 00     # rs1_a0 rs2_t1 @Throwaway_token beq
    183                     # +24B
    184 
    185     93 05 F0 FF     # rd_a1 !-1 addi                    ; write = false
    186     EF 00 C0 19     # rd_ra $DoByte jal                 ; Deal with everything else
    187                     # +412B
    188 
    189     13 03 C0 FF     # rd_t1 !-4 addi                    ; Deal with EOF
    190     63 08 65 00     # rs1_a0 rs2_t1 @First_pass_done beq
    191                     # +16B
    192 
    193     6F F0 9F FB     # $First_pass_loop jal              ; Keep looping
    194                     # -72B
    195 
    196 # :Throwaway_token ; (0x060015C)
    197     ; Deal with Pointer to label
    198     EF 00 00 29     # rd_ra $Read_byte jal              ; Drop the char
    199                     # +656B
    200     6F F0 1F FB     # $First_pass_loop jal              ; Loop again
    201                     # -80B
    202 
    203 # :First_pass_done ; (0x0600164)
    204     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    205     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    206     67 80 00 00     # rs1_ra jalr                       ; return
    207 
    208 # :Second_pass ; (0x0600170)
    209     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    210     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    211 
    212 # :Second_pass_loop ; (0x0600178)
    213     EF 00 40 27     # rd_ra $Read_byte jal              ; Read another byte
    214                     # +628B
    215 
    216     ; Deal with EOF
    217     13 03 C0 FF     # rd_t1 !-4 addi                    ; Deal with EOF
    218     63 0E 65 14     # rs1_a0 rs2_t1 @Second_pass_done beq
    219                     # +348B
    220 
    221     ; Drop the label
    222     13 03 A0 03     # rd_t1 !0x3a addi
    223     63 16 65 00     # rs1_a0 rs2_t1 @Second_pass_0 bne
    224                     # +12B
    225 
    226     EF 00 00 26     # rd_ra $Read_byte jal              ; Read the label
    227                     # +608B
    228     6F F0 9F FE     # $Second_pass_loop jal             ; Continue looping
    229                     # -24B
    230 
    231 # :Second_pass_0 ; (0x0600194)
    232     ; Check for !
    233     13 03 10 02     # rd_t1 !0x21 addi
    234     63 08 65 02     # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    235                     # +48B
    236 
    237     ; Check for @
    238     13 03 00 04     # rd_t1 !0x40 addi
    239     63 04 65 02     # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    240                     # +40B
    241 
    242     ; Check for $
    243     13 03 40 02     # rd_t1 !0x24 addi
    244     63 00 65 02     # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    245                     # +32B
    246 
    247     ; Check for ~
    248     13 03 E0 07     # rd_t1 !0x7e addi
    249     63 0C 65 00     # rs1_a0 rs2_t1 @UpdateShiftRegister beq
    250                     # +24B
    251 
    252     ; Deal with everything else
    253     93 05 00 00     # rd_a1 mv                          ; write = true
    254     EF 00 00 13     # rd_ra $DoByte jal                 ; Process our char
    255                     # +304B
    256 
    257     # Deal with EOF
    258     13 03 C0 FF     # rd_t1 !-4 addi
    259     63 0E 65 10     # rs1_a0 rs2_t1 @Second_pass_done beq ; We are done
    260                     # +284B
    261 
    262     6F F0 5F FB     # $Second_pass_loop jal             ; continue looping
    263                     # -76B
    264 
    265 # :UpdateShiftRegister ; (0x06001C8)
    266     93 05 05 00     # rd_a1 rs1_a0 mv                   ; Store label prefix
    267     EF 00 C0 25     # rd_ra $Get_table_target jal       ; Get target
    268                     # +604B
    269     03 35 05 00     # rd_a0 rs1_a0 ld                   ; Dereference pointer
    270     33 05 65 41     # rd_a0 rs1_a0 rs2_s6 sub           ; target - ip
    271 
    272     ; Check for !
    273     13 03 10 02     # rd_t1 !0x21 addi
    274     63 80 65 02     # rs1_a1 rs2_t1 @UpdateShiftRegister_I beq
    275                     # +32B
    276 
    277     ; Check for @
    278     13 03 00 04     # rd_t1 !0x40 addi
    279     63 8A 65 02     # rs1_a1 rs2_t1 @UpdateShiftRegister_B beq
    280                     # +52B
    281 
    282     ; Check for $
    283     13 03 40 02     # rd_t1 !0x24 addi
    284     63 8A 65 06     # rs1_a1 rs2_t1 @UpdateShiftRegister_J beq
    285                     # +116B
    286 
    287     ; Check for ~
    288     13 03 E0 07     # rd_t1 !0x7e addi
    289     63 88 65 0A     # rs1_a1 rs2_t1 @UpdateShiftRegister_U beq
    290                     # +176B
    291 
    292     6F F0 1F F8     # $Second_pass_loop jal             ; continue looping
    293                     # -128B
    294 
    295 # :UpdateShiftRegister_I ; (0x06001FC)
    296     ; Corresponds to RISC-V I format
    297     13 05 45 00     # rd_a0 rs1_a0 !4 addi              ; add 4 due to this being 2nd part of auipc combo
    298 
    299     37 13 00 00     # rd_t1 ~0xfff lui                  ; load higher bits
    300     1B 03 F3 FF     # rd_t1 rs1_t1 !0xfff addiw
    301     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; (value & 0xfff)
    302     93 1B 43 01     # rd_s7 rs1_t1 rs2_x20 slli         ; tempword = (value & 0xfff) << 20
    303     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    304 
    305     6F F0 5F F6     # $Second_pass_loop jal             ; continue looping
    306                     # -156B
    307 
    308 # :UpdateShiftRegister_B ; (0x0600218)
    309     ; Corresponds to RISC-V B format
    310 
    311     ; tempword = ((value & 0x1e) << 7)            ; imm[4:1]
    312     ;          | ((value & 0x7e0) << (31 - 11))   ; imm[10:5]
    313     ;          | ((value & 0x800) >> 4)           ; imm[11]
    314     ;          | ((value & 0x1000) << (31 - 12))  ; imm[12]
    315 
    316     13 03 E0 01     # rd_t1 !0x1e addi
    317     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x1e
    318     93 12 73 00     # rd_t0 rs1_t1 rs2_x7 slli          ; tempword = (value & 0x1e) << 7
    319 
    320     13 03 00 7E     # rd_t1 !0x7e0 addi
    321     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x7e0
    322     13 13 43 01     # rd_t1 rs1_t1 rs2_x20 slli         ; (value & 0x7e0) << (31 - 11)
    323     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    324 
    325     37 13 00 00     # rd_t1 ~0x800 lui                  ; load higher bits
    326     1B 03 03 80     # rd_t1 rs1_t1 !0x800 addiw
    327     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x800
    328     13 53 43 00     # rd_t1 rs1_t1 rs2_x4 srli          ; (value & 0x800) >> 4
    329     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    330 
    331     37 13 00 00     # rd_t1 ~0x1000 lui                 ; load higher bits
    332     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x1000
    333     13 13 33 01     # rd_t1 rs1_t1 rs2_x19 slli         ; (value & 0x1000) << (31 - 12)
    334     B3 EB 62 00     # rd_s7 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    335 
    336     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    337 
    338     6F F0 DF F1     # $Second_pass_loop jal             ; continue looping
    339                     # -228B
    340 
    341 # :UpdateShiftRegister_J ; (0x0600260)
    342     ; Corresponds to RISC-V J format
    343 
    344     ; tempword = ((value & 0x7fe) << (30 - 10))    ; imm[10:1]
    345     ;          | ((value & 0x800) << (20 - 11))    ; imm[11]
    346     ;          | ((value & 0xff000))               ; imm[19:12]
    347     ;          | ((value & 0x100000) << (31 - 20)) ; imm[20]
    348 
    349     13 03 E0 7F     # rd_t1 !0x7fe addi
    350     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x7fe
    351     93 12 43 01     # rd_t0 rs1_t1 rs2_x20 slli         ; tempword = (value & 0x7fe) << 20
    352 
    353     37 13 00 00     # rd_t1 ~0x800 lui                  ; load higher bits
    354     1B 03 03 80     # rd_t1 rs1_t1 !0x800 addiw
    355     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x800
    356     13 13 93 00     # rd_t1 rs1_t1 rs2_x9 slli          ; (value & 0x800) << (20 - 11)
    357     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    358 
    359     37 F3 0F 00     # rd_t1 ~0xff000 lui                ; load higher bits
    360     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xff000
    361     B3 E2 62 00     # rd_t0 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    362 
    363     37 03 10 00     # rd_t1 ~0x100000 lui               ; load higher bits
    364     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0x100000
    365     13 13 B3 00     # rd_t1 rs1_t1 rs2_x11 slli         ; (value & 0x100000) << (31 - 20)
    366     B3 EB 62 00     # rd_s7 rs1_t0 rs2_t1 or            ; logical or with the previous expression
    367 
    368     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    369 
    370     6F F0 9F ED     # $Second_pass_loop jal             ; continue looping
    371                     # -296B
    372 
    373 # :UpdateShiftRegister_U ; (0x06002A4)
    374     ; Corresponds to RISC-V U format
    375     ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension
    376 
    377     B7 12 00 00     # rd_t0 ~0x800 lui                  ; load higher bits
    378     9B 82 02 80     # rd_t0 rs1_t0 !0x800 addiw
    379     37 13 00 00     # rd_t1 ~0xfff lui                  ; load higher bits
    380     1B 03 F3 FF     # rd_t1 rs1_t1 !0xfff addiw
    381 
    382     ; We are outside 31-bit that ~ can normally load
    383     B7 03 10 00     # rd_t2 ~0x100000 lui               ; load 0xfffff000
    384     9B 83 F3 FF     # rd_t2 rs1_t2 !-1 addiw            ; load 0xfffff000
    385     93 93 C3 00     # rd_t2 rs1_t2 rs2_x12 slli         ; load 0xfffff000
    386     33 73 65 00     # rd_t1 rs1_a0 rs2_t1 and           ; value & 0xfff
    387     B3 7B 75 00     # rd_s7 rs1_a0 rs2_t2 and           ; value & 0xfffff000
    388     63 46 53 00     # rs1_t1 rs2_t0 @UpdateShiftRegister_U_small blt
    389                     # +12B
    390 
    391     # Deal with sign extension: add 0x1000
    392     B7 12 00 00     # rd_t0 ~0x1000 lui                 ; load higher bits
    393     BB 8B 72 01     # rd_s7 rs1_t0 rs2_s7 addw          ; (value & 0xfffff000) + 0x1000
    394 
    395 # :UpdateShiftRegister_U_small ; (0x06002D4)
    396     33 4C 7C 01     # rd_s8 rs1_s8 rs2_s7 xor           ; shiftregister = shiftregister ^ tempword
    397 
    398     6F F0 1F EA     # $Second_pass_loop jal             ; continue looping
    399                     # -352B
    400 
    401 # :Second_pass_done ; (0x06002DC)
    402     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    403     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    404     67 80 00 00     # rs1_ra jalr                       ; return
    405 
    406 
    407 ; DoByte function
    408 ; Receives:
    409 ;   character in a0
    410 ;   bool write in a1
    411 ; Does not return anything
    412 # :DoByte ; (0x06002E8)
    413     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    414     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    415 
    416     EF 00 00 05     # rd_ra $hex jal                    ; Process hex, store it in a6
    417                     # +80B
    418 
    419     63 40 08 04     # rs1_a6 @DoByte_Done bltz          ; Deal with EOF and unrecognized characters
    420                     # +64B
    421 
    422     63 1A 0A 02     # rs1_s4 @DoByte_NotToggle bnez     ; Check if toggle is set
    423                     # +56B
    424 
    425     ; toggle = true
    426     63 92 05 02     # rs1_a1 @DoByte_1 bnez             ; check if we have to write
    427                     # +36B
    428 
    429     ; write = true
    430     ; We calculate (hold * 16) + hex(c) ^ sr_nextb()
    431     ; First, calculate new shiftregister
    432     93 02 F0 0F     # rd_t0 !0xff addi
    433     B3 72 5C 00     # rd_t0 rs1_s8 rs2_t0 and           ; sr_nextb = shiftregister & 0xff
    434     13 5C 8C 00     # rd_s8 rs1_s8 rs2_x8 srli          ; shiftregister >> 8
    435 
    436     B3 C2 02 01     # rd_t0 rs1_t0 rs2_a6 xor           ; hex(c) ^ sr_nextb
    437     13 93 4A 00     # rd_t1 rs1_s5 rs2_x4 slli          ; hold << 4
    438     33 85 62 00     # rd_a0 rs1_t0 rs2_t1 add           ; (hold << 4) + hex(c) ^ sr_nextb()
    439     EF 00 40 15     # rd_ra $fputc jal                  ; print it
    440                     # +340B
    441     63 0C 05 18     # rs1_a0 @Fail beqz                 ; Fail if nothing was written
    442                     # +408B
    443 
    444 # :DoByte_1 ; (0x0600320)
    445     13 0B 1B 00     # rd_s6 rs1_s6 !1 addi              ; Increment IP
    446     93 0A 00 00     # rd_s5 mv                          ; hold = 0
    447     6F 00 80 00     # $DoByte_FlipToggle jal            ; return
    448                     # +8B
    449 
    450 # :DoByte_NotToggle ; (0x060032C)
    451     93 0A 08 00     # rd_s5 rs1_a6 mv                   ; hold = hex(c)
    452 
    453 # :DoByte_FlipToggle ; (0x0600330)
    454     13 4A FA FF     # rd_s4 rs1_s4 not                  ; Flip the toggle
    455 
    456 # :DoByte_Done ; (0x0600334)
    457     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    458     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    459     67 80 00 00     # rs1_ra jalr                       ; return
    460 
    461 ; Convert ASCII hex characters into binary representation, e.g. 'a' -> 0xA
    462 ; Receives:
    463 ;   character in a0
    464 ; Returns:
    465 ;   a6 with character's hex value.
    466 # :hex ; (0x0600340)
    467     13 01 01 FF     # rd_sp rs1_sp !-16 addi            ; Allocate stack
    468     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    469     23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    470 
    471     ; Deal with EOF
    472     13 03 C0 FF     # rd_t1 !-4 addi
    473     63 06 65 08     # rs1_a0 rs2_t1 @hex_return beq
    474                     # +140B
    475 
    476     ; deal with line comments starting with #
    477     13 03 30 02     # rd_t1 !0x23 addi
    478     63 06 65 06     # rs1_a0 rs2_t1 @ascii_comment beq ; a0 eq to '#'
    479                     # +108B
    480 
    481     ; deal with line comments starting with ;
    482     13 03 B0 03     # rd_t1 !0x3b addi
    483     63 02 65 06     # rs1_a0 rs2_t1 @ascii_comment beq  ; a0 eq to ';'
    484                     # +100B
    485 
    486     ; deal all ascii less than 0
    487     13 03 00 03     # rd_t1 !0x30 addi
    488     63 4A 65 04     # rs1_a0 rs2_t1 @ascii_other blt
    489                     # +84B
    490 
    491     ; deal with 0-9
    492     13 03 A0 03     # rd_t1 !0x3a addi
    493     63 44 65 02     # rs1_a0 rs2_t1 @ascii_num blt
    494                     # +40B
    495 
    496     ; deal with all ascii less than A
    497     13 03 10 04     # rd_t1 !0x41 addi
    498     63 42 65 04     # rs1_a0 rs2_t1 @ascii_other blt
    499                     # +68B
    500 
    501     ; deal with A-F
    502     13 03 70 04     # rd_t1 !0x47 addi
    503     63 48 65 02     # rs1_a0 rs2_t1 @ascii_high blt
    504                     # +48B
    505 
    506     ; deal with all ascii less than a
    507     13 03 10 06     # rd_t1 !0x61 addi
    508     63 4A 65 02     # rs1_a0 rs2_t1 @ascii_other blt
    509                     # +52B
    510 
    511     ; deal with a-f
    512     13 03 70 06     # rd_t1 !0x67 addi
    513     63 4A 65 00     # rs1_a0 rs2_t1 @ascii_low blt
    514                     # +20B
    515 
    516     ; The rest that remains needs to be ignored
    517     6F 00 80 02     # $ascii_other jal
    518                     # +40B
    519 
    520 # :ascii_num ; (0x0600398)
    521     13 03 00 03     # rd_t1 !0x30 addi                  ; '0' -> 0
    522     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    523     6F 00 C0 03     # $hex_return jal                   ; return
    524                     # +60B
    525 # :ascii_low ; (0x06003A4)
    526     13 03 70 05     # rd_t1 !0x57 addi                  ; 'a' -> 0xA
    527     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    528     6F 00 00 03     # $hex_return jal                   ; return
    529                     # +48B
    530 # :ascii_high ; (0x06003B0)
    531     13 03 70 03     # rd_t1 !0x37 addi                  ; 'A' -> 0xA
    532     33 08 65 40     # rd_a6 rs1_a0 rs2_t1 sub
    533     6F 00 40 02 # $hex_return jal                       ; return
    534                     # +36B
    535 # :ascii_other ; (0x06003BC)
    536     13 08 F0 FF     # rd_a6 !-1 addi                    ; Return -1
    537     6F 00 C0 01     # $hex_return jal                   ; return
    538                     # +28B
    539 # :ascii_comment ; (0x06003C4)                          ; Read the comment until newline
    540     EF 00 80 02     # rd_ra $Read_byte jal
    541                     # +40B
    542     13 03 D0 00     # rd_t1 !0xd addi                   ; CR
    543     63 06 65 00     # rs1_a0 rs2_t1 @ascii_comment_cr beq
    544                     # +12B
    545     13 03 A0 00     # rd_t1 !0xa addi                   ; LF
    546     E3 18 65 FE     # rs1_a0 rs2_t1 @ascii_comment bne  ; Keep reading comment
    547                     # -16B
    548 # :ascii_comment_cr ; (0x06003D8)
    549     13 08 F0 FF     # rd_a6 !-1 addi                    ; Return -1
    550 # :hex_return ; (0x06003DC)
    551     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    552     83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    553     13 01 01 01     # rd_sp rs1_sp !16 addi             ; Deallocate stack
    554     67 80 00 00     # rs1_ra jalr                       ; return
    555 
    556 ; Read byte into a0
    557 # :Read_byte ; (0x06003EC)
    558     13 01 01 FF     # rd_sp rs1_sp !-16 addi            ; Allocate stack
    559     23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    560 
    561     93 08 F0 03     # rd_a7 !63 addi                    ; sys_read
    562     13 05 09 00     # rd_a0 rs1_s2 mv                   ; File descriptor
    563     93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address for buffer
    564     13 00 00 00     # nop                               ; no-op
    565     13 06 10 00     # rd_a2 !1 addi                     ; Size of what we want to read
    566     73 00 00 00     # ecall                             ; syscall
    567 
    568     63 06 05 00     # rs1_a0 @Read_byte_1 beqz          ; Deal with EOF
    569                     # +12B
    570     03 85 05 00     # rd_a0 rs1_a1 lb                   ; Dereference pointer
    571 
    572     6F 00 80 00     # $Read_byte_done jal               ; return
    573                     # +8B
    574 
    575 # :Read_byte_1 ; (0x0600418)
    576     13 05 C0 FF     # rd_a0 !-4 addi                    ; Put EOF in a0
    577 # :Read_byte_done ; (0x060041C)
    578     83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    579     13 01 01 01     # rd_sp rs1_sp !16 addi             ; Deallocate stack
    580     67 80 00 00     # rs1_ra jalr                       ; return
    581 
    582 ; Reads a byte and calculates table address
    583 ; Returns a pointer in a0
    584 # :Get_table_target ; (0x0600428)
    585     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    586     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    587 
    588     EF F0 DF FB     # rd_ra $Read_byte jal              ; Get single char label
    589                     # -68B
    590     13 15 35 00     # rd_a0 rs1_a0 rs2_x3 slli          ; Each label in table takes 8 bytes to store
    591     97 02 00 00     # rd_t0 ~table auipc                ; Load address of table
    592     93 82 82 08     # rd_t0 rs1_t0 !table addi          ; into register t0
    593                     # +136B
    594     33 05 55 00     # rd_a0 rs1_a0 rs2_t0 add           ; Calculate offset
    595 
    596     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    597     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    598     67 80 00 00     # rs1_ra jalr                       ; return
    599 
    600 # :StoreLabel ; (0x0600450)
    601     13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; Allocate stack
    602     23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    603 
    604     EF F0 1F FD     # rd_ra $Get_table_target jal
    605                     # -48B
    606     23 30 65 01     # rs1_a0 rs2_s6 sd                  ; Store ip into table target
    607 
    608     83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    609     13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    610     67 80 00 00     # rs1_ra jalr                       ; return
    611 
    612 ; fputc function
    613 ; Receives CHAR in a0
    614 ; Writes and returns number of bytes written in a0
    615 # :fputc ; (0x060046C)
    616     13 01 01 FE     # rd_sp rs1_sp !-32 addi            ; allocate stack
    617     23 30 A1 00     # rs1_sp rs2_a0 sd                  ; protect a0
    618     23 34 11 00     # rs1_sp rs2_ra @8 sd               ; protect ra
    619     23 38 B1 00     # rs1_sp rs2_a1 @16 sd              ; protect a1
    620     23 3C C1 00     # rs1_sp rs2_a2 @24 sd              ; protect a2
    621 
    622     93 08 00 04     # rd_a7 !64 addi                    ; sys_write
    623     13 85 09 00     # rd_a0 rs1_s3 mv                   ; write to output
    624     93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    625     13 06 10 00     # rd_a2 !1 addi                     ; write 1 character
    626     73 00 00 00     # ecall                             ; syscall
    627 
    628     83 30 81 00     # rd_ra rs1_sp !8 ld                ; restore ra
    629     83 35 01 01     # rd_a1 rs1_sp !16 ld               ; restore a1
    630     03 36 81 01     # rd_a2 rs1_sp !24 ld               ; restore a2
    631     13 01 01 02     # rd_sp rs1_sp !32 addi             ; Deallocate stack
    632     67 80 00 00     # rs1_ra jalr                       ; return
    633 
    634 # :Done ; (0x06004A8)
    635     ; Terminate program with 0 return code
    636     93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    637     13 05 00 00     # rd_a0 mv                          ; Return code 0
    638     73 00 00 00     # ecall                             ; exit(0)
    639 # :Fail ; (0x06004B4)
    640     ; Terminate program with 1 return code
    641     93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    642     13 05 10 00     # rd_a0 !1 addi                     ; Return code 1
    643     73 00 00 00     # ecall                             ; exit(1)
    644 # PROGRAM END
    645 
    646 # :table; (0x06004C0)
    647     00