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