M0.hex2 (65307B)
1 ## Copyright (C) 2017 Jeremiah Orians 2 ## Copyright (C) 2021 Andrius Štikonas 3 ## Copyright (C) 2021 Gabriel Wicki 4 ## This file is part of stage0. 5 ## 6 ## stage0 is free software: you can redistribute it and/or modify 7 ## it under the terms of the GNU General Public License as published by 8 ## the Free Software Foundation, either version 3 of the License, or 9 ## (at your option) any later version. 10 ## 11 ## stage0 is distributed in the hope that it will be useful, 12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 ## GNU General Public License for more details. 15 ## 16 ## You should have received a copy of the GNU General Public License 17 ## along with stage0. If not, see <http://www.gnu.org/licenses/>. 18 19 ; Where the ELF Header is going to hit 20 ; Simply jump to _start 21 ; Our main function 22 23 ; Register use: 24 ; s1: malloc pointer 25 ; s2: input fd 26 ; s3: output fd 27 ; s4: struct HEAD 28 ; s5: protected char 29 ; s6: scratch 30 31 ; Struct format: (size 16) 32 ; NEXT => 0 ; Next element in linked list 33 ; TYPE => 4 ; Token type 34 ; TEXT => 8 35 ; EXPRESSION => 12 36 37 ; Types 38 ; None => 0 39 ; MACRO => 1 40 ; STRING => 2 41 42 :_start 43 # rd_s4 addi 44 .000A0000 13000000 45 46 # rd_a2 rs1_sp !8 lw ; Input file name 47 .00060000 .00000100 .00008000 03200000 48 49 ; Open input file and store FD in s2 50 # rd_a7 !56 addi ; sys_openat 51 .80080000 .00008003 13000000 52 # rd_a0 !-100 addi ; AT_FDCWD 53 .00050000 .0000C0F9 13000000 54 # rd_a1 rs1_a2 mv ; file name 55 .80050000 .00000600 13000000 56 # rd_a2 addi ; read only 57 .00060000 13000000 58 # ecall ; syscall 59 73000000 60 # rs1_a0 @Fail bltz ; Error opening file 61 .00000500 @Fail 63400000 62 # rd_s2 rs1_a0 mv ; Save fd in for later 63 .00090000 .00000500 13000000 64 65 ; Set default FD for output file to stdout 66 # rd_s3 !1 addi 67 .80090000 .00001000 13000000 68 69 ; If we only have 2 arguments, don't use the third (it's not set) 70 # rd_t0 !2 addi 71 .80020000 .00002000 13000000 72 # rd_a0 rs1_sp lw ; Get number of the args 73 .00050000 .00000100 03200000 74 # rs1_a0 rs2_t0 @Fail blt ; No input file provided 75 .00000500 .00005000 @Fail 63400000 76 # rs1_a0 rs2_t0 @after_open beq ; No output file provided. Use stdout 77 .00000500 .00005000 @after_open 63000000 78 79 ; Open output file and store the FD in s3 80 # rd_a7 !56 addi ; sys_openat 81 .80080000 .00008003 13000000 82 # rd_a0 !-100 addi ; AT_FDCWD 83 .00050000 .0000C0F9 13000000 84 # rd_a1 rs1_sp !12 lw ; Output file (argument 3) 85 .80050000 .00000100 .0000C000 03200000 86 # rd_a2 !577 addi ; octal 00001101 87 .00060000 .00001024 13000000 88 ; O_TRUNC 00001000 89 ; O_CREAT 00000100 90 ; O_WRONLY 00000001 91 ; OCTAL! 92 # rd_a3 !384 addi ; Set read and write permission on user 93 .80060000 .00000018 13000000 94 # ecall ; syscall 95 73000000 96 # rd_s3 rs1_a0 mv ; Save fd in for later 97 .80090000 .00000500 13000000 98 99 :after_open 100 ; Prepare heap memory 101 # rd_a7 !214 addi ; sys_brk 102 .80080000 .0000600D 13000000 103 # rd_a0 addi ; Get current brk 104 .00050000 13000000 105 # ecall ; syscall 106 73000000 107 # rd_s1 rs1_a0 mv ; Set our malloc pointer 108 .80040000 .00000500 13000000 109 110 # rd_a0 !512 addi ; Allocate scratch 111 .00050000 .00000020 13000000 112 # rd_ra $malloc jal ; Get S pointer 113 .80000000 $malloc 6F000000 114 # rd_s6 rs1_a0 mv ; Save scratch pointer 115 .000B0000 .00000500 13000000 116 117 # rd_ra $Tokenize_Line jal ; Get all lines 118 .80000000 $Tokenize_Line 6F000000 119 # rd_a0 rs1_s4 mv ; Prepare for Reverse_List 120 .00050000 .00000A00 13000000 121 # rd_ra $Reverse_List jal ; Correct order 122 .80000000 $Reverse_List 6F000000 123 # rd_s4 rs1_a0 mv ; Update HEAD 124 .000A0000 .00000500 13000000 125 # rd_ra $Identify_Macros jal ; Find the DEFINEs 126 .80000000 $Identify_Macros 6F000000 127 # rd_ra $Line_Macro jal ; Apply the DEFINEs 128 .80000000 $Line_Macro 6F000000 129 # rd_ra $Process_String jal ; Handle strings 130 .80000000 $Process_String 6F000000 131 # rd_ra $Eval_Immediates jal ; Handle numbers 132 .80000000 $Eval_Immediates 6F000000 133 # rd_ra $Preserve_Other jal ; Collect the remaining 134 .80000000 $Preserve_Other 6F000000 135 # rd_ra $Print_Hex jal ; Output our results 136 .80000000 $Print_Hex 6F000000 137 138 ; Terminate program with 0 return code 139 # rd_a7 !93 addi ; sys_exit 140 .80080000 .0000D005 13000000 141 # rd_a0 mv ; Return code 0 142 .00050000 13000000 143 # ecall ; exit(0) 144 73000000 145 146 147 ; Tokenize_Line Function 148 ; Using input file s2 and Head s4 149 ; Creates a linked list of structs 150 ; Uses a1 for in_set strings, a2 for Int C and a3 for Struct Token* p 151 :Tokenize_Line 152 # rd_sp rs1_sp !-4 addi ; allocate stack 153 .00010000 .00000100 .0000C0FF 13000000 154 # rs1_sp rs2_ra sw ; protect ra 155 .00000100 .00001000 23200000 156 157 :restart 158 # rd_ra $fgetc jal ; Read a char 159 .80000000 $fgetc 6F000000 160 # rd_t0 !-4 addi ; EOF 161 .80020000 .0000C0FF 13000000 162 # rs1_a0 rs2_t0 @done beq ; File is collected 163 .00000500 .00005000 @done 63000000 164 165 # rd_a2 rs1_a0 mv ; Protect C 166 .00060000 .00000500 13000000 167 168 # rd_a1 ~comments auipc ; Get pointer to "#;" 169 .80050000 ~comments 17000000 170 # rd_a1 rs1_a1 !comments addi ; Get pointer to "#;" 171 .80050000 .00800500 !comments 13000000 172 # rd_ra $In_Set jal ; Check for comments 173 .80000000 $In_Set 6F000000 174 # rd_t0 !1 addi ; If comment 175 .80020000 .00001000 13000000 176 # rs1_a0 rs2_t0 @Purge_LineComment beq ; try again 177 .00000500 .00005000 @Purge_LineComment 63000000 178 179 # rd_a0 rs1_a2 mv ; Put C in place for check 180 .00050000 .00000600 13000000 181 # rd_a1 ~terminators auipc ; Get pointer to "\n\t " 182 .80050000 ~terminators 17000000 183 # rd_a1 rs1_a1 !terminators addi ; Get pointer to "\n\t " 184 .80050000 .00800500 !terminators 13000000 185 # rd_ra $In_Set jal ; Check for terminators 186 .80000000 $In_Set 6F000000 187 # rd_t0 !1 addi ; If terminator 188 .80020000 .00001000 13000000 189 # rs1_a0 rs2_t0 @restart beq ; try again 190 .00000500 .00005000 @restart 63000000 191 192 # rd_a0 !16 addi ; malloc struct P 193 .00050000 .00000001 13000000 194 # rd_ra $malloc jal ; Get pointer to P 195 .80000000 $malloc 6F000000 196 # rd_a3 rs1_a0 mv ; Protect P 197 .80060000 .00000500 13000000 198 # rs1_a3 rs2_s4 sw ; P->NEXT = HEAD 199 .00800600 .00004001 23200000 200 # rd_s4 rs1_a3 mv ; HEAD = P 201 .000A0000 .00800600 13000000 202 203 # rd_a0 rs1_a2 mv ; Put C in place for check 204 .00050000 .00000600 13000000 205 # rd_a1 ~string_char auipc ; Get pointer to "\"'" 206 .80050000 ~string_char 17000000 207 # rd_a1 rs1_a1 !string_char addi ; Get pointer to "\"'" 208 .80050000 .00800500 !string_char 13000000 209 # rd_ra $In_Set jal ; Check for string char 210 .80000000 $In_Set 6F000000 211 # rd_t0 !1 addi ; If string char 212 .80020000 .00001000 13000000 213 # rs1_a0 rs2_t0 @Store_String beq ; Get string 214 .00000500 .00005000 @Store_String 63000000 215 216 # rd_ra $Store_Atom jal ; Get whole token 217 .80000000 $Store_Atom 6F000000 218 # $restart jal 219 $restart 6F000000 220 221 :done 222 # rd_ra rs1_sp lw ; restore ra 223 .80000000 .00000100 03200000 224 # rd_sp rs1_sp !4 addi ; deallocate stack 225 .00010000 .00000100 .00004000 13000000 226 # rs1_ra jalr ; return 227 .00800000 67000000 228 229 230 ; In_Set function 231 ; Receives char C in a0 and Char* in a1 232 ; Returns 1 if true, zero if false in a0 233 :In_Set 234 # rd_sp rs1_sp !-4 addi ; allocate stack 235 .00010000 .00000100 .0000C0FF 13000000 236 # rs1_sp rs2_a1 sw ; protect a1 237 .00000100 .0000B000 23200000 238 239 :In_Set_loop 240 # rd_t0 rs1_a1 lbu ; Read char 241 .80020000 .00800500 03400000 242 # rs1_a0 rs2_t0 @In_Set_True beq ; Return true 243 .00000500 .00005000 @In_Set_True 63000000 244 # rs1_t0 @In_Set_False beqz ; Return False if NULL 245 .00800200 @In_Set_False 63000000 246 # rd_a1 rs1_a1 !1 addi ; s = s + 1 247 .80050000 .00800500 .00001000 13000000 248 # $In_Set_loop jal ; Continue looping 249 $In_Set_loop 6F000000 250 251 :In_Set_True 252 # rd_a0 !1 addi ; Set True 253 .00050000 .00001000 13000000 254 # rd_a1 rs1_sp lw ; restore a1 255 .80050000 .00000100 03200000 256 # rd_sp rs1_sp !4 addi ; deallocate stack 257 .00010000 .00000100 .00004000 13000000 258 # rs1_ra jalr ; return 259 .00800000 67000000 260 261 :In_Set_False 262 # rd_a0 mv ; Set False 263 .00050000 13000000 264 # rd_a1 rs1_sp lw ; restore a1 265 .80050000 .00000100 03200000 266 # rd_sp rs1_sp !4 addi ; deallocate stack 267 .00010000 .00000100 .00004000 13000000 268 # rs1_ra jalr ; return 269 .00800000 67000000 270 271 272 ; Purge_LineComment function 273 ; Reads chars until LF and jumps to restart 274 :Purge_LineComment 275 # rd_ra $fgetc jal ; Get a char 276 .80000000 $fgetc 6F000000 277 # rd_t0 !10 addi ; While not LF 278 .80020000 .0000A000 13000000 279 # rs1_a0 rs2_t0 @Purge_LineComment bne ; Keep reading 280 .00000500 .00005000 @Purge_LineComment 63100000 281 # $restart jal 282 $restart 6F000000 283 284 285 ; Store_String Function 286 ; Receives C in a2, HEAD in a3 and Input file in s2 287 ; Uses a1 for terminator, a2 for C and a3 for string 288 :Store_String 289 # rd_sp rs1_sp !-12 addi ; allocate stack 290 .00010000 .00000100 .000040FF 13000000 291 # rs1_sp rs2_a1 sw ; protect a1 292 .00000100 .0000B000 23200000 293 # rs1_sp rs2_a2 @4 sw ; protect a2 294 .00000100 .0000C000 .00020000 23200000 295 # rs1_sp rs2_a3 @8 sw ; protect a3 296 .00000100 .0000D000 .00040000 23200000 297 298 # rd_a0 !2 addi ; Using TYPE STRING 299 .00050000 .00002000 13000000 300 # rs1_a3 rs2_a0 @4 sw ; HEAD->TYPE = STRING 301 .00800600 .0000A000 .00020000 23200000 302 # rd_a1 rs1_a2 mv ; Protect terminator 303 .80050000 .00000600 13000000 304 # rd_a3 rs1_s6 mv ; Protect string pointer 305 .80060000 .00000B00 13000000 306 :Store_String_Loop 307 # rs1_a3 rs2_a2 sb ; write byte 308 .00800600 .0000C000 23000000 309 # rd_ra $fgetc jal ; read next char 310 .80000000 $fgetc 6F000000 311 # rd_a2 rs1_a0 mv ; Update C 312 .00060000 .00000500 13000000 313 # rd_a3 rs1_a3 !1 addi ; STRING = STRING + 1 314 .80060000 .00800600 .00001000 13000000 315 # rs1_a1 rs2_a2 @Store_String_Loop bne ; Keep looping unless we hit terminator 316 .00800500 .0000C000 @Store_String_Loop 63100000 317 318 # rd_a0 rs1_s6 mv ; Prepare the string in scratch 319 .00050000 .00000B00 13000000 320 # rd_ra $string_length jal ; Calculate length 321 .80000000 $string_length 6F000000 322 # rd_a0 rs1_a0 !1 addi ; Add 1 for 0 terminator 323 .00050000 .00000500 .00001000 13000000 324 # rd_ra $malloc jal ; Allocate memory 325 .80000000 $malloc 6F000000 326 # rd_a3 rs1_sp !8 lw ; restore a3 (HEAD) 327 .80060000 .00000100 .00008000 03200000 328 # rs1_a3 rs2_a0 @8 sw ; HEAD->TEXT = STRING 329 .00800600 .0000A000 .00040000 23200000 330 # rd_ra $copy_string jal ; Copy the string 331 .80000000 $copy_string 6F000000 332 333 # rd_a1 rs1_sp lw ; restore a1 334 .80050000 .00000100 03200000 335 # rd_a2 rs1_sp !4 lw ; restore a2 336 .00060000 .00000100 .00004000 03200000 337 # rd_sp rs1_sp !12 addi ; deallocate stack 338 .00010000 .00000100 .0000C000 13000000 339 # $restart jal 340 $restart 6F000000 341 342 ; copy_string function 343 ; Receives target in a0, and scratch s6 for source 344 ; Uses a0, for target string T, a1 for C, a2 for source string S 345 ; Returns nothing 346 :copy_string 347 # rd_sp rs1_sp !-12 addi ; allocate stack 348 .00010000 .00000100 .000040FF 13000000 349 # rs1_sp rs2_ra sw ; protect ra 350 .00000100 .00001000 23200000 351 # rs1_sp rs2_a1 @4 sw ; protect a1 352 .00000100 .0000B000 .00020000 23200000 353 # rs1_sp rs2_a2 @8 sw ; protect a2 354 .00000100 .0000C000 .00040000 23200000 355 356 # rd_a2 rs1_s6 mv ; Get S 357 .00060000 .00000B00 13000000 358 359 :copy_string_loop 360 # rd_a1 rs1_a2 lbu ; S[0] 361 .80050000 .00000600 03400000 362 # rs1_a1 @copy_string_done beqz ; Check if we are done 363 .00800500 @copy_string_done 63000000 364 365 # rs1_a0 rs2_a1 sb ; Copy char 366 .00000500 .0000B000 23000000 367 # rd_a2 rs1_a2 !1 addi ; S = S + 1 368 .00060000 .00000600 .00001000 13000000 369 # rd_a0 rs1_a0 !1 addi ; T = T + 1 370 .00050000 .00000500 .00001000 13000000 371 # $copy_string_loop jal ; Keep going 372 $copy_string_loop 6F000000 373 374 :copy_string_done 375 # rd_ra $ClearScratch jal ; Clear scratch 376 .80000000 $ClearScratch 6F000000 377 378 # rd_ra rs1_sp lw ; restore ra 379 .80000000 .00000100 03200000 380 # rd_a1 rs1_sp !4 lw ; restore a1 381 .80050000 .00000100 .00004000 03200000 382 # rd_a2 rs1_sp !8 lw ; restore a2 383 .00060000 .00000100 .00008000 03200000 384 # rd_sp rs1_sp !12 addi ; deallocate stack 385 .00010000 .00000100 .0000C000 13000000 386 # ret 387 67800000 388 389 390 ; Zero scratch area 391 :ClearScratch 392 # rd_sp rs1_sp !-12 addi ; allocate stack 393 .00010000 .00000100 .000040FF 13000000 394 # rs1_sp rs2_ra sw ; protect ra 395 .00000100 .00001000 23200000 396 # rs1_sp rs2_a0 @4 sw ; protect a0 397 .00000100 .0000A000 .00020000 23200000 398 # rs1_sp rs2_a1 @8 sw ; protect a1 399 .00000100 .0000B000 .00040000 23200000 400 401 # rd_a0 rs1_s6 mv ; Prepare scratch 402 .00050000 .00000B00 13000000 403 404 :ClearScratch_loop 405 # rd_a1 rs1_a0 lb ; Read current byte: s[i] 406 .80050000 .00000500 03000000 407 # rs1_a0 sb ; Write zero: s[i] = 0 408 .00000500 23000000 409 # rd_a0 rs1_a0 !1 addi ; Increment: i = i + 1 410 .00050000 .00000500 .00001000 13000000 411 # rs1_a1 @ClearScratch_loop bnez ; Keep looping 412 .00800500 @ClearScratch_loop 63100000 413 414 # rd_ra rs1_sp lw ; restore ra 415 .80000000 .00000100 03200000 416 # rd_a0 rs1_sp !4 lw ; restore a0 417 .00050000 .00000100 .00004000 03200000 418 # rd_a1 rs1_sp !8 lw ; restore a1 419 .80050000 .00000100 .00008000 03200000 420 # rd_sp rs1_sp !12 addi ; deallocate stack 421 .00010000 .00000100 .0000C000 13000000 422 # ret 423 67800000 424 425 426 ; Store_Atom Function 427 ; Receives C in a2, HEAD in a3 and Input file in s2 428 ; Uses a1 for in_set strings, a2 for C and a3 for string 429 :Store_Atom 430 # rd_sp rs1_sp !-16 addi ; allocate stack 431 .00010000 .00000100 .000000FF 13000000 432 # rs1_sp rs2_ra sw ; protect ra 433 .00000100 .00001000 23200000 434 # rs1_sp rs2_a1 @4 sw ; protect a1 435 .00000100 .0000B000 .00020000 23200000 436 # rs1_sp rs2_a2 @8 sw ; protect a2 437 .00000100 .0000C000 .00040000 23200000 438 # rs1_sp rs2_a3 @12 sw ; protect a3 439 .00000100 .0000D000 .00060000 23200000 440 441 # rd_a1 ~terminators auipc ; Get pointer to "\n\t " 442 .80050000 ~terminators 17000000 443 # rd_a1 rs1_a1 !terminators addi ; Get pointer to "\n\t " 444 .80050000 .00800500 !terminators 13000000 445 # rd_a3 rs1_s6 mv ; Protect string pointer 446 .80060000 .00000B00 13000000 447 448 :Store_Atom_loop 449 # rs1_a3 rs2_a2 sb ; write byte 450 .00800600 .0000C000 23000000 451 # rd_ra $fgetc jal ; read next char 452 .80000000 $fgetc 6F000000 453 # rd_a2 rs1_a0 mv ; Update C 454 .00060000 .00000500 13000000 455 # rd_a3 rs1_a3 !1 addi ; STRING = STRING + 1 456 .80060000 .00800600 .00001000 13000000 457 # rd_ra $In_Set jal ; Check for terminators 458 .80000000 $In_Set 6F000000 459 # rs1_a0 @Store_Atom_loop beqz ; Loop if not "\n\t " 460 .00000500 @Store_Atom_loop 63000000 461 462 # rd_a0 rs1_s6 mv ; Prepare the string in scratch 463 .00050000 .00000B00 13000000 464 # rd_ra $string_length jal ; Calculate length 465 .80000000 $string_length 6F000000 466 # rd_a0 rs1_a0 !1 addi ; Add 1 for 0 terminator 467 .00050000 .00000500 .00001000 13000000 468 # rd_ra $malloc jal ; Allocate memory 469 .80000000 $malloc 6F000000 470 # rd_a3 rs1_sp !12 lw ; restore a3 471 .80060000 .00000100 .0000C000 03200000 472 # rs1_a3 rs2_a0 @8 sw ; HEAD->TEXT = STRING 473 .00800600 .0000A000 .00040000 23200000 474 # rd_ra $copy_string jal ; Copy the string 475 .80000000 $copy_string 6F000000 476 477 # rd_ra rs1_sp lw ; restore ra 478 .80000000 .00000100 03200000 479 # rd_a1 rs1_sp !4 lw ; restore a1 480 .80050000 .00000100 .00004000 03200000 481 # rd_a2 rs1_sp !8 lw ; restore a2 482 .00060000 .00000100 .00008000 03200000 483 # rd_sp rs1_sp !16 addi ; deallocate stack 484 .00010000 .00000100 .00000001 13000000 485 # rs1_ra jalr ; return 486 .00800000 67000000 487 488 489 ; Reverse_List function 490 ; Receives list in a0 491 ; Returns the list reversed in a0 492 :Reverse_List 493 # rd_sp rs1_sp !-8 addi ; allocate stack 494 .00010000 .00000100 .000080FF 13000000 495 # rs1_sp rs2_a1 sw ; protect a1 496 .00000100 .0000B000 23200000 497 # rs1_sp rs2_a2 @4 sw ; protect a2 498 .00000100 .0000C000 .00020000 23200000 499 # rd_a1 rs1_a0 mv ; Set HEAD 500 .80050000 .00000500 13000000 501 # rd_a0 mv ; ROOT = NULL 502 .00050000 13000000 503 :Reverse_List_Loop 504 # rs1_a1 @Reverse_List_Done beqz ; Stop if HEAD == NULL 505 .00800500 @Reverse_List_Done 63000000 506 507 # rd_a2 rs1_a1 lw ; NEXT = HEAD->NEXT 508 .00060000 .00800500 03200000 509 # rs1_a1 rs2_a0 sw ; HEAD->NEXT = ROOT 510 .00800500 .0000A000 23200000 511 # rd_a0 rs1_a1 mv ; ROOT = HEAD 512 .00050000 .00800500 13000000 513 # rd_a1 rs1_a2 mv ; HEAD = NEXT 514 .80050000 .00000600 13000000 515 # $Reverse_List_Loop jal ; Continue looping 516 $Reverse_List_Loop 6F000000 517 518 :Reverse_List_Done 519 # rd_a1 rs1_sp lw ; restore a1 520 .80050000 .00000100 03200000 521 # rd_a2 rs1_sp !4 lw ; restore a2 522 .00060000 .00000100 .00004000 03200000 523 # rd_sp rs1_sp !8 addi ; deallocate stack 524 .00010000 .00000100 .00008000 13000000 525 # rs1_ra jalr ; return 526 .00800000 67000000 527 528 529 ; Identify_Macros function 530 ; Receives List in a0 531 ; Updates the list in place; does not modify registers 532 ; Uses a1 for DEFINE, a2 for I 533 :Identify_Macros 534 # rd_sp rs1_sp !-16 addi ; allocate stack 535 .00010000 .00000100 .000000FF 13000000 536 # rs1_sp rs2_ra sw ; protect ra 537 .00000100 .00001000 23200000 538 # rs1_sp rs2_a0 @4 sw ; protect a0 539 .00000100 .0000A000 .00020000 23200000 540 # rs1_sp rs2_a1 @8 sw ; protect a1 541 .00000100 .0000B000 .00040000 23200000 542 # rs1_sp rs2_a2 @12 sw ; protect a2 543 .00000100 .0000C000 .00060000 23200000 544 545 # rd_a1 ~DEFINE_str auipc ; Setup DEFINE string 546 .80050000 ~DEFINE_str 17000000 547 # rd_a1 rs1_a1 !DEFINE_str addi ; Setup DEFINE string 548 .80050000 .00800500 !DEFINE_str 13000000 549 # rd_a2 rs1_a0 mv ; I = HEAD 550 .00060000 .00000500 13000000 551 552 :Identify_Macros_Loop 553 # rd_a0 rs1_a2 !8 lw ; I->TEXT 554 .00050000 .00000600 .00008000 03200000 555 # rd_ra $match jal ; IF "DEFINE" == I->TEXT 556 .80000000 $match 6F000000 557 # rs1_a0 @Identify_Macros_Next bnez ; Check if we got macro 558 .00000500 @Identify_Macros_Next 63100000 559 560 ; Deal with MACRO 561 # rd_a0 !1 addi ; a0 = MACRO 562 .00050000 .00001000 13000000 563 # rs1_a2 rs2_a0 @4 sw ; I->TYPE = MACRO 564 .00000600 .0000A000 .00020000 23200000 565 566 # rd_a0 rs1_a2 lw ; I->NEXT 567 .00050000 .00000600 03200000 568 # rd_a0 rs1_a0 !8 lw ; I->NEXT->TEXT 569 .00050000 .00000500 .00008000 03200000 570 # rs1_a2 rs2_a0 @8 sw ; I->TEXT = I->NEXT->TEXT 571 .00000600 .0000A000 .00040000 23200000 572 573 # rd_a0 rs1_a2 lw ; I->NEXT 574 .00050000 .00000600 03200000 575 # rd_a0 rs1_a0 lw ; I->NEXT->NEXT 576 .00050000 .00000500 03200000 577 # rd_a0 rs1_a0 !8 lw ; I->NEXT->NEXT->TEXT 578 .00050000 .00000500 .00008000 03200000 579 # rs1_a2 rs2_a0 @12 sw ; I->EXPRESSION = I->NEXT->NEXT->TEXT 580 .00000600 .0000A000 .00060000 23200000 581 582 # rd_a0 rs1_a2 lw ; I->NEXT 583 .00050000 .00000600 03200000 584 # rd_a0 rs1_a0 lw ; I->NEXT->NEXT 585 .00050000 .00000500 03200000 586 # rd_a0 rs1_a0 lw ; I->NEXT->NEXT->NEXT 587 .00050000 .00000500 03200000 588 # rs1_a2 rs2_a0 sw ; I->NEXT = I->NEXT->NEXT->NEXT 589 .00000600 .0000A000 23200000 590 591 :Identify_Macros_Next 592 # rd_a2 rs1_a2 lw ; I = I->NEXT 593 .00060000 .00000600 03200000 594 # rs1_a2 @Identify_Macros_Loop bnez ; Check if we are done 595 .00000600 @Identify_Macros_Loop 63100000 596 597 # rd_ra rs1_sp lw ; restore ra 598 .80000000 .00000100 03200000 599 # rd_a0 rs1_sp !4 lw ; restore a0 600 .00050000 .00000100 .00004000 03200000 601 # rd_a1 rs1_sp !8 lw ; restore a1 602 .80050000 .00000100 .00008000 03200000 603 # rd_a2 rs1_sp !12 lw ; restore a2 604 .00060000 .00000100 .0000C000 03200000 605 # rd_sp rs1_sp !16 addi ; deallocate stack 606 .00010000 .00000100 .00000001 13000000 607 # rs1_ra jalr ; return 608 .00800000 67000000 609 610 611 ; match function 612 ; Receives CHAR* in a0 and CHAR* in a1 613 ; Returns 0 (TRUE) or 1 (FALSE) in a0 614 :match 615 # rd_sp rs1_sp !-12 addi ; allocate stack 616 .00010000 .00000100 .000040FF 13000000 617 # rs1_sp rs2_a1 sw ; protect a1 618 .00000100 .0000B000 23200000 619 # rs1_sp rs2_a2 @4 sw ; protect a2 620 .00000100 .0000C000 .00020000 23200000 621 # rs1_sp rs2_a3 @8 sw ; protect a3 622 .00000100 .0000D000 .00040000 23200000 623 624 # rd_a2 rs1_a0 mv ; S1 in place 625 .00060000 .00000500 13000000 626 # rd_a3 rs1_a1 mv ; S2 in place 627 .80060000 .00800500 13000000 628 629 :match_Loop 630 # rd_a0 rs1_a2 lbu ; S1[i] 631 .00050000 .00000600 03400000 632 # rd_a1 rs1_a3 lbu ; S2[i] 633 .80050000 .00800600 03400000 634 # rs1_a0 rs2_a1 @match_False bne ; Check if they match 635 .00000500 .0000B000 @match_False 63100000 636 637 # rd_a2 rs1_a2 !1 addi ; S1 = S1 + 1 638 .00060000 .00000600 .00001000 13000000 639 # rd_a3 rs1_a3 !1 addi ; S2 = S2 + 1 640 .80060000 .00800600 .00001000 13000000 641 # rs1_a0 @match_Done beqz ; Match if we reached end of string 642 .00000500 @match_Done 63000000 643 # $match_Loop jal ; Otherwise keep looping 644 $match_Loop 6F000000 645 646 :match_False 647 # rd_a0 !1 addi ; Return false 648 .00050000 .00001000 13000000 649 :match_Done 650 # rd_a1 rs1_sp lw ; restore a1 651 .80050000 .00000100 03200000 652 # rd_a2 rs1_sp !4 lw ; restore a2 653 .00060000 .00000100 .00004000 03200000 654 # rd_a3 rs1_sp !8 lw ; restore a3 655 .80060000 .00000100 .00008000 03200000 656 # rd_sp rs1_sp !12 addi ; deallocate stack 657 .00010000 .00000100 .0000C000 13000000 658 # rs1_ra jalr ; return 659 .00800000 67000000 660 661 662 ; Line_Macro function 663 ; Receives List in a0 664 ; Updates the list in place; does not modify registers 665 ; Uses a0 for I, a1 for I->TEXT, a2 for I->EXPRESSION 666 :Line_Macro 667 # rd_sp rs1_sp !-16 addi ; allocate stack 668 .00010000 .00000100 .000000FF 13000000 669 # rs1_sp rs2_ra sw ; protect ra 670 .00000100 .00001000 23200000 671 # rs1_sp rs2_a0 @4 sw ; protect a0 672 .00000100 .0000A000 .00020000 23200000 673 # rs1_sp rs2_a1 @8 sw ; protect a1 674 .00000100 .0000B000 .00040000 23200000 675 # rs1_sp rs2_a2 @12 sw ; protect a2 676 .00000100 .0000C000 .00060000 23200000 677 678 :Line_Macro_Loop 679 # rd_a1 rs1_a0 !4 lw ; I->TYPE 680 .80050000 .00000500 .00004000 03200000 681 # rd_t0 !1 addi ; t0 = MACRO 682 .80020000 .00001000 13000000 683 # rs1_a1 rs2_t0 @Line_Macro_Next bne ; Move on unless I->TYPE == MACRO 684 .00800500 .00005000 @Line_Macro_Next 63100000 685 686 ; Apply macro 687 # rd_a1 rs1_a0 !8 lw ; I->TEXT 688 .80050000 .00000500 .00008000 03200000 689 # rd_a2 rs1_a0 !12 lw ; I->EXPRESSION 690 .00060000 .00000500 .0000C000 03200000 691 # rd_a0 rs1_a0 lw ; I->NEXT 692 .00050000 .00000500 03200000 693 # rd_ra $Set_Expression jal ; Apply it 694 .80000000 $Set_Expression 6F000000 695 # $Line_Macro_Loop jal ; Move on to next 696 $Line_Macro_Loop 6F000000 697 698 :Line_Macro_Next 699 # rd_a0 rs1_a0 lw ; I->NEXT 700 .00050000 .00000500 03200000 701 # rs1_a0 @Line_Macro_Loop bnez ; Check if we are done 702 .00000500 @Line_Macro_Loop 63100000 703 704 # rd_ra rs1_sp lw ; restore ra 705 .80000000 .00000100 03200000 706 # rd_a0 rs1_sp !4 lw ; restore a0 707 .00050000 .00000100 .00004000 03200000 708 # rd_a1 rs1_sp !8 lw ; restore a1 709 .80050000 .00000100 .00008000 03200000 710 # rd_a2 rs1_sp !12 lw ; restore a2 711 .00060000 .00000100 .0000C000 03200000 712 # rd_sp rs1_sp !16 addi ; deallocate stack 713 .00010000 .00000100 .00000001 13000000 714 # rs1_ra jalr ; return 715 .00800000 67000000 716 717 718 ; Set_Expression function 719 ; Receives List in a0, CHAR* in a1 and CHAR* in a2 720 ; Updates the list in place; does not modify registers 721 ; Uses a1 for C, a2 for EXP and a3 for I 722 :Set_Expression 723 # rd_sp rs1_sp !-20 addi ; allocate stack 724 .00010000 .00000100 .0000C0FE 13000000 725 # rs1_sp rs2_ra sw ; protect ra 726 .00000100 .00001000 23200000 727 # rs1_sp rs2_a0 @4 sw ; protect a0 728 .00000100 .0000A000 .00020000 23200000 729 # rs1_sp rs2_a1 @8 sw ; protect a1 730 .00000100 .0000B000 .00040000 23200000 731 # rs1_sp rs2_a2 @12 sw ; protect a2 732 .00000100 .0000C000 .00060000 23200000 733 # rs1_sp rs2_a3 @16 sw ; protect a3 734 .00000100 .0000D000 .00080000 23200000 735 736 # rd_a3 rs1_a0 mv ; Set I 737 .80060000 .00000500 13000000 738 :Set_Expression_Loop 739 # rd_a0 rs1_a3 !4 lw ; I->TYPE 740 .00050000 .00800600 .00004000 03200000 741 # rd_t0 !1 addi ; t0 = MACRO 742 .80020000 .00001000 13000000 743 # rs1_a0 rs2_t0 @Set_Expression_Next beq ; If MACRO == I->Type then ignore and move on 744 .00000500 .00005000 @Set_Expression_Next 63000000 745 746 # rd_a0 rs1_a3 !8 lw ; I->TEXT 747 .00050000 .00800600 .00008000 03200000 748 # rd_ra $match jal ; Check for match 749 .80000000 $match 6F000000 750 # rs1_a0 @Set_Expression_Next bnez ; Check next if does not match 751 .00000500 @Set_Expression_Next 63100000 752 753 ; Non-macro match 754 # rs1_a3 rs2_a2 @12 sw ; I->EXPRESSION = EXP 755 .00800600 .0000C000 .00060000 23200000 756 757 :Set_Expression_Next 758 # rd_a3 rs1_a3 lw ; I = I->NEXT 759 .80060000 .00800600 03200000 760 # rs1_a3 @Set_Expression_Loop bnez ; Check if we are done 761 .00800600 @Set_Expression_Loop 63100000 762 763 # rd_ra rs1_sp lw ; restore ra 764 .80000000 .00000100 03200000 765 # rd_a0 rs1_sp !4 lw ; restore a0 766 .00050000 .00000100 .00004000 03200000 767 # rd_a1 rs1_sp !8 lw ; restore a1 768 .80050000 .00000100 .00008000 03200000 769 # rd_a2 rs1_sp !12 lw ; restore a2 770 .00060000 .00000100 .0000C000 03200000 771 # rd_a3 rs1_sp !16 lw ; restore a3 772 .80060000 .00000100 .00000001 03200000 773 # rd_sp rs1_sp !20 addi ; deallocate stack 774 .00010000 .00000100 .00004001 13000000 775 # rs1_ra jalr ; return 776 .00800000 67000000 777 778 779 ; Process_String function 780 ; Receives List in a0 781 ; Update the list in place; does not modify registers 782 ; Uses a1 for I->TEXT, a2 for I and RDX for S 783 :Process_String 784 # rd_sp rs1_sp !-20 addi ; allocate stack 785 .00010000 .00000100 .0000C0FE 13000000 786 # rs1_sp rs2_ra sw ; protect ra 787 .00000100 .00001000 23200000 788 # rs1_sp rs2_a0 @4 sw ; protect a0 789 .00000100 .0000A000 .00020000 23200000 790 # rs1_sp rs2_a1 @8 sw ; protect a1 791 .00000100 .0000B000 .00040000 23200000 792 # rs1_sp rs2_a2 @12 sw ; protect a2 793 .00000100 .0000C000 .00060000 23200000 794 # rs1_sp rs2_a3 @16 sw ; protect a3 795 .00000100 .0000D000 .00080000 23200000 796 797 # rd_a2 rs1_a0 mv ; I = HEAD 798 .00060000 .00000500 13000000 799 800 :Process_String_loop 801 # rd_a0 rs1_a2 !4 lw ; I->TYPE 802 .00050000 .00000600 .00004000 03200000 803 # rd_t0 !2 addi ; t0 = STRING 804 .80020000 .00002000 13000000 805 # rs1_a0 rs2_t0 @Process_String_Next bne ; Skip to next 806 .00000500 .00005000 @Process_String_Next 63100000 807 808 # rd_a1 rs1_a2 !8 lw ; I->TEXT 809 .80050000 .00000600 .00008000 03200000 810 # rd_a0 rs1_a1 lbu ; I->TEXT[0] 811 .00050000 .00800500 03400000 812 # rd_t0 !39 addi ; t0 = \' 813 .80020000 .00007002 13000000 814 # rs1_a0 rs2_t0 @Process_String_Raw bne ; Deal with '"' 815 .00000500 .00005000 @Process_String_Raw 63100000 816 817 ; Deal with \' 818 # rd_a1 rs1_a1 !1 addi ; I->TEXT + 1 819 .80050000 .00800500 .00001000 13000000 820 # rs1_a2 rs2_a1 @12 sw ; I->EXPRESSION = I->TEXT + 1 821 .00000600 .0000B000 .00060000 23200000 822 # $Process_String_Next jal ; Move on to next 823 $Process_String_Next 6F000000 824 825 :Process_String_Raw 826 # rd_a0 rs1_a1 mv ; I->TEXT 827 .00050000 .00800500 13000000 828 # rd_ra $string_length jal ; Get length of I->TEXT 829 .80000000 $string_length 6F000000 830 # rd_a0 rs1_a0 rs2_x2 srli ; LENGTH = LENGTH >> 2 831 .00050000 .00000500 .00002000 13500000 832 # rd_a0 rs1_a0 !1 addi ; LENGTH = LENGTH + 1 833 .00050000 .00000500 .00001000 13000000 834 # rd_a0 rs1_a0 rs2_x3 slli ; LENGTH = LENGTH << 3 835 .00050000 .00000500 .00003000 13100000 836 # rd_ra $malloc jal ; Get string 837 .80000000 $malloc 6F000000 838 # rd_a3 rs1_a1 mv ; S = I->TEXT 839 .80060000 .00800500 13000000 840 # rd_a3 rs1_a3 !1 addi ; S = S + 1 841 .80060000 .00800600 .00001000 13000000 842 # rs1_a2 rs2_a0 @12 sw ; I->EXPRESSION = hexify 843 .00000600 .0000A000 .00060000 23200000 844 # rd_a1 rs1_a0 mv ; Put hexify buffer in a1 845 .80050000 .00000500 13000000 846 847 :Process_String_Raw_Loop 848 # rd_a0 rs1_a3 lbu ; Read 1 character 849 .00050000 .00800600 03400000 850 # rd_a3 rs1_a3 !1 addi ; S = S + 1 851 .80060000 .00800600 .00001000 13000000 852 # rd_s5 rs1_a0 mv ; Protect character 853 .800A0000 .00000500 13000000 854 # rd_ra $hex8 jal ; write them all 855 .80000000 $hex8 6F000000 856 # rd_a0 rs1_s5 mv ; Restore character 857 .00050000 .00800A00 13000000 858 # rs1_a0 @Process_String_Raw_Loop bnez ; Keep looping 859 .00000500 @Process_String_Raw_Loop 63100000 860 861 :Process_String_Next 862 # rd_a2 rs1_a2 lw ; I = I->NEXT 863 .00060000 .00000600 03200000 864 # rs1_a2 @Process_String_loop bnez ; Check if we are done 865 .00000600 @Process_String_loop 63100000 866 867 # rd_ra rs1_sp lw ; restore ra 868 .80000000 .00000100 03200000 869 # rd_a0 rs1_sp !4 lw ; restore a0 870 .00050000 .00000100 .00004000 03200000 871 # rd_a1 rs1_sp !8 lw ; restore a1 872 .80050000 .00000100 .00008000 03200000 873 # rd_a2 rs1_sp !12 lw ; restore a2 874 .00060000 .00000100 .0000C000 03200000 875 # rd_a3 rs1_sp !16 lw ; restore a3 876 .80060000 .00000100 .00000001 03200000 877 # rd_sp rs1_sp !20 addi ; deallocate stack 878 .00010000 .00000100 .00004001 13000000 879 # rs1_ra jalr ; return 880 .00800000 67000000 881 882 883 ; string_length function 884 ; Receives CHAR* in a0 885 ; Returns INT in a0 886 ; Uses a0 for CH, a1 for S and a2 for INDEX 887 :string_length 888 # rd_sp rs1_sp !-8 addi ; allocate stack 889 .00010000 .00000100 .000080FF 13000000 890 # rs1_sp rs2_a1 sw ; protect a1 891 .00000100 .0000B000 23200000 892 # rs1_sp rs2_a2 @4 sw ; protect a2 893 .00000100 .0000C000 .00020000 23200000 894 895 # rd_a1 rs1_a0 mv ; Set S 896 .80050000 .00000500 13000000 897 # rd_a2 mv ; INDEX = 0 898 .00060000 13000000 899 900 :string_length_loop 901 # rd_t0 rs1_a1 rs2_a2 add ; S + INDEX 902 .80020000 .00800500 .0000C000 33000000 903 # rd_a0 rs1_t0 lbu ; S[INDEX] 904 .00050000 .00800200 03400000 905 # rs1_a0 @string_length_done beqz ; Check if we are done 906 .00000500 @string_length_done 63000000 907 908 # rd_a2 rs1_a2 !1 addi ; INDEX = INDEX + 1 909 .00060000 .00000600 .00001000 13000000 910 # $string_length_loop jal ; Keep going 911 $string_length_loop 6F000000 912 913 :string_length_done 914 # rd_a0 rs1_a2 mv ; return INDEX 915 .00050000 .00000600 13000000 916 # rd_a1 rs1_sp lw ; restore a1 917 .80050000 .00000100 03200000 918 # rd_a2 rs1_sp !4 lw ; restore a2 919 .00060000 .00000100 .00004000 03200000 920 # rd_sp rs1_sp !8 addi ; deallocate stack 921 .00010000 .00000100 .00008000 13000000 922 # rs1_ra jalr ; return 923 .00800000 67000000 924 925 926 ; Eval_Immediates function 927 ; Receives List in a0 928 ; Updates the list in place; does not modify registers 929 ; Uses a1 for I->TEXT[0], a2 for I->TEXT[1] and a3 for I 930 :Eval_Immediates 931 # rd_sp rs1_sp !-20 addi ; allocate stack 932 .00010000 .00000100 .0000C0FE 13000000 933 # rs1_sp rs2_ra sw ; protect ra 934 .00000100 .00001000 23200000 935 # rs1_sp rs2_a0 @4 sw ; protect a0 936 .00000100 .0000A000 .00020000 23200000 937 # rs1_sp rs2_a1 @8 sw ; protect a1 938 .00000100 .0000B000 .00040000 23200000 939 # rs1_sp rs2_a2 @12 sw ; protect a2 940 .00000100 .0000C000 .00060000 23200000 941 # rs1_sp rs2_a3 @16 sw ; protect a3 942 .00000100 .0000D000 .00080000 23200000 943 944 # rd_a3 rs1_a0 mv ; I = HEAD 945 .80060000 .00000500 13000000 946 947 :Eval_Immediates_Loop 948 ; Check for MACRO 949 # rd_a0 rs1_a3 !4 lw ; I->TYPE 950 .00050000 .00800600 .00004000 03200000 951 # rd_t0 !1 addi ; t0 = MACRO 952 .80020000 .00001000 13000000 953 # rs1_a0 rs2_t0 @Eval_Immediates_Next beq ; Skip to next if I->TYPE == MACRO 954 .00000500 .00005000 @Eval_Immediates_Next 63000000 955 956 ; Check for NULL EXPRESSION 957 # rd_a0 rs1_a3 !12 lw ; I->EXPRESSION 958 .00050000 .00800600 .0000C000 03200000 959 # rs1_a0 @Eval_Immediates_Next bnez ; Skip to next if NULL == I->EXPRESSION 960 .00000500 @Eval_Immediates_Next 63100000 961 962 ; Check if number 963 # rd_a0 rs1_a3 !8 lw ; I->TEXT 964 .00050000 .00800600 .00008000 03200000 965 # rd_a1 rs1_a0 lbu ; I->TEXT[0] 966 .80050000 .00000500 03400000 967 # rd_a0 rs1_a0 !1 addi ; I->TEXT + 1 968 .00050000 .00000500 .00001000 13000000 969 # rd_a2 rs1_a0 lbu ; I->TEXT[1] 970 .00060000 .00000500 03400000 971 # rd_ra $numerate_string jal ; Convert string to INT 972 .80000000 $numerate_string 6F000000 973 # rs1_a0 @Eval_Immediates_value bnez ; Has a value IF 0 != numerate_string(I->TEXT + 1) 974 .00000500 @Eval_Immediates_value 63100000 975 976 ; Last chance for Immediate 977 # rd_t0 !48 addi ; If '0' = I->TEXT[1] 978 .80020000 .00000003 13000000 979 # rs1_a2 rs2_t0 @Eval_Immediates_Next bne ; Skip to next 980 .00000600 .00005000 @Eval_Immediates_Next 63100000 981 982 :Eval_Immediates_value 983 # rd_ra $express_number jal ; Convert value to hex string 984 .80000000 $express_number 6F000000 985 # rs1_a3 rs2_a0 @12 sw ; I->EXPRESSION = express_number(value, I-TEXT[0]) 986 .00800600 .0000A000 .00060000 23200000 987 988 :Eval_Immediates_Next 989 # rd_a3 rs1_a3 lw ; I = I->NEXT 990 .80060000 .00800600 03200000 991 # rs1_a3 @Eval_Immediates_Loop bnez ; Check if we are done 992 .00800600 @Eval_Immediates_Loop 63100000 993 994 # rd_ra rs1_sp lw ; restore ra 995 .80000000 .00000100 03200000 996 # rd_a0 rs1_sp !4 lw ; restore a0 997 .00050000 .00000100 .00004000 03200000 998 # rd_a1 rs1_sp !8 lw ; restore a1 999 .80050000 .00000100 .00008000 03200000 1000 # rd_a2 rs1_sp !12 lw ; restore a2 1001 .00060000 .00000100 .0000C000 03200000 1002 # rd_a3 rs1_sp !16 lw ; restore a3 1003 .80060000 .00000100 .00000001 03200000 1004 # rd_sp rs1_sp !20 addi ; deallocate stack 1005 .00010000 .00000100 .00004001 13000000 1006 # rs1_ra jalr ; return 1007 .00800000 67000000 1008 1009 1010 ; numerate_string function 1011 ; Receives CHAR* in a0 1012 ; Returns value of CHAR* in a0 1013 ; Uses a0 for VALUE, a1 for S, a2 for CH and a3 for NEGATIVE? 1014 :numerate_string 1015 # rd_sp rs1_sp !-12 addi ; allocate stack 1016 .00010000 .00000100 .000040FF 13000000 1017 # rs1_sp rs2_a1 sw ; protect a1 1018 .00000100 .0000B000 23200000 1019 # rs1_sp rs2_a2 @4 sw ; protect a2 1020 .00000100 .0000C000 .00020000 23200000 1021 # rs1_sp rs2_a3 @8 sw ; protect a3 1022 .00000100 .0000D000 .00040000 23200000 1023 1024 # rd_a1 rs1_a0 mv ; put S in correct place 1025 .80050000 .00000500 13000000 1026 # rd_a0 mv ; Initialize to Zero 1027 .00050000 13000000 1028 :numerate_string_loop 1029 # rd_t0 rs1_a1 !1 addi ; S + 1 1030 .80020000 .00800500 .00001000 13000000 1031 # rd_a2 rs1_t0 lbu ; S[1] 1032 .00060000 .00800200 03400000 1033 # rd_t0 !120 addi ; 'x' 1034 .80020000 .00008007 13000000 1035 # rs1_a2 rs2_t0 @numerate_hex beq ; Deal with hex_input 1036 .00000600 .00005000 @numerate_hex 63000000 1037 1038 ; Assume decimal input 1039 # rd_a3 mv ; Assume no negation 1040 .80060000 13000000 1041 # rd_a2 rs1_a1 lbu ; S[0] 1042 .00060000 .00800500 03400000 1043 # rd_t0 !45 addi ; '-' 1044 .80020000 .0000D002 13000000 1045 # rs1_a2 rs2_t0 @numerate_decimal bne ; Skip negation 1046 .00000600 .00005000 @numerate_decimal 63100000 1047 1048 # rd_a3 !1 addi ; Set FLAG 1049 .80060000 .00001000 13000000 1050 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1051 .80050000 .00800500 .00001000 13000000 1052 1053 :numerate_decimal 1054 # rd_a2 rs1_a1 lbu ; S[i] 1055 .00060000 .00800500 03400000 1056 # rs1_a2 @numerate_decimal_done beqz ; We are done if NULL == S[i] 1057 .00000600 @numerate_decimal_done 63000000 1058 1059 ; a0 = a0 * 10 = (a0 << 3) + (a0 << 1) 1060 # rd_t0 rs1_a0 rs2_x3 slli ; a0 * 8 1061 .80020000 .00000500 .00003000 13100000 1062 # rd_t1 rs1_a0 rs2_x1 slli ; a0 * 2 1063 .00030000 .00000500 .00001000 13100000 1064 # rd_a0 rs1_t0 rs2_t1 add ; VALUE = VALUE * 10 1065 .00050000 .00800200 .00006000 33000000 1066 # rd_a2 rs1_a2 !-48 addi ; CH = CH - '0' 1067 .00060000 .00000600 .000000FD 13000000 1068 # rd_t0 !9 addi ; t0 = 9 1069 .80020000 .00009000 13000000 1070 # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for illegal CH > 9 1071 .00800200 .0000C000 @numerate_string_fail 63400000 1072 # rs1_a2 @numerate_string_fail bltz ; Check for illegal CH < 0 1073 .00000600 @numerate_string_fail 63400000 1074 # rd_a0 rs1_a0 rs2_a2 add ; VALUE = VALUE + CH 1075 .00050000 .00000500 .0000C000 33000000 1076 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1077 .80050000 .00800500 .00001000 13000000 1078 # $numerate_decimal jal 1079 $numerate_decimal 6F000000 1080 1081 :numerate_decimal_done 1082 # rd_t0 !1 addi ; Check for negative FLAG 1083 .80020000 .00001000 13000000 1084 # rs1_a3 rs2_t0 @numerate_string_done bne ; Nope 1085 .00800600 .00005000 @numerate_string_done 63100000 1086 1087 # rd_a0 rs2_a0 sub ; VALUE = -VALUE 1088 .00050000 .0000A000 33000040 1089 # $numerate_string_done jal ; Done 1090 $numerate_string_done 6F000000 1091 1092 :numerate_hex 1093 # rd_a1 rs1_a1 !2 addi ; S = S + 2 1094 .80050000 .00800500 .00002000 13000000 1095 :numerate_hex_loop 1096 # rd_a2 rs1_a1 lbu ; S[i] 1097 .00060000 .00800500 03400000 1098 # rs1_a2 @numerate_string_done beqz ; We are done if NULL == S[i] 1099 .00000600 @numerate_string_done 63000000 1100 1101 # rd_a0 rs1_a0 rs2_x4 slli ; VALUE = VALUE << 4 1102 .00050000 .00000500 .00004000 13100000 1103 # rd_a2 rs1_a2 !-48 addi ; CH = CH - '0' 1104 .00060000 .00000600 .000000FD 13000000 1105 # rd_t0 !10 addi ; t0 = 10 1106 .80020000 .0000A000 13000000 1107 # rs1_a2 rs2_t0 @numerate_hex_digit blt ; Check if we are dealing with number or letter 1108 .00000600 .00005000 @numerate_hex_digit 63400000 1109 # rd_a2 rs1_a2 !-7 addi ; Push A-F into range 1110 .00060000 .00000600 .000090FF 13000000 1111 1112 :numerate_hex_digit 1113 # rd_t0 !15 addi ; t0 = 15 1114 .80020000 .0000F000 13000000 1115 # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for CH > 'F' 1116 .00800200 .0000C000 @numerate_string_fail 63400000 1117 # rs1_a2 @numerate_string_fail bltz ; Check for CH < 0 1118 .00000600 @numerate_string_fail 63400000 1119 # rd_a0 rs1_a0 rs2_a2 add ; VALUE = VALUE + CH 1120 .00050000 .00000500 .0000C000 33000000 1121 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1122 .80050000 .00800500 .00001000 13000000 1123 # $numerate_hex_loop jal ; Keep looping 1124 $numerate_hex_loop 6F000000 1125 1126 :numerate_string_fail 1127 # rd_a0 mv ; return ZERO 1128 .00050000 13000000 1129 1130 :numerate_string_done 1131 # rd_a1 rs1_sp lw ; restore a1 1132 .80050000 .00000100 03200000 1133 # rd_a2 rs1_sp !4 lw ; restore a2 1134 .00060000 .00000100 .00004000 03200000 1135 # rd_a3 rs1_sp !8 lw ; restore a3 1136 .80060000 .00000100 .00008000 03200000 1137 # rd_sp rs1_sp !12 addi ; deallocate stack 1138 .00010000 .00000100 .0000C000 13000000 1139 # rs1_ra jalr ; return 1140 .00800000 67000000 1141 1142 1143 ; express_number function 1144 ; Receives INT in a0 and CHAR in a1 1145 ; Allocates a string and expresses the value in appropriate RISC-V encoding 1146 ; Returns string in a0 1147 ; Uses a0 for VALUE, a1 for S and a2 for CH 1148 :express_number 1149 # rd_sp rs1_sp !-16 addi ; allocate stack 1150 .00010000 .00000100 .000000FF 13000000 1151 # rs1_sp rs2_ra sw ; protect ra 1152 .00000100 .00001000 23200000 1153 # rs1_sp rs2_a1 @4 sw ; protect a1 1154 .00000100 .0000B000 .00020000 23200000 1155 # rs1_sp rs2_a2 @8 sw ; protect a2 1156 .00000100 .0000C000 .00040000 23200000 1157 # rs1_sp rs2_a3 @12 sw ; protect a3 1158 .00000100 .0000D000 .00060000 23200000 1159 1160 # rd_a2 rs1_a1 mv ; Put CH in right place 1161 .00060000 .00800500 13000000 1162 # rd_s5 rs1_a0 mv ; Protect VALUE 1163 .800A0000 .00000500 13000000 1164 1165 # rd_a0 !10 addi ; We need 10 bytes 1166 .00050000 .0000A000 13000000 1167 # rd_ra $malloc jal ; Get S pointer 1168 .80000000 $malloc 6F000000 1169 # rd_a1 rs1_a0 mv ; Put S in place 1170 .80050000 .00000500 13000000 1171 # rd_a0 rs1_s5 mv ; Restore VALUE 1172 .00050000 .00800A00 13000000 1173 1174 ; Check for % 1175 # rd_t0 !0x25 addi 1176 .80020000 .00005002 13000000 1177 # rs1_a2 rs2_t0 @express_number_const beq 1178 .00000600 .00005000 @express_number_const 63000000 1179 1180 # rd_s5 rs1_a1 mv ; Protect S 1181 .800A0000 .00800500 13000000 1182 # rd_t0 !0x2E addi ; t0 = '.' 1183 .80020000 .0000E002 13000000 1184 # rs1_a1 rs2_t0 sw ; S[0] = '.' 1185 .00800500 .00005000 23200000 1186 # rd_a1 rs1_a1 !1 addi ; Next byte 1187 .80050000 .00800500 .00001000 13000000 1188 1189 ; Check for ! 1190 # rd_t0 !0x21 addi 1191 .80020000 .00001002 13000000 1192 # rs1_a2 rs2_t0 @express_number_I beq 1193 .00000600 .00005000 @express_number_I 63000000 1194 1195 ; Check for @ 1196 # rd_t0 !0x40 addi 1197 .80020000 .00000004 13000000 1198 # rs1_a2 rs2_t0 @express_number_S beq 1199 .00000600 .00005000 @express_number_S 63000000 1200 1201 ; Check for ~ 1202 # rd_t0 !0x7E addi 1203 .80020000 .0000E007 13000000 1204 # rs1_a2 rs2_t0 @express_number_U beq 1205 .00000600 .00005000 @express_number_U 63000000 1206 1207 # $Fail jal ; Error 1208 $Fail 6F000000 1209 1210 :express_number_const 1211 ; provides an option for 32-bit immediate constants 1212 1213 # rd_t0 !2 addi 1214 .80020000 .00002000 13000000 1215 # rd_t0 rs1_t0 rs2_x31 slli 1216 .80020000 .00800200 .0000F001 13100000 1217 # rd_t0 rs1_t0 !-1 addi ; t0 = 0xffffffff 1218 .80020000 .00800200 .0000F0FF 13000000 1219 # rd_a0 rs1_a0 rs2_t0 and ; immediate = value & 0xffffffff 1220 .00050000 .00000500 .00005000 33700000 1221 1222 # rd_s5 rs1_a1 mv ; Protect S 1223 .800A0000 .00800500 13000000 1224 # rd_ra $hex32l jal ; Store 32-bits 1225 .80000000 $hex32l 6F000000 1226 # $express_number_done jal ; done 1227 $express_number_done 6F000000 1228 1229 :express_number_I 1230 ; Corresponds to RISC-V S format 1231 ; (value & 0xfff) << 20 1232 # rd_t0 !0xFFF addi 1233 .80020000 .0000F0FF 13000000 1234 # rd_a0 rs1_a0 rs2_t0 and ; value & 0xfff 1235 .00050000 .00000500 .00005000 33700000 1236 # rd_a0 rs1_a0 rs2_x20 slli ; (value & 0xfff) << 20 1237 .00050000 .00000500 .00004001 13100000 1238 # rd_ra $hex32l jal ; Store 32-bits 1239 .80000000 $hex32l 6F000000 1240 # $express_number_done jal ; done 1241 $express_number_done 6F000000 1242 1243 :express_number_S 1244 ; Corresponds to RISC-V S format 1245 ; ((value & 0x1f) << 7) | ((value & 0xfe0) << (31 - 11)) 1246 # rd_t0 !0x1F addi 1247 .80020000 .0000F001 13000000 1248 # rd_t1 rs1_a0 rs2_t0 and ; value & 0x1f 1249 .00030000 .00000500 .00005000 33700000 1250 # rd_t1 rs1_t1 rs2_x7 slli ; (value & 0x1f) << 7 1251 .00030000 .00000300 .00007000 13100000 1252 # rd_t0 !0xFE0 addi 1253 .80020000 .000000FE 13000000 1254 # rd_t0 rs1_a0 rs2_t0 and ; value & 0xfe0 1255 .80020000 .00000500 .00005000 33700000 1256 # rd_t0 rs1_t0 rs2_x20 slli ; (value & 0xfe0) << (31 - 11) 1257 .80020000 .00800200 .00004001 13100000 1258 # rd_a0 rs1_t0 rs2_t1 or ; Combine two parts 1259 .00050000 .00800200 .00006000 33600000 1260 # rd_ra $hex32l jal ; Store 32-bits 1261 .80000000 $hex32l 6F000000 1262 # $express_number_done jal ; done 1263 $express_number_done 6F000000 1264 1265 :express_number_U 1266 ; Corresponds to RISC-V U format 1267 ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension 1268 1269 # rd_t0 ~0x800 lui ; load higher bits 1270 .80020000 .00100000 37000000 1271 # rd_t0 rs1_t0 !0x800 addi 1272 .80020000 .00800200 .00000080 13000000 1273 # rd_t1 ~0xFFF lui ; load higher bits 1274 .00030000 .00100000 37000000 1275 # rd_t1 rs1_t1 !0xFFF addi 1276 .00030000 .00000300 .0000F0FF 13000000 1277 ; We are outside 31-bit that ~ can normally load 1278 # rd_t2 ~0x100000 lui ; load 0xfffff000 1279 .80030000 .00001000 37000000 1280 # rd_t2 rs1_t2 !-1 addi ; load 0xfffff000 1281 .80030000 .00800300 .0000F0FF 13000000 1282 # rd_t2 rs1_t2 rs2_x12 slli ; load 0xfffff000 1283 .80030000 .00800300 .0000C000 13100000 1284 # rd_t1 rs1_a0 rs2_t1 and ; value & 0xfff 1285 .00030000 .00000500 .00006000 33700000 1286 # rd_a0 rs1_a0 rs2_t2 and ; value & 0xfffff000 1287 .00050000 .00000500 .00007000 33700000 1288 # rs1_t1 rs2_t0 @express_number_U_small blt 1289 .00000300 .00005000 @express_number_U_small 63400000 1290 1291 ; Deal with sign extension: add 0x1000 1292 # rd_t0 ~0x1000 lui 1293 .80020000 .00100000 37000000 1294 # rd_a0 rs1_t0 rs2_a0 add ; (value & 0xfffff000) + 0x1000 1295 .00050000 .00800200 .0000A000 33000000 1296 :express_number_U_small 1297 # rd_ra $hex32l jal ; Store 32-bits 1298 .80000000 $hex32l 6F000000 1299 # $express_number_done jal ; done 1300 $express_number_done 6F000000 1301 1302 :express_number_done 1303 # rd_a0 rs1_s5 mv ; Restore S 1304 .00050000 .00800A00 13000000 1305 # rd_ra rs1_sp lw ; restore ra 1306 .80000000 .00000100 03200000 1307 # rd_a1 rs1_sp !4 lw ; restore a1 1308 .80050000 .00000100 .00004000 03200000 1309 # rd_a2 rs1_sp !8 lw ; restore a2 1310 .00060000 .00000100 .00008000 03200000 1311 # rd_a3 rs1_sp !12 lw ; restore a3 1312 .80060000 .00000100 .0000C000 03200000 1313 # rd_sp rs1_sp !16 addi ; deallocate stack 1314 .00010000 .00000100 .00000001 13000000 1315 # rs1_ra jalr ; return 1316 .00800000 67000000 1317 1318 1319 ; HEX to ascii routine 1320 ; Receives INT in a0 and CHAR* in a1 1321 ; Stores ascii of INT in CHAR* 1322 ; Returns only modifying a0 1323 :hex32l 1324 # rd_sp rs1_sp !-8 addi ; allocate stack 1325 .00010000 .00000100 .000080FF 13000000 1326 # rs1_sp rs2_ra sw ; Protect ra 1327 .00000100 .00001000 23200000 1328 # rs1_sp rs2_a0 @4 sw ; Protect top 16 bits 1329 .00000100 .0000A000 .00020000 23200000 1330 # rd_ra $hex16l jal ; Store it 1331 .80000000 $hex16l 6F000000 1332 # rd_a0 rs1_sp !4 lw ; do high 16-bits 1333 .00050000 .00000100 .00004000 03200000 1334 # rd_a0 rs1_a0 rs2_x16 srli ; do bottom 16 bits 1335 .00050000 .00000500 .00000001 13500000 1336 # rd_ra $hex16l jal ; Store it 1337 .80000000 $hex16l 6F000000 1338 # rd_ra rs1_sp lw ; restore ra 1339 .80000000 .00000100 03200000 1340 # rd_sp rs1_sp !8 addi ; deallocate stack 1341 .00010000 .00000100 .00008000 13000000 1342 # rs1_ra jalr ; return 1343 .00800000 67000000 1344 1345 :hex16l 1346 # rd_sp rs1_sp !-8 addi ; allocate stack 1347 .00010000 .00000100 .000080FF 13000000 1348 # rs1_sp rs2_ra sw ; Protect ra 1349 .00000100 .00001000 23200000 1350 # rs1_sp rs2_a0 @4 sw ; Protect top byte 1351 .00000100 .0000A000 .00020000 23200000 1352 # rd_ra $hex8 jal ; Store it 1353 .80000000 $hex8 6F000000 1354 # rd_a0 rs1_sp !4 lw ; do high byte 1355 .00050000 .00000100 .00004000 03200000 1356 # rd_a0 rs1_a0 rs2_x8 srli ; do bottom byte 1357 .00050000 .00000500 .00008000 13500000 1358 # rd_ra $hex8 jal ; Store it 1359 .80000000 $hex8 6F000000 1360 # rd_ra rs1_sp lw ; restore ra 1361 .80000000 .00000100 03200000 1362 # rd_sp rs1_sp !8 addi ; deallocate stack 1363 .00010000 .00000100 .00008000 13000000 1364 # rs1_ra jalr ; return 1365 .00800000 67000000 1366 1367 :hex8 1368 # rd_sp rs1_sp !-8 addi ; allocate stack 1369 .00010000 .00000100 .000080FF 13000000 1370 # rs1_sp rs2_ra sw ; Protect ra 1371 .00000100 .00001000 23200000 1372 # rs1_sp rs2_a0 @4 sw ; Protect bottom nibble 1373 .00000100 .0000A000 .00020000 23200000 1374 # rd_a0 rs1_a0 rs2_x4 srli ; do high nibble first 1375 .00050000 .00000500 .00004000 13500000 1376 # rd_ra $hex4 jal ; Store it 1377 .80000000 $hex4 6F000000 1378 # rd_a0 rs1_sp !4 lw ; do low nibble 1379 .00050000 .00000100 .00004000 03200000 1380 # rd_ra $hex4 jal ; Store it 1381 .80000000 $hex4 6F000000 1382 # rd_ra rs1_sp lw ; restore ra 1383 .80000000 .00000100 03200000 1384 # rd_sp rs1_sp !8 addi ; deallocate stack 1385 .00010000 .00000100 .00008000 13000000 1386 # rs1_ra jalr ; return 1387 .00800000 67000000 1388 1389 :hex4 1390 # rd_t0 !0xF addi 1391 .80020000 .0000F000 13000000 1392 # rd_a0 rs1_a0 rs2_t0 and ; isolate nibble 1393 .00050000 .00000500 .00005000 33700000 1394 # rd_a0 rs1_a0 !0x30 addi ; convert to ascii 1395 .00050000 .00000500 .00000003 13000000 1396 # rd_t0 !0x39 addi ; t0 = '9' 1397 .80020000 .00009003 13000000 1398 # rs1_t0 rs2_a0 @hex1 bge ; check if valid digit 1399 .00800200 .0000A000 @hex1 63500000 1400 # rd_a0 rs1_a0 !7 addi ; use alpha range 1401 .00050000 .00000500 .00007000 13000000 1402 :hex1 1403 # rs1_a1 rs2_a0 sb ; store result 1404 .00800500 .0000A000 23000000 1405 # rd_a1 rs1_a1 !1 addi ; next position 1406 .80050000 .00800500 .00001000 13000000 1407 # rs1_ra jalr ; return 1408 .00800000 67000000 1409 1410 1411 ; Preserve_Other function 1412 ; Receives list in a0 1413 ; Update the list in place; does not modify registers 1414 ; Uses a0 for I, a1 for I->TEXT 1415 :Preserve_Other 1416 # rd_sp rs1_sp !-16 addi ; allocate stack 1417 .00010000 .00000100 .000000FF 13000000 1418 # rs1_sp rs2_a1 sw ; protect a1 1419 .00000100 .0000B000 23200000 1420 # rs1_sp rs2_a2 @4 sw ; protect a2 1421 .00000100 .0000C000 .00020000 23200000 1422 # rs1_sp rs2_a3 @8 sw ; protect a3 1423 .00000100 .0000D000 .00040000 23200000 1424 # rs1_sp rs2_a4 @21 sw ; protect a4 1425 .00000100 .0000E000 .00060000 23200000 1426 :Preserve_Other_Loop 1427 # rd_a1 rs1_a0 !12 lw ; I->EXPRESSION 1428 .80050000 .00000500 .0000C000 03200000 1429 # rs1_a1 @Preserve_Other_Next bnez ; IF NULL == I->EXPRESSION then preserve 1430 .00800500 @Preserve_Other_Next 63100000 1431 1432 # rd_a1 rs1_a0 !8 lw ; I->TEXT 1433 .80050000 .00000500 .00008000 03200000 1434 # rs1_a0 rs2_a1 @12 sw ; I->EXPRESSION = I->TEXT 1435 .00000500 .0000B000 .00060000 23200000 1436 1437 :Preserve_Other_Next 1438 # rd_a0 rs1_a0 lw ; I = I->NEXT 1439 .00050000 .00000500 03200000 1440 # rs1_a0 @Preserve_Other_Loop bnez ; Keep looping until I == NULL 1441 .00000500 @Preserve_Other_Loop 63100000 1442 1443 # rd_a1 rs1_sp lw ; restore a1 1444 .80050000 .00000100 03200000 1445 # rd_a2 rs1_sp !4 lw ; restore a2 1446 .00060000 .00000100 .00004000 03200000 1447 # rd_a3 rs1_sp !8 lw ; restore a3 1448 .80060000 .00000100 .00008000 03200000 1449 # rd_a4 rs1_sp !12 lw ; restore a4 1450 .00070000 .00000100 .0000C000 03200000 1451 # rd_sp rs1_sp !16 addi ; deallocate stack 1452 .00010000 .00000100 .00000001 13000000 1453 # rs1_ra jalr ; return 1454 .00800000 67000000 1455 1456 1457 ; Print_Hex function 1458 ; Receives list in a0 1459 ; walks the list and prints the I->EXPRESSION for all nodes followed by newline 1460 ; Uses a1 for I 1461 :Print_Hex 1462 # rd_sp rs1_sp !-12 addi ; allocate stack 1463 .00010000 .00000100 .000040FF 13000000 1464 # rs1_sp rs2_ra sw ; protect ra 1465 .00000100 .00001000 23200000 1466 # rs1_sp rs2_a1 @4 sw ; protect a1 1467 .00000100 .0000B000 .00020000 23200000 1468 # rs1_sp rs2_a2 @8 sw ; protect a2 1469 .00000100 .0000C000 .00040000 23200000 1470 1471 # rd_a1 rs1_s4 mv ; I = HEAD 1472 .80050000 .00000A00 13000000 1473 1474 :Print_Hex_Loop 1475 # rd_a0 rs1_a1 !4 lw ; I->TYPE 1476 .00050000 .00800500 .00004000 03200000 1477 # rd_t0 !1 addi ; t0 = MACRO 1478 .80020000 .00001000 13000000 1479 # rs1_a0 rs2_t0 @Print_Hex_Next beq ; Skip if MACRO = I->TYPE 1480 .00000500 .00005000 @Print_Hex_Next 63000000 1481 1482 # rd_a0 rs1_a1 !12 lw ; Using EXPRESSION 1483 .00050000 .00800500 .0000C000 03200000 1484 # rd_ra $File_Print jal ; Print it 1485 .80000000 $File_Print 6F000000 1486 # rd_a0 !10 addi ; \n 1487 .00050000 .0000A000 13000000 1488 # rd_ra $fputc jal ; Print newline 1489 .80000000 $fputc 6F000000 1490 1491 :Print_Hex_Next 1492 # rd_a1 rs1_a1 lw ; Iterate to next Token 1493 .80050000 .00800500 03200000 1494 # rs1_a1 @Print_Hex_Loop bnez ; Stop if NULL, otherwise keep looping 1495 .00800500 @Print_Hex_Loop 63100000 1496 1497 # rd_ra rs1_sp lw ; restore ra 1498 .80000000 .00000100 03200000 1499 # rd_a1 rs1_sp !4 lw ; restore a1 1500 .80050000 .00000100 .00004000 03200000 1501 # rd_a2 rs1_sp !8 lw ; restore a2 1502 .00060000 .00000100 .00008000 03200000 1503 # rd_sp rs1_sp !12 addi ; deallocate stack 1504 .00010000 .00000100 .0000C000 13000000 1505 # ret 1506 67800000 1507 1508 1509 ; File_Print function 1510 ; Receives CHAR* in a0 1511 ; calls fputc for every non-null char 1512 :File_Print 1513 # rd_sp rs1_sp !-12 addi ; allocate stack 1514 .00010000 .00000100 .000040FF 13000000 1515 # rs1_sp rs2_ra sw ; protect ra 1516 .00000100 .00001000 23200000 1517 # rs1_sp rs2_a1 @4 sw ; protect a1 1518 .00000100 .0000B000 .00020000 23200000 1519 # rs1_sp rs2_a2 @8 sw ; protect a2 1520 .00000100 .0000C000 .00040000 23200000 1521 # rd_a1 rs1_a0 mv ; protect a0 1522 .80050000 .00000500 13000000 1523 1524 # rs1_a0 @File_Print_Done beqz ; Protect against nulls 1525 .00000500 @File_Print_Done 63000000 1526 1527 :File_Print_Loop 1528 # rd_a0 rs1_a1 lbu ; Read byte 1529 .00050000 .00800500 03400000 1530 # rs1_a0 @File_Print_Done beqz ; Stop at NULL 1531 .00000500 @File_Print_Done 63000000 1532 1533 # rd_ra $fputc jal ; print it 1534 .80000000 $fputc 6F000000 1535 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1536 .80050000 .00800500 .00001000 13000000 1537 # $File_Print_Loop jal ; Keep printing 1538 $File_Print_Loop 6F000000 1539 1540 :File_Print_Done 1541 # rd_ra rs1_sp lw ; restore ra 1542 .80000000 .00000100 03200000 1543 # rd_a1 rs1_sp !4 lw ; restore a1 1544 .80050000 .00000100 .00004000 03200000 1545 # rd_a2 rs1_sp !8 lw ; restore a2 1546 .00060000 .00000100 .00008000 03200000 1547 # rd_sp rs1_sp !12 addi ; deallocate stack 1548 .00010000 .00000100 .0000C000 13000000 1549 # rs1_ra jalr ; return 1550 .00800000 67000000 1551 1552 1553 ; fgetc function 1554 ; Loads FILE* from s2 1555 ; Returns -4 (EOF) or char in a0 1556 :fgetc 1557 # rd_sp rs1_sp !-16 addi ; allocate stack 1558 .00010000 .00000100 .000000FF 13000000 1559 # rs1_sp rs2_ra @4 sw ; protect ra 1560 .00000100 .00001000 .00020000 23200000 1561 # rs1_sp rs2_a1 @8 sw ; protect a1 1562 .00000100 .0000B000 .00040000 23200000 1563 # rs1_sp rs2_a2 @12 sw ; protect a2 1564 .00000100 .0000C000 .00060000 23200000 1565 1566 # rd_a7 !63 addi ; sys_read 1567 .80080000 .0000F003 13000000 1568 # rd_a1 rs1_sp mv ; Get stack address for buffer 1569 .80050000 .00000100 13000000 1570 # rd_a0 rs1_s2 mv ; read from input file 1571 .00050000 .00000900 13000000 1572 # rd_a2 !1 addi ; read 1 character 1573 .00060000 .00001000 13000000 1574 # ecall ; syscall 1575 73000000 1576 1577 # rs1_a0 @fgetc_done bnez ; Check if nothing was read 1578 .00000500 @fgetc_done 63100000 1579 # rd_a2 !-4 addi ; Use -4 as EOF 1580 .00060000 .0000C0FF 13000000 1581 # rs1_a1 rs2_a2 sb ; Store EOF in *a1 1582 .00800500 .0000C000 23000000 1583 1584 :fgetc_done 1585 # rd_a0 rs1_a1 lb ; return char in a0 1586 .00050000 .00800500 03000000 1587 # rd_ra rs1_sp !4 lw ; restore ra 1588 .80000000 .00000100 .00004000 03200000 1589 # rd_a1 rs1_sp !8 lw ; restore a1 1590 .80050000 .00000100 .00008000 03200000 1591 # rd_a2 rs1_sp !12 lw ; restore a2 1592 .00060000 .00000100 .0000C000 03200000 1593 # rd_sp rs1_sp !16 addi ; deallocate stack 1594 .00010000 .00000100 .00000001 13000000 1595 # rs1_ra jalr ; return 1596 .00800000 67000000 1597 1598 1599 ; Malloc isn't actually required if the program being built fits in the initial memory 1600 ; However, it doesn't take much to add it. 1601 ; Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes 1602 :malloc 1603 # rd_sp rs1_sp !-8 addi ; allocate stack 1604 .00010000 .00000100 .000080FF 13000000 1605 # rs1_sp rs2_ra sw ; protect ra 1606 .00000100 .00001000 23200000 1607 # rs1_sp rs2_a1 @4 sw ; protect a1 1608 .00000100 .0000B000 .00020000 23200000 1609 1610 # rd_a1 rs1_s1 mv ; Store the current pointer 1611 .80050000 .00800400 13000000 1612 # rd_a0 rs1_a0 rs2_s1 add ; Request the number of desired bytes 1613 .00050000 .00000500 .00009000 33000000 1614 # rd_a7 !214 addi ; sys_brk 1615 .80080000 .0000600D 13000000 1616 # ecall ; syscall 1617 73000000 1618 # rd_s1 rs1_a0 mv ; Set our malloc pointer 1619 .80040000 .00000500 13000000 1620 # rd_a0 rs1_a1 mv ; Return the pointer 1621 .00050000 .00800500 13000000 1622 1623 # rd_ra rs1_sp lw ; restore ra 1624 .80000000 .00000100 03200000 1625 # rd_a1 rs1_sp !4 lw ; restore a1 1626 .80050000 .00000100 .00004000 03200000 1627 # rd_sp rs1_sp !8 addi ; deallocate stack 1628 .00010000 .00000100 .00008000 13000000 1629 # rs1_ra jalr ; return 1630 .00800000 67000000 1631 1632 1633 ; fputc function 1634 ; receives CHAR in a0 and load FILE* from s3 1635 ; writes char and returns 1636 :fputc 1637 # rd_sp rs1_sp !-16 addi ; allocate stack 1638 .00010000 .00000100 .000000FF 13000000 1639 # rs1_sp rs2_a0 sw ; protect a0 1640 .00000100 .0000A000 23200000 1641 # rs1_sp rs2_ra @4 sw ; protect ra 1642 .00000100 .00001000 .00020000 23200000 1643 # rs1_sp rs2_a1 @8 sw ; protect a1 1644 .00000100 .0000B000 .00040000 23200000 1645 # rs1_sp rs2_a2 @12 sw ; protect a2 1646 .00000100 .0000C000 .00060000 23200000 1647 1648 # rd_a7 !64 addi ; sys_write 1649 .80080000 .00000004 13000000 1650 # rd_a0 rs1_s3 mv ; write to output 1651 .00050000 .00800900 13000000 1652 # rd_a1 rs1_sp mv ; Get stack address 1653 .80050000 .00000100 13000000 1654 # rd_a2 !1 addi ; write 1 character 1655 .00060000 .00001000 13000000 1656 # ecall ; syscall 1657 73000000 1658 1659 # rd_a0 rs1_sp lw ; restore a0 1660 .00050000 .00000100 03200000 1661 # rd_ra rs1_sp !4 lw ; restore ra 1662 .80000000 .00000100 .00004000 03200000 1663 # rd_a1 rs1_sp !8 lw ; restore a1 1664 .80050000 .00000100 .00008000 03200000 1665 # rd_a2 rs1_sp !12 lw ; restore a2 1666 .00060000 .00000100 .0000C000 03200000 1667 # rd_sp rs1_sp !16 addi ; deallocate stack 1668 .00010000 .00000100 .00000001 13000000 1669 # rs1_ra jalr ; return 1670 .00800000 67000000 1671 1672 1673 :Fail 1674 ; Terminate program with 1 return code 1675 # rd_a7 !93 addi ; sys_exit 1676 .80080000 .0000D005 13000000 1677 # rd_a0 !1 addi ; Return code 1 1678 .00050000 .00001000 13000000 1679 # ecall ; exit(1) 1680 73000000 1681 1682 ; PROGRAM END 1683 1684 :terminators 1685 # " 1686 # " 1687 0A 09 20 00 1688 1689 :comments 1690 # "#;" 1691 23 3B 00 1692 1693 :string_char 1694 # '22 27 00' 1695 22 27 00 1696 1697 :DEFINE_str 1698 # "DEFINE" 1699 44 45 46 49 4E 45 00 1700 1701 :ELF_end