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