boot2

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

hex1.hex0 (27107B)


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