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