M0.hex2 (65364B)
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 32) 32 ; NEXT => 0 ; Next element in linked list 33 ; TYPE => 8 ; Token type 34 ; TEXT => 16 35 ; EXPRESSION => 24 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 !16 ld ; Input file name 47 .00060000 .00000100 .00000001 03300000 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 ld ; Get number of the args 73 .00050000 .00000100 03300000 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 !24 ld ; Output file (argument 3) 85 .80050000 .00000100 .00008001 03300000 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 !-8 addi ; allocate stack 153 .00010000 .00000100 .000080FF 13000000 154 # rs1_sp rs2_ra sd ; protect ra 155 .00000100 .00001000 23300000 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 !32 addi ; malloc struct P 193 .00050000 .00000002 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 sd ; P->NEXT = HEAD 199 .00800600 .00004001 23300000 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 ld ; restore ra 223 .80000000 .00000100 03300000 224 # rd_sp rs1_sp !8 addi ; deallocate stack 225 .00010000 .00000100 .00008000 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 !-8 addi ; allocate stack 235 .00010000 .00000100 .000080FF 13000000 236 # rs1_sp rs2_a1 sd ; protect a1 237 .00000100 .0000B000 23300000 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 ld ; restore a1 255 .80050000 .00000100 03300000 256 # rd_sp rs1_sp !8 addi ; deallocate stack 257 .00010000 .00000100 .00008000 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 ld ; restore a1 265 .80050000 .00000100 03300000 266 # rd_sp rs1_sp !8 addi ; deallocate stack 267 .00010000 .00000100 .00008000 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 !-24 addi ; allocate stack 290 .00010000 .00000100 .000080FE 13000000 291 # rs1_sp rs2_a1 sd ; protect a1 292 .00000100 .0000B000 23300000 293 # rs1_sp rs2_a2 @8 sd ; protect a2 294 .00000100 .0000C000 .00040000 23300000 295 # rs1_sp rs2_a3 @16 sd ; protect a3 296 .00000100 .0000D000 .00080000 23300000 297 298 # rd_a0 !2 addi ; Using TYPE STRING 299 .00050000 .00002000 13000000 300 # rs1_a3 rs2_a0 @8 sd ; HEAD->TYPE = STRING 301 .00800600 .0000A000 .00040000 23300000 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 !16 ld ; restore a3 (HEAD) 327 .80060000 .00000100 .00000001 03300000 328 # rs1_a3 rs2_a0 @16 sd ; HEAD->TEXT = STRING 329 .00800600 .0000A000 .00080000 23300000 330 # rd_ra $copy_string jal ; Copy the string 331 .80000000 $copy_string 6F000000 332 333 # rd_a1 rs1_sp ld ; restore a1 334 .80050000 .00000100 03300000 335 # rd_a2 rs1_sp !8 ld ; restore a2 336 .00060000 .00000100 .00008000 03300000 337 # rd_sp rs1_sp !24 addi ; deallocate stack 338 .00010000 .00000100 .00008001 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 !-24 addi ; allocate stack 348 .00010000 .00000100 .000080FE 13000000 349 # rs1_sp rs2_ra sd ; protect ra 350 .00000100 .00001000 23300000 351 # rs1_sp rs2_a1 @8 sd ; protect a1 352 .00000100 .0000B000 .00040000 23300000 353 # rs1_sp rs2_a2 @16 sd ; protect a2 354 .00000100 .0000C000 .00080000 23300000 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 ld ; restore ra 379 .80000000 .00000100 03300000 380 # rd_a1 rs1_sp !8 ld ; restore a1 381 .80050000 .00000100 .00008000 03300000 382 # rd_a2 rs1_sp !16 ld ; restore a2 383 .00060000 .00000100 .00000001 03300000 384 # rd_sp rs1_sp !24 addi ; deallocate stack 385 .00010000 .00000100 .00008001 13000000 386 # ret 387 67800000 388 389 390 ; Zero scratch area 391 :ClearScratch 392 # rd_sp rs1_sp !-24 addi ; allocate stack 393 .00010000 .00000100 .000080FE 13000000 394 # rs1_sp rs2_ra sd ; protect ra 395 .00000100 .00001000 23300000 396 # rs1_sp rs2_a0 @8 sd ; protect a0 397 .00000100 .0000A000 .00040000 23300000 398 # rs1_sp rs2_a1 @16 sd ; protect a1 399 .00000100 .0000B000 .00080000 23300000 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 ld ; restore ra 415 .80000000 .00000100 03300000 416 # rd_a0 rs1_sp !8 ld ; restore a0 417 .00050000 .00000100 .00008000 03300000 418 # rd_a1 rs1_sp !16 ld ; restore a1 419 .80050000 .00000100 .00000001 03300000 420 # rd_sp rs1_sp !24 addi ; deallocate stack 421 .00010000 .00000100 .00008001 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 !-32 addi ; allocate stack 431 .00010000 .00000100 .000000FE 13000000 432 # rs1_sp rs2_ra sd ; protect ra 433 .00000100 .00001000 23300000 434 # rs1_sp rs2_a1 @8 sd ; protect a1 435 .00000100 .0000B000 .00040000 23300000 436 # rs1_sp rs2_a2 @16 sd ; protect a2 437 .00000100 .0000C000 .00080000 23300000 438 # rs1_sp rs2_a3 @24 sd ; protect a3 439 .00000100 .0000D000 .000C0000 23300000 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 !24 ld ; restore a3 471 .80060000 .00000100 .00008001 03300000 472 # rs1_a3 rs2_a0 @16 sd ; HEAD->TEXT = STRING 473 .00800600 .0000A000 .00080000 23300000 474 # rd_ra $copy_string jal ; Copy the string 475 .80000000 $copy_string 6F000000 476 477 # rd_ra rs1_sp ld ; restore ra 478 .80000000 .00000100 03300000 479 # rd_a1 rs1_sp !8 ld ; restore a1 480 .80050000 .00000100 .00008000 03300000 481 # rd_a2 rs1_sp !16 ld ; restore a2 482 .00060000 .00000100 .00000001 03300000 483 # rd_sp rs1_sp !32 addi ; deallocate stack 484 .00010000 .00000100 .00000002 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 !-16 addi ; allocate stack 494 .00010000 .00000100 .000000FF 13000000 495 # rs1_sp rs2_a1 sd ; protect a1 496 .00000100 .0000B000 23300000 497 # rs1_sp rs2_a2 @8 sd ; protect a2 498 .00000100 .0000C000 .00040000 23300000 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 ld ; NEXT = HEAD->NEXT 508 .00060000 .00800500 03300000 509 # rs1_a1 rs2_a0 sd ; HEAD->NEXT = ROOT 510 .00800500 .0000A000 23300000 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 ld ; restore a1 520 .80050000 .00000100 03300000 521 # rd_a2 rs1_sp !8 ld ; restore a2 522 .00060000 .00000100 .00008000 03300000 523 # rd_sp rs1_sp !16 addi ; deallocate stack 524 .00010000 .00000100 .00000001 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 !-32 addi ; allocate stack 535 .00010000 .00000100 .000000FE 13000000 536 # rs1_sp rs2_ra sd ; protect ra 537 .00000100 .00001000 23300000 538 # rs1_sp rs2_a0 @8 sd ; protect a0 539 .00000100 .0000A000 .00040000 23300000 540 # rs1_sp rs2_a1 @16 sd ; protect a1 541 .00000100 .0000B000 .00080000 23300000 542 # rs1_sp rs2_a2 @24 sd ; protect a2 543 .00000100 .0000C000 .000C0000 23300000 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 !16 ld ; I->TEXT 554 .00050000 .00000600 .00000001 03300000 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 @8 sd ; I->TYPE = MACRO 564 .00000600 .0000A000 .00040000 23300000 565 566 # rd_a0 rs1_a2 ld ; I->NEXT 567 .00050000 .00000600 03300000 568 # rd_a0 rs1_a0 !16 ld ; I->NEXT->TEXT 569 .00050000 .00000500 .00000001 03300000 570 # rs1_a2 rs2_a0 @16 sd ; I->TEXT = I->NEXT->TEXT 571 .00000600 .0000A000 .00080000 23300000 572 573 # rd_a0 rs1_a2 ld ; I->NEXT 574 .00050000 .00000600 03300000 575 # rd_a0 rs1_a0 ld ; I->NEXT->NEXT 576 .00050000 .00000500 03300000 577 # rd_a0 rs1_a0 !16 ld ; I->NEXT->NEXT->TEXT 578 .00050000 .00000500 .00000001 03300000 579 # rs1_a2 rs2_a0 @24 sd ; I->EXPRESSION = I->NEXT->NEXT->TEXT 580 .00000600 .0000A000 .000C0000 23300000 581 582 # rd_a0 rs1_a2 ld ; I->NEXT 583 .00050000 .00000600 03300000 584 # rd_a0 rs1_a0 ld ; I->NEXT->NEXT 585 .00050000 .00000500 03300000 586 # rd_a0 rs1_a0 ld ; I->NEXT->NEXT->NEXT 587 .00050000 .00000500 03300000 588 # rs1_a2 rs2_a0 sd ; I->NEXT = I->NEXT->NEXT->NEXT 589 .00000600 .0000A000 23300000 590 591 :Identify_Macros_Next 592 # rd_a2 rs1_a2 ld ; I = I->NEXT 593 .00060000 .00000600 03300000 594 # rs1_a2 @Identify_Macros_Loop bnez ; Check if we are done 595 .00000600 @Identify_Macros_Loop 63100000 596 597 # rd_ra rs1_sp ld ; restore ra 598 .80000000 .00000100 03300000 599 # rd_a0 rs1_sp !8 ld ; restore a0 600 .00050000 .00000100 .00008000 03300000 601 # rd_a1 rs1_sp !16 ld ; restore a1 602 .80050000 .00000100 .00000001 03300000 603 # rd_a2 rs1_sp !24 ld ; restore a2 604 .00060000 .00000100 .00008001 03300000 605 # rd_sp rs1_sp !32 addi ; deallocate stack 606 .00010000 .00000100 .00000002 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 !-24 addi ; allocate stack 616 .00010000 .00000100 .000080FE 13000000 617 # rs1_sp rs2_a1 sd ; protect a1 618 .00000100 .0000B000 23300000 619 # rs1_sp rs2_a2 @8 sd ; protect a2 620 .00000100 .0000C000 .00040000 23300000 621 # rs1_sp rs2_a3 @16 sd ; protect a3 622 .00000100 .0000D000 .00080000 23300000 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 ld ; restore a1 651 .80050000 .00000100 03300000 652 # rd_a2 rs1_sp !8 ld ; restore a2 653 .00060000 .00000100 .00008000 03300000 654 # rd_a3 rs1_sp !16 ld ; restore a3 655 .80060000 .00000100 .00000001 03300000 656 # rd_sp rs1_sp !24 addi ; deallocate stack 657 .00010000 .00000100 .00008001 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 !-32 addi ; allocate stack 668 .00010000 .00000100 .000000FE 13000000 669 # rs1_sp rs2_ra sd ; protect ra 670 .00000100 .00001000 23300000 671 # rs1_sp rs2_a0 @8 sd ; protect a0 672 .00000100 .0000A000 .00040000 23300000 673 # rs1_sp rs2_a1 @16 sd ; protect a1 674 .00000100 .0000B000 .00080000 23300000 675 # rs1_sp rs2_a2 @24 sd ; protect a2 676 .00000100 .0000C000 .000C0000 23300000 677 678 :Line_Macro_Loop 679 # rd_a1 rs1_a0 !8 ld ; I->TYPE 680 .80050000 .00000500 .00008000 03300000 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 !16 ld ; I->TEXT 688 .80050000 .00000500 .00000001 03300000 689 # rd_a2 rs1_a0 !24 ld ; I->EXPRESSION 690 .00060000 .00000500 .00008001 03300000 691 # rd_a0 rs1_a0 ld ; I->NEXT 692 .00050000 .00000500 03300000 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 ld ; I->NEXT 700 .00050000 .00000500 03300000 701 # rs1_a0 @Line_Macro_Loop bnez ; Check if we are done 702 .00000500 @Line_Macro_Loop 63100000 703 704 # rd_ra rs1_sp ld ; restore ra 705 .80000000 .00000100 03300000 706 # rd_a0 rs1_sp !8 ld ; restore a0 707 .00050000 .00000100 .00008000 03300000 708 # rd_a1 rs1_sp !16 ld ; restore a1 709 .80050000 .00000100 .00000001 03300000 710 # rd_a2 rs1_sp !24 ld ; restore a2 711 .00060000 .00000100 .00008001 03300000 712 # rd_sp rs1_sp !32 addi ; deallocate stack 713 .00010000 .00000100 .00000002 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 !-40 addi ; allocate stack 724 .00010000 .00000100 .000080FD 13000000 725 # rs1_sp rs2_ra sd ; protect ra 726 .00000100 .00001000 23300000 727 # rs1_sp rs2_a0 @8 sd ; protect a0 728 .00000100 .0000A000 .00040000 23300000 729 # rs1_sp rs2_a1 @16 sd ; protect a1 730 .00000100 .0000B000 .00080000 23300000 731 # rs1_sp rs2_a2 @24 sd ; protect a2 732 .00000100 .0000C000 .000C0000 23300000 733 # rs1_sp rs2_a3 @32 sd ; protect a3 734 .00000100 .0000D000 .00000002 23300000 735 736 # rd_a3 rs1_a0 mv ; Set I 737 .80060000 .00000500 13000000 738 :Set_Expression_Loop 739 # rd_a0 rs1_a3 !8 ld ; I->TYPE 740 .00050000 .00800600 .00008000 03300000 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 !16 ld ; I->TEXT 747 .00050000 .00800600 .00000001 03300000 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 @24 sd ; I->EXPRESSION = EXP 755 .00800600 .0000C000 .000C0000 23300000 756 757 :Set_Expression_Next 758 # rd_a3 rs1_a3 ld ; I = I->NEXT 759 .80060000 .00800600 03300000 760 # rs1_a3 @Set_Expression_Loop bnez ; Check if we are done 761 .00800600 @Set_Expression_Loop 63100000 762 # rd_ra rs1_sp ld ; restore ra 763 .80000000 .00000100 03300000 764 # rd_a0 rs1_sp !8 ld ; restore a0 765 .00050000 .00000100 .00008000 03300000 766 # rd_a1 rs1_sp !16 ld ; restore a1 767 .80050000 .00000100 .00000001 03300000 768 # rd_a2 rs1_sp !24 ld ; restore a2 769 .00060000 .00000100 .00008001 03300000 770 # rd_a3 rs1_sp !32 ld ; restore a3 771 .80060000 .00000100 .00000002 03300000 772 # rd_sp rs1_sp !40 addi ; deallocate stack 773 .00010000 .00000100 .00008002 13000000 774 # rs1_ra jalr ; return 775 .00800000 67000000 776 777 778 ; Process_String function 779 ; Receives List in a0 780 ; Update the list in place; does not modify registers 781 ; Uses a1 for I->TEXT, a2 for I and RDX for S 782 :Process_String 783 # rd_sp rs1_sp !-40 addi ; allocate stack 784 .00010000 .00000100 .000080FD 13000000 785 # rs1_sp rs2_ra sd ; protect ra 786 .00000100 .00001000 23300000 787 # rs1_sp rs2_a0 @8 sd ; protect a0 788 .00000100 .0000A000 .00040000 23300000 789 # rs1_sp rs2_a1 @16 sd ; protect a1 790 .00000100 .0000B000 .00080000 23300000 791 # rs1_sp rs2_a2 @24 sd ; protect a2 792 .00000100 .0000C000 .000C0000 23300000 793 # rs1_sp rs2_a3 @32 sd ; protect a3 794 .00000100 .0000D000 .00000002 23300000 795 796 # rd_a2 rs1_a0 mv ; I = HEAD 797 .00060000 .00000500 13000000 798 799 :Process_String_loop 800 # rd_a0 rs1_a2 !8 ld ; I->TYPE 801 .00050000 .00000600 .00008000 03300000 802 # rd_t0 !2 addi ; t0 = STRING 803 .80020000 .00002000 13000000 804 # rs1_a0 rs2_t0 @Process_String_Next bne ; Skip to next 805 .00000500 .00005000 @Process_String_Next 63100000 806 807 # rd_a1 rs1_a2 !16 ld ; I->TEXT 808 .80050000 .00000600 .00000001 03300000 809 # rd_a0 rs1_a1 lbu ; I->TEXT[0] 810 .00050000 .00800500 03400000 811 # rd_t0 !39 addi ; t0 = \' 812 .80020000 .00007002 13000000 813 # rs1_a0 rs2_t0 @Process_String_Raw bne ; Deal with '"' 814 .00000500 .00005000 @Process_String_Raw 63100000 815 816 ; Deal with \' 817 # rd_a1 rs1_a1 !1 addi ; I->TEXT + 1 818 .80050000 .00800500 .00001000 13000000 819 # rs1_a2 rs2_a1 @24 sd ; I->EXPRESSION = I->TEXT + 1 820 .00000600 .0000B000 .000C0000 23300000 821 # $Process_String_Next jal ; Move on to next 822 $Process_String_Next 6F000000 823 824 :Process_String_Raw 825 # rd_a0 rs1_a1 mv ; I->TEXT 826 .00050000 .00800500 13000000 827 # rd_ra $string_length jal ; Get length of I->TEXT 828 .80000000 $string_length 6F000000 829 # rd_a0 rs1_a0 rs2_x2 srli ; LENGTH = LENGTH >> 2 830 .00050000 .00000500 .00002000 13500000 831 # rd_a0 rs1_a0 !1 addi ; LENGTH = LENGTH + 1 832 .00050000 .00000500 .00001000 13000000 833 # rd_a0 rs1_a0 rs2_x3 slli ; LENGTH = LENGTH << 3 834 .00050000 .00000500 .00003000 13100000 835 # rd_ra $malloc jal ; Get string 836 .80000000 $malloc 6F000000 837 # rd_a3 rs1_a1 mv ; S = I->TEXT 838 .80060000 .00800500 13000000 839 # rd_a3 rs1_a3 !1 addi ; S = S + 1 840 .80060000 .00800600 .00001000 13000000 841 # rs1_a2 rs2_a0 @24 sd ; I->EXPRESSION = hexify 842 .00000600 .0000A000 .000C0000 23300000 843 # rd_a1 rs1_a0 mv ; Put hexify buffer in a1 844 .80050000 .00000500 13000000 845 846 :Process_String_Raw_Loop 847 # rd_a0 rs1_a3 lbu ; Read 1 character 848 .00050000 .00800600 03400000 849 # rd_a3 rs1_a3 !1 addi ; S = S + 1 850 .80060000 .00800600 .00001000 13000000 851 # rd_s5 rs1_a0 mv ; Protect character 852 .800A0000 .00000500 13000000 853 # rd_ra $hex8 jal ; write them all 854 .80000000 $hex8 6F000000 855 # rd_a0 rs1_s5 mv ; Restore character 856 .00050000 .00800A00 13000000 857 # rs1_a0 @Process_String_Raw_Loop bnez ; Keep looping 858 .00000500 @Process_String_Raw_Loop 63100000 859 860 :Process_String_Next 861 # rd_a2 rs1_a2 ld ; I = I->NEXT 862 .00060000 .00000600 03300000 863 # rs1_a2 @Process_String_loop bnez ; Check if we are done 864 .00000600 @Process_String_loop 63100000 865 866 # rd_ra rs1_sp ld ; restore ra 867 .80000000 .00000100 03300000 868 # rd_a0 rs1_sp !8 ld ; restore a0 869 .00050000 .00000100 .00008000 03300000 870 # rd_a1 rs1_sp !16 ld ; restore a1 871 .80050000 .00000100 .00000001 03300000 872 # rd_a2 rs1_sp !24 ld ; restore a2 873 .00060000 .00000100 .00008001 03300000 874 # rd_a3 rs1_sp !32 ld ; restore a3 875 .80060000 .00000100 .00000002 03300000 876 # rd_sp rs1_sp !40 addi ; deallocate stack 877 .00010000 .00000100 .00008002 13000000 878 # rs1_ra jalr ; return 879 .00800000 67000000 880 881 882 ; string_length function 883 ; Receives CHAR* in a0 884 ; Returns INT in a0 885 ; Uses a0 for CH, a1 for S and a2 for INDEX 886 :string_length 887 # rd_sp rs1_sp !-16 addi ; allocate stack 888 .00010000 .00000100 .000000FF 13000000 889 # rs1_sp rs2_a1 sd ; protect a1 890 .00000100 .0000B000 23300000 891 # rs1_sp rs2_a2 @8 sd ; protect a2 892 .00000100 .0000C000 .00040000 23300000 893 894 # rd_a1 rs1_a0 mv ; Set S 895 .80050000 .00000500 13000000 896 # rd_a2 mv ; INDEX = 0 897 .00060000 13000000 898 899 :string_length_loop 900 # rd_t0 rs1_a1 rs2_a2 add ; S + INDEX 901 .80020000 .00800500 .0000C000 33000000 902 # rd_a0 rs1_t0 lbu ; S[INDEX] 903 .00050000 .00800200 03400000 904 # rs1_a0 @string_length_done beqz ; Check if we are done 905 .00000500 @string_length_done 63000000 906 907 # rd_a2 rs1_a2 !1 addi ; INDEX = INDEX + 1 908 .00060000 .00000600 .00001000 13000000 909 # $string_length_loop jal ; Keep going 910 $string_length_loop 6F000000 911 912 :string_length_done 913 # rd_a0 rs1_a2 mv ; return INDEX 914 .00050000 .00000600 13000000 915 # rd_a1 rs1_sp ld ; restore a1 916 .80050000 .00000100 03300000 917 # rd_a2 rs1_sp !8 ld ; restore a2 918 .00060000 .00000100 .00008000 03300000 919 # rd_sp rs1_sp !16 addi ; deallocate stack 920 .00010000 .00000100 .00000001 13000000 921 # rs1_ra jalr ; return 922 .00800000 67000000 923 924 925 ; Eval_Immediates function 926 ; Receives List in a0 927 ; Updates the list in place; does not modify registers 928 ; Uses a1 for I->TEXT[0], a2 for I->TEXT[1] and a3 for I 929 :Eval_Immediates 930 # rd_sp rs1_sp !-40 addi ; allocate stack 931 .00010000 .00000100 .000080FD 13000000 932 # rs1_sp rs2_ra sd ; protect ra 933 .00000100 .00001000 23300000 934 # rs1_sp rs2_a0 @8 sd ; protect a0 935 .00000100 .0000A000 .00040000 23300000 936 # rs1_sp rs2_a1 @16 sd ; protect a1 937 .00000100 .0000B000 .00080000 23300000 938 # rs1_sp rs2_a2 @24 sd ; protect a2 939 .00000100 .0000C000 .000C0000 23300000 940 # rs1_sp rs2_a3 @32 sd ; protect a3 941 .00000100 .0000D000 .00000002 23300000 942 943 # rd_a3 rs1_a0 mv ; I = HEAD 944 .80060000 .00000500 13000000 945 946 :Eval_Immediates_Loop 947 ; Check for MACRO 948 # rd_a0 rs1_a3 !8 ld ; I->TYPE 949 .00050000 .00800600 .00008000 03300000 950 # rd_t0 !1 addi ; t0 = MACRO 951 .80020000 .00001000 13000000 952 # rs1_a0 rs2_t0 @Eval_Immediates_Next beq ; Skip to next if I->TYPE == MACRO 953 .00000500 .00005000 @Eval_Immediates_Next 63000000 954 955 ; Check for NULL EXPRESSION 956 # rd_a0 rs1_a3 !24 ld ; I->EXPRESSION 957 .00050000 .00800600 .00008001 03300000 958 # rs1_a0 @Eval_Immediates_Next bnez ; Skip to next if NULL == I->EXPRESSION 959 .00000500 @Eval_Immediates_Next 63100000 960 961 ; Check if number 962 # rd_a0 rs1_a3 !16 ld ; I->TEXT 963 .00050000 .00800600 .00000001 03300000 964 # rd_a1 rs1_a0 lbu ; I->TEXT[0] 965 .80050000 .00000500 03400000 966 # rd_a0 rs1_a0 !1 addi ; I->TEXT + 1 967 .00050000 .00000500 .00001000 13000000 968 # rd_a2 rs1_a0 lbu ; I->TEXT[1] 969 .00060000 .00000500 03400000 970 # rd_ra $numerate_string jal ; Convert string to INT 971 .80000000 $numerate_string 6F000000 972 # rs1_a0 @Eval_Immediates_value bnez ; Has a value IF 0 != numerate_string(I->TEXT + 1) 973 .00000500 @Eval_Immediates_value 63100000 974 975 ; Last chance for Immediate 976 # rd_t0 !48 addi ; If '0' = I->TEXT[1] 977 .80020000 .00000003 13000000 978 # rs1_a2 rs2_t0 @Eval_Immediates_Next bne ; Skip to next 979 .00000600 .00005000 @Eval_Immediates_Next 63100000 980 981 :Eval_Immediates_value 982 # rd_ra $express_number jal ; Convert value to hex string 983 .80000000 $express_number 6F000000 984 # rs1_a3 rs2_a0 @24 sd ; I->EXPRESSION = express_number(value, I-TEXT[0]) 985 .00800600 .0000A000 .000C0000 23300000 986 987 :Eval_Immediates_Next 988 # rd_a3 rs1_a3 ld ; I = I->NEXT 989 .80060000 .00800600 03300000 990 # rs1_a3 @Eval_Immediates_Loop bnez ; Check if we are done 991 .00800600 @Eval_Immediates_Loop 63100000 992 993 # rd_ra rs1_sp ld ; restore ra 994 .80000000 .00000100 03300000 995 # rd_a0 rs1_sp !8 ld ; restore a0 996 .00050000 .00000100 .00008000 03300000 997 # rd_a1 rs1_sp !16 ld ; restore a1 998 .80050000 .00000100 .00000001 03300000 999 # rd_a2 rs1_sp !24 ld ; restore a2 1000 .00060000 .00000100 .00008001 03300000 1001 # rd_a3 rs1_sp !32 ld ; restore a3 1002 .80060000 .00000100 .00000002 03300000 1003 # rd_sp rs1_sp !40 addi ; deallocate stack 1004 .00010000 .00000100 .00008002 13000000 1005 # rs1_ra jalr ; return 1006 .00800000 67000000 1007 1008 1009 ; numerate_string function 1010 ; Receives CHAR* in a0 1011 ; Returns value of CHAR* in a0 1012 ; Uses a0 for VALUE, a1 for S, a2 for CH and a3 for NEGATIVE? 1013 :numerate_string 1014 # rd_sp rs1_sp !-24 addi ; allocate stack 1015 .00010000 .00000100 .000080FE 13000000 1016 # rs1_sp rs2_a1 sd ; protect a1 1017 .00000100 .0000B000 23300000 1018 # rs1_sp rs2_a2 @8 sd ; protect a2 1019 .00000100 .0000C000 .00040000 23300000 1020 # rs1_sp rs2_a3 @16 sd ; protect a3 1021 .00000100 .0000D000 .00080000 23300000 1022 1023 # rd_a1 rs1_a0 mv ; put S in correct place 1024 .80050000 .00000500 13000000 1025 # rd_a0 mv ; Initialize to Zero 1026 .00050000 13000000 1027 :numerate_string_loop 1028 # rd_t0 rs1_a1 !1 addi ; S + 1 1029 .80020000 .00800500 .00001000 13000000 1030 # rd_a2 rs1_t0 lbu ; S[1] 1031 .00060000 .00800200 03400000 1032 # rd_t0 !120 addi ; 'x' 1033 .80020000 .00008007 13000000 1034 # rs1_a2 rs2_t0 @numerate_hex beq ; Deal with hex_input 1035 .00000600 .00005000 @numerate_hex 63000000 1036 1037 ; Assume decimal input 1038 # rd_a3 mv ; Assume no negation 1039 .80060000 13000000 1040 # rd_a2 rs1_a1 lbu ; S[0] 1041 .00060000 .00800500 03400000 1042 # rd_t0 !45 addi ; '-' 1043 .80020000 .0000D002 13000000 1044 # rs1_a2 rs2_t0 @numerate_decimal bne ; Skip negation 1045 .00000600 .00005000 @numerate_decimal 63100000 1046 1047 # rd_a3 !1 addi ; Set FLAG 1048 .80060000 .00001000 13000000 1049 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1050 .80050000 .00800500 .00001000 13000000 1051 1052 :numerate_decimal 1053 # rd_a2 rs1_a1 lbu ; S[i] 1054 .00060000 .00800500 03400000 1055 # rs1_a2 @numerate_decimal_done beqz ; We are done if NULL == S[i] 1056 .00000600 @numerate_decimal_done 63000000 1057 1058 ; a0 = a0 * 10 = (a0 << 3) + (a0 << 1) 1059 # rd_t0 rs1_a0 rs2_x3 slli ; a0 * 8 1060 .80020000 .00000500 .00003000 13100000 1061 # rd_t1 rs1_a0 rs2_x1 slli ; a0 * 2 1062 .00030000 .00000500 .00001000 13100000 1063 # rd_a0 rs1_t0 rs2_t1 add ; VALUE = VALUE * 10 1064 .00050000 .00800200 .00006000 33000000 1065 # rd_a2 rs1_a2 !-48 addi ; CH = CH - '0' 1066 .00060000 .00000600 .000000FD 13000000 1067 # rd_t0 !9 addi ; t0 = 9 1068 .80020000 .00009000 13000000 1069 # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for illegal CH > 9 1070 .00800200 .0000C000 @numerate_string_fail 63400000 1071 # rs1_a2 @numerate_string_fail bltz ; Check for illegal CH < 0 1072 .00000600 @numerate_string_fail 63400000 1073 # rd_a0 rs1_a0 rs2_a2 add ; VALUE = VALUE + CH 1074 .00050000 .00000500 .0000C000 33000000 1075 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1076 .80050000 .00800500 .00001000 13000000 1077 # $numerate_decimal jal 1078 $numerate_decimal 6F000000 1079 1080 :numerate_decimal_done 1081 # rd_t0 !1 addi ; Check for negative FLAG 1082 .80020000 .00001000 13000000 1083 # rs1_a3 rs2_t0 @numerate_string_done bne ; Nope 1084 .00800600 .00005000 @numerate_string_done 63100000 1085 1086 # rd_a0 rs2_a0 sub ; VALUE = -VALUE 1087 .00050000 .0000A000 33000040 1088 # $numerate_string_done jal ; Done 1089 $numerate_string_done 6F000000 1090 1091 :numerate_hex 1092 # rd_a1 rs1_a1 !2 addi ; S = S + 2 1093 .80050000 .00800500 .00002000 13000000 1094 :numerate_hex_loop 1095 # rd_a2 rs1_a1 lbu ; S[i] 1096 .00060000 .00800500 03400000 1097 # rs1_a2 @numerate_string_done beqz ; We are done if NULL == S[i] 1098 .00000600 @numerate_string_done 63000000 1099 1100 # rd_a0 rs1_a0 rs2_x4 slli ; VALUE = VALUE << 4 1101 .00050000 .00000500 .00004000 13100000 1102 # rd_a2 rs1_a2 !-48 addi ; CH = CH - '0' 1103 .00060000 .00000600 .000000FD 13000000 1104 # rd_t0 !10 addi ; t0 = 10 1105 .80020000 .0000A000 13000000 1106 # rs1_a2 rs2_t0 @numerate_hex_digit blt ; Check if we are dealing with number or letter 1107 .00000600 .00005000 @numerate_hex_digit 63400000 1108 # rd_a2 rs1_a2 !-7 addi ; Push A-F into range 1109 .00060000 .00000600 .000090FF 13000000 1110 1111 :numerate_hex_digit 1112 # rd_t0 !15 addi ; t0 = 15 1113 .80020000 .0000F000 13000000 1114 # rs1_t0 rs2_a2 @numerate_string_fail blt ; Check for CH > 'F' 1115 .00800200 .0000C000 @numerate_string_fail 63400000 1116 # rs1_a2 @numerate_string_fail bltz ; Check for CH < 0 1117 .00000600 @numerate_string_fail 63400000 1118 # rd_a0 rs1_a0 rs2_a2 add ; VALUE = VALUE + CH 1119 .00050000 .00000500 .0000C000 33000000 1120 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1121 .80050000 .00800500 .00001000 13000000 1122 # $numerate_hex_loop jal ; Keep looping 1123 $numerate_hex_loop 6F000000 1124 1125 :numerate_string_fail 1126 # rd_a0 mv ; return ZERO 1127 .00050000 13000000 1128 1129 :numerate_string_done 1130 # rd_a1 rs1_sp ld ; restore a1 1131 .80050000 .00000100 03300000 1132 # rd_a2 rs1_sp !8 ld ; restore a2 1133 .00060000 .00000100 .00008000 03300000 1134 # rd_a3 rs1_sp !16 ld ; restore a3 1135 .80060000 .00000100 .00000001 03300000 1136 # rd_sp rs1_sp !24 addi ; deallocate stack 1137 .00010000 .00000100 .00008001 13000000 1138 # rs1_ra jalr ; return 1139 .00800000 67000000 1140 1141 1142 ; express_number function 1143 ; Receives INT in a0 and CHAR in a1 1144 ; Allocates a string and expresses the value in appropriate RISC-V encoding 1145 ; Returns string in a0 1146 ; Uses a0 for VALUE, a1 for S and a2 for CH 1147 :express_number 1148 # rd_sp rs1_sp !-32 addi ; allocate stack 1149 .00010000 .00000100 .000000FE 13000000 1150 # rs1_sp rs2_ra sd ; protect ra 1151 .00000100 .00001000 23300000 1152 # rs1_sp rs2_a1 @8 sd ; protect a1 1153 .00000100 .0000B000 .00040000 23300000 1154 # rs1_sp rs2_a2 @16 sd ; protect a2 1155 .00000100 .0000C000 .00080000 23300000 1156 # rs1_sp rs2_a3 @24 sd ; protect a3 1157 .00000100 .0000D000 .000C0000 23300000 1158 1159 # rd_a2 rs1_a1 mv ; Put CH in right place 1160 .00060000 .00800500 13000000 1161 # rd_s5 rs1_a0 mv ; Protect VALUE 1162 .800A0000 .00000500 13000000 1163 1164 # rd_a0 !10 addi ; We need 10 bytes 1165 .00050000 .0000A000 13000000 1166 # rd_ra $malloc jal ; Get S pointer 1167 .80000000 $malloc 6F000000 1168 # rd_a1 rs1_a0 mv ; Put S in place 1169 .80050000 .00000500 13000000 1170 # rd_a0 rs1_s5 mv ; Restore VALUE 1171 .00050000 .00800A00 13000000 1172 1173 ; Check for % 1174 # rd_t0 !0x25 addi 1175 .80020000 .00005002 13000000 1176 # rs1_a2 rs2_t0 @express_number_const beq 1177 .00000600 .00005000 @express_number_const 63000000 1178 1179 # rd_s5 rs1_a1 mv ; Protect S 1180 .800A0000 .00800500 13000000 1181 # rd_t0 !0x2E addi ; t0 = '.' 1182 .80020000 .0000E002 13000000 1183 # rs1_a1 rs2_t0 sd ; S[0] = '.' 1184 .00800500 .00005000 23300000 1185 # rd_a1 rs1_a1 !1 addi ; Next byte 1186 .80050000 .00800500 .00001000 13000000 1187 1188 ; Check for ! 1189 # rd_t0 !0x21 addi 1190 .80020000 .00001002 13000000 1191 # rs1_a2 rs2_t0 @express_number_I beq 1192 .00000600 .00005000 @express_number_I 63000000 1193 1194 ; Check for @ 1195 # rd_t0 !0x40 addi 1196 .80020000 .00000004 13000000 1197 # rs1_a2 rs2_t0 @express_number_S beq 1198 .00000600 .00005000 @express_number_S 63000000 1199 1200 ; Check for ~ 1201 # rd_t0 !0x7E addi 1202 .80020000 .0000E007 13000000 1203 # rs1_a2 rs2_t0 @express_number_U beq 1204 .00000600 .00005000 @express_number_U 63000000 1205 1206 # $Fail jal ; Error 1207 $Fail 6F000000 1208 1209 :express_number_const 1210 ; provides an option for 32-bit immediate constants 1211 1212 # rd_t0 !2 addi 1213 .80020000 .00002000 13000000 1214 # rd_t0 rs1_t0 rs2_x31 slli 1215 .80020000 .00800200 .0000F001 13100000 1216 # rd_t0 rs1_t0 !-1 addi ; t0 = 0xffffffff 1217 .80020000 .00800200 .0000F0FF 13000000 1218 # rd_a0 rs1_a0 rs2_t0 and ; immediate = value & 0xffffffff 1219 .00050000 .00000500 .00005000 33700000 1220 1221 # rd_s5 rs1_a1 mv ; Protect S 1222 .800A0000 .00800500 13000000 1223 # rd_ra $hex32l jal ; Store 32-bits 1224 .80000000 $hex32l 6F000000 1225 # $express_number_done jal ; done 1226 $express_number_done 6F000000 1227 1228 :express_number_I 1229 ; Corresponds to RISC-V S format 1230 ; (value & 0xfff) << 20 1231 # rd_t0 !0xFFF addi 1232 .80020000 .0000F0FF 13000000 1233 # rd_a0 rs1_a0 rs2_t0 and ; value & 0xfff 1234 .00050000 .00000500 .00005000 33700000 1235 # rd_a0 rs1_a0 rs2_x20 slli ; (value & 0xfff) << 20 1236 .00050000 .00000500 .00004001 13100000 1237 # rd_ra $hex32l jal ; Store 32-bits 1238 .80000000 $hex32l 6F000000 1239 # $express_number_done jal ; done 1240 $express_number_done 6F000000 1241 1242 :express_number_S 1243 ; Corresponds to RISC-V S format 1244 ; ((value & 0x1f) << 7) | ((value & 0xfe0) << (31 - 11)) 1245 # rd_t0 !0x1F addi 1246 .80020000 .0000F001 13000000 1247 # rd_t1 rs1_a0 rs2_t0 and ; value & 0x1f 1248 .00030000 .00000500 .00005000 33700000 1249 # rd_t1 rs1_t1 rs2_x7 slli ; (value & 0x1f) << 7 1250 .00030000 .00000300 .00007000 13100000 1251 # rd_t0 !0xFE0 addi 1252 .80020000 .000000FE 13000000 1253 # rd_t0 rs1_a0 rs2_t0 and ; value & 0xfe0 1254 .80020000 .00000500 .00005000 33700000 1255 # rd_t0 rs1_t0 rs2_x20 slli ; (value & 0xfe0) << (31 - 11) 1256 .80020000 .00800200 .00004001 13100000 1257 # rd_a0 rs1_t0 rs2_t1 or ; Combine two parts 1258 .00050000 .00800200 .00006000 33600000 1259 # rd_ra $hex32l jal ; Store 32-bits 1260 .80000000 $hex32l 6F000000 1261 # $express_number_done jal ; done 1262 $express_number_done 6F000000 1263 1264 :express_number_U 1265 ; Corresponds to RISC-V U format 1266 ; if value is 0x800 or more we have to add 11-th bit (0x1000) to compensate for signed extension 1267 1268 # rd_t0 ~0x800 lui ; load higher bits 1269 .80020000 .00100000 37000000 1270 # rd_t0 rs1_t0 !0x800 addiw 1271 .80020000 .00800200 .00000080 1B000000 1272 # rd_t1 ~0xFFF lui ; load higher bits 1273 .00030000 .00100000 37000000 1274 # rd_t1 rs1_t1 !0xFFF addiw 1275 .00030000 .00000300 .0000F0FF 1B000000 1276 ; We are outside 31-bit that ~ can normally load 1277 # rd_t2 ~0x100000 lui ; load 0xfffff000 1278 .80030000 .00001000 37000000 1279 # rd_t2 rs1_t2 !-1 addiw ; load 0xfffff000 1280 .80030000 .00800300 .0000F0FF 1B000000 1281 # rd_t2 rs1_t2 rs2_x12 slli ; load 0xfffff000 1282 .80030000 .00800300 .0000C000 13100000 1283 # rd_t1 rs1_a0 rs2_t1 and ; value & 0xfff 1284 .00030000 .00000500 .00006000 33700000 1285 # rd_a0 rs1_a0 rs2_t2 and ; value & 0xfffff000 1286 .00050000 .00000500 .00007000 33700000 1287 # rs1_t1 rs2_t0 @express_number_U_small blt 1288 .00000300 .00005000 @express_number_U_small 63400000 1289 1290 ; Deal with sign extension: add 0x1000 1291 # rd_t0 ~0x1000 lui 1292 .80020000 .00100000 37000000 1293 # rd_a0 rs1_t0 rs2_a0 addw ; (value & 0xfffff000) + 0x1000 1294 .00050000 .00800200 .0000A000 3B000000 1295 :express_number_U_small 1296 # rd_ra $hex32l jal ; Store 32-bits 1297 .80000000 $hex32l 6F000000 1298 # $express_number_done jal ; done 1299 $express_number_done 6F000000 1300 1301 :express_number_done 1302 # rd_a0 rs1_s5 mv ; Restore S 1303 .00050000 .00800A00 13000000 1304 # rd_ra rs1_sp ld ; restore ra 1305 .80000000 .00000100 03300000 1306 # rd_a1 rs1_sp !8 ld ; restore a1 1307 .80050000 .00000100 .00008000 03300000 1308 # rd_a2 rs1_sp !16 ld ; restore a2 1309 .00060000 .00000100 .00000001 03300000 1310 # rd_a3 rs1_sp !24 ld ; restore a3 1311 .80060000 .00000100 .00008001 03300000 1312 # rd_sp rs1_sp !32 addi ; deallocate stack 1313 .00010000 .00000100 .00000002 13000000 1314 # rs1_ra jalr ; return 1315 .00800000 67000000 1316 1317 1318 ; HEX to ascii routine 1319 ; Receives INT in a0 and CHAR* in a1 1320 ; Stores ascii of INT in CHAR* 1321 ; Returns only modifying a0 1322 :hex32l 1323 # rd_sp rs1_sp !-16 addi ; allocate stack 1324 .00010000 .00000100 .000000FF 13000000 1325 # rs1_sp rs2_ra sd ; Protect ra 1326 .00000100 .00001000 23300000 1327 # rs1_sp rs2_a0 @8 sd ; Protect top 16 bits 1328 .00000100 .0000A000 .00040000 23300000 1329 # rd_ra $hex16l jal ; Store it 1330 .80000000 $hex16l 6F000000 1331 # rd_a0 rs1_sp !8 ld ; do high 16-bits 1332 .00050000 .00000100 .00008000 03300000 1333 # rd_a0 rs1_a0 rs2_x16 srli ; do bottom 16 bits 1334 .00050000 .00000500 .00000001 13500000 1335 # rd_ra $hex16l jal ; Store it 1336 .80000000 $hex16l 6F000000 1337 # rd_ra rs1_sp ld ; restore ra 1338 .80000000 .00000100 03300000 1339 # rd_sp rs1_sp !16 addi ; deallocate stack 1340 .00010000 .00000100 .00000001 13000000 1341 # rs1_ra jalr ; return 1342 .00800000 67000000 1343 1344 :hex16l 1345 # rd_sp rs1_sp !-16 addi ; allocate stack 1346 .00010000 .00000100 .000000FF 13000000 1347 # rs1_sp rs2_ra sd ; Protect ra 1348 .00000100 .00001000 23300000 1349 # rs1_sp rs2_a0 @8 sd ; Protect top byte 1350 .00000100 .0000A000 .00040000 23300000 1351 # rd_ra $hex8 jal ; Store it 1352 .80000000 $hex8 6F000000 1353 # rd_a0 rs1_sp !8 ld ; do high byte 1354 .00050000 .00000100 .00008000 03300000 1355 # rd_a0 rs1_a0 rs2_x8 srli ; do bottom byte 1356 .00050000 .00000500 .00008000 13500000 1357 # rd_ra $hex8 jal ; Store it 1358 .80000000 $hex8 6F000000 1359 # rd_ra rs1_sp ld ; restore ra 1360 .80000000 .00000100 03300000 1361 # rd_sp rs1_sp !16 addi ; deallocate stack 1362 .00010000 .00000100 .00000001 13000000 1363 # rs1_ra jalr ; return 1364 .00800000 67000000 1365 1366 :hex8 1367 # rd_sp rs1_sp !-16 addi ; allocate stack 1368 .00010000 .00000100 .000000FF 13000000 1369 # rs1_sp rs2_ra sd ; Protect ra 1370 .00000100 .00001000 23300000 1371 # rs1_sp rs2_a0 @8 sd ; Protect bottom nibble 1372 .00000100 .0000A000 .00040000 23300000 1373 # rd_a0 rs1_a0 rs2_x4 srli ; do high nibble first 1374 .00050000 .00000500 .00004000 13500000 1375 # rd_ra $hex4 jal ; Store it 1376 .80000000 $hex4 6F000000 1377 # rd_a0 rs1_sp !8 ld ; do low nibble 1378 .00050000 .00000100 .00008000 03300000 1379 # rd_ra $hex4 jal ; Store it 1380 .80000000 $hex4 6F000000 1381 # rd_ra rs1_sp ld ; restore ra 1382 .80000000 .00000100 03300000 1383 # rd_sp rs1_sp !16 addi ; deallocate stack 1384 .00010000 .00000100 .00000001 13000000 1385 # rs1_ra jalr ; return 1386 .00800000 67000000 1387 1388 :hex4 1389 # rd_t0 !0xF addi 1390 .80020000 .0000F000 13000000 1391 # rd_a0 rs1_a0 rs2_t0 and ; isolate nibble 1392 .00050000 .00000500 .00005000 33700000 1393 # rd_a0 rs1_a0 !0x30 addi ; convert to ascii 1394 .00050000 .00000500 .00000003 13000000 1395 # rd_t0 !0x39 addi ; t0 = '9' 1396 .80020000 .00009003 13000000 1397 # rs1_t0 rs2_a0 @hex1 bge ; check if valid digit 1398 .00800200 .0000A000 @hex1 63500000 1399 # rd_a0 rs1_a0 !7 addi ; use alpha range 1400 .00050000 .00000500 .00007000 13000000 1401 :hex1 1402 # rs1_a1 rs2_a0 sb ; store result 1403 .00800500 .0000A000 23000000 1404 # rd_a1 rs1_a1 !1 addi ; next position 1405 .80050000 .00800500 .00001000 13000000 1406 # rs1_ra jalr ; return 1407 .00800000 67000000 1408 1409 1410 ; Preserve_Other function 1411 ; Receives list in a0 1412 ; Update the list in place; does not modify registers 1413 ; Uses a0 for I, a1 for I->TEXT 1414 :Preserve_Other 1415 # rd_sp rs1_sp !-32 addi ; allocate stack 1416 .00010000 .00000100 .000000FE 13000000 1417 # rs1_sp rs2_a1 sd ; protect a1 1418 .00000100 .0000B000 23300000 1419 # rs1_sp rs2_a2 @8 sd ; protect a2 1420 .00000100 .0000C000 .00040000 23300000 1421 # rs1_sp rs2_a3 @16 sd ; protect a3 1422 .00000100 .0000D000 .00080000 23300000 1423 # rs1_sp rs2_a4 @24 sd ; protect a4 1424 .00000100 .0000E000 .000C0000 23300000 1425 :Preserve_Other_Loop 1426 # rd_a1 rs1_a0 !24 ld ; I->EXPRESSION 1427 .80050000 .00000500 .00008001 03300000 1428 # rs1_a1 @Preserve_Other_Next bnez ; IF NULL == I->EXPRESSION then preserve 1429 .00800500 @Preserve_Other_Next 63100000 1430 1431 # rd_a1 rs1_a0 !16 ld ; I->TEXT 1432 .80050000 .00000500 .00000001 03300000 1433 # rs1_a0 rs2_a1 @24 sd ; I->EXPRESSION = I->TEXT 1434 .00000500 .0000B000 .000C0000 23300000 1435 1436 :Preserve_Other_Next 1437 # rd_a0 rs1_a0 ld ; I = I->NEXT 1438 .00050000 .00000500 03300000 1439 # rs1_a0 @Preserve_Other_Loop bnez ; Keep looping until I == NULL 1440 .00000500 @Preserve_Other_Loop 63100000 1441 1442 # rd_a1 rs1_sp ld ; restore a1 1443 .80050000 .00000100 03300000 1444 # rd_a2 rs1_sp !8 ld ; restore a2 1445 .00060000 .00000100 .00008000 03300000 1446 # rd_a3 rs1_sp !16 ld ; restore a3 1447 .80060000 .00000100 .00000001 03300000 1448 # rd_a4 rs1_sp !24 ld ; restore a4 1449 .00070000 .00000100 .00008001 03300000 1450 # rd_sp rs1_sp !32 addi ; deallocate stack 1451 .00010000 .00000100 .00000002 13000000 1452 # rs1_ra jalr ; return 1453 .00800000 67000000 1454 1455 1456 ; Print_Hex function 1457 ; Receives list in a0 1458 ; walks the list and prints the I->EXPRESSION for all nodes followed by newline 1459 ; Uses a1 for I 1460 :Print_Hex 1461 # rd_sp rs1_sp !-24 addi ; allocate stack 1462 .00010000 .00000100 .000080FE 13000000 1463 # rs1_sp rs2_ra sd ; protect ra 1464 .00000100 .00001000 23300000 1465 # rs1_sp rs2_a1 @8 sd ; protect a1 1466 .00000100 .0000B000 .00040000 23300000 1467 # rs1_sp rs2_a2 @16 sd ; protect a2 1468 .00000100 .0000C000 .00080000 23300000 1469 1470 # rd_a1 rs1_s4 mv ; I = HEAD 1471 .80050000 .00000A00 13000000 1472 1473 :Print_Hex_Loop 1474 # rd_a0 rs1_a1 !8 ld ; I->TYPE 1475 .00050000 .00800500 .00008000 03300000 1476 # rd_t0 !1 addi ; t0 = MACRO 1477 .80020000 .00001000 13000000 1478 # rs1_a0 rs2_t0 @Print_Hex_Next beq ; Skip if MACRO = I->TYPE 1479 .00000500 .00005000 @Print_Hex_Next 63000000 1480 1481 # rd_a0 rs1_a1 !24 ld ; Using EXPRESSION 1482 .00050000 .00800500 .00008001 03300000 1483 # rd_ra $File_Print jal ; Print it 1484 .80000000 $File_Print 6F000000 1485 # rd_a0 !10 addi ; \n 1486 .00050000 .0000A000 13000000 1487 # rd_ra $fputc jal ; Print newline 1488 .80000000 $fputc 6F000000 1489 1490 :Print_Hex_Next 1491 # rd_a1 rs1_a1 ld ; Iterate to next Token 1492 .80050000 .00800500 03300000 1493 # rs1_a1 @Print_Hex_Loop bnez ; Stop if NULL, otherwise keep looping 1494 .00800500 @Print_Hex_Loop 63100000 1495 1496 # rd_ra rs1_sp ld ; restore ra 1497 .80000000 .00000100 03300000 1498 # rd_a1 rs1_sp !8 ld ; restore a1 1499 .80050000 .00000100 .00008000 03300000 1500 # rd_a2 rs1_sp !16 ld ; restore a2 1501 .00060000 .00000100 .00000001 03300000 1502 # rd_sp rs1_sp !24 addi ; deallocate stack 1503 .00010000 .00000100 .00008001 13000000 1504 # rs1_ra jalr ; return 1505 .00800000 67000000 1506 1507 1508 ; File_Print function 1509 ; Receives CHAR* in a0 1510 ; calls fputc for every non-null char 1511 :File_Print 1512 # rd_sp rs1_sp !-24 addi ; allocate stack 1513 .00010000 .00000100 .000080FE 13000000 1514 # rs1_sp rs2_ra sd ; protect ra 1515 .00000100 .00001000 23300000 1516 # rs1_sp rs2_a1 @8 sd ; protect a1 1517 .00000100 .0000B000 .00040000 23300000 1518 # rs1_sp rs2_a2 @16 sd ; protect a2 1519 .00000100 .0000C000 .00080000 23300000 1520 # rd_a1 rs1_a0 mv ; protect a0 1521 .80050000 .00000500 13000000 1522 1523 # rs1_a0 @File_Print_Done beqz ; Protect against nulls 1524 .00000500 @File_Print_Done 63000000 1525 1526 :File_Print_Loop 1527 # rd_a0 rs1_a1 lbu ; Read byte 1528 .00050000 .00800500 03400000 1529 # rs1_a0 @File_Print_Done beqz ; Stop at NULL 1530 .00000500 @File_Print_Done 63000000 1531 1532 # rd_ra $fputc jal ; print it 1533 .80000000 $fputc 6F000000 1534 # rd_a1 rs1_a1 !1 addi ; S = S + 1 1535 .80050000 .00800500 .00001000 13000000 1536 # $File_Print_Loop jal ; Keep printing 1537 $File_Print_Loop 6F000000 1538 1539 :File_Print_Done 1540 # rd_ra rs1_sp ld ; restore ra 1541 .80000000 .00000100 03300000 1542 # rd_a1 rs1_sp !8 ld ; restore a1 1543 .80050000 .00000100 .00008000 03300000 1544 # rd_a2 rs1_sp !16 ld ; restore a2 1545 .00060000 .00000100 .00000001 03300000 1546 # rd_sp rs1_sp !24 addi ; deallocate stack 1547 .00010000 .00000100 .00008001 13000000 1548 # rs1_ra jalr ; return 1549 .00800000 67000000 1550 1551 1552 ; fgetc function 1553 ; Loads FILE* from s2 1554 ; Returns -4 (EOF) or char in a0 1555 :fgetc 1556 # rd_sp rs1_sp !-32 addi ; allocate stack 1557 .00010000 .00000100 .000000FE 13000000 1558 # rs1_sp rs2_ra @8 sd ; protect ra 1559 .00000100 .00001000 .00040000 23300000 1560 # rs1_sp rs2_a1 @16 sd ; protect a1 1561 .00000100 .0000B000 .00080000 23300000 1562 # rs1_sp rs2_a2 @24 sd ; protect a2 1563 .00000100 .0000C000 .000C0000 23300000 1564 1565 # rd_a7 !63 addi ; sys_read 1566 .80080000 .0000F003 13000000 1567 # rd_a1 rs1_sp mv ; Get stack address for buffer 1568 .80050000 .00000100 13000000 1569 # rd_a0 rs1_s2 mv ; read from input file 1570 .00050000 .00000900 13000000 1571 # rd_a2 !1 addi ; read 1 character 1572 .00060000 .00001000 13000000 1573 # ecall ; syscall 1574 73000000 1575 1576 # rs1_a0 @fgetc_done bnez ; Check if nothing was read 1577 .00000500 @fgetc_done 63100000 1578 # rd_a2 !-4 addi ; Use -4 as EOF 1579 .00060000 .0000C0FF 13000000 1580 # rs1_a1 rs2_a2 sb ; Store EOF in *a1 1581 .00800500 .0000C000 23000000 1582 1583 :fgetc_done 1584 # rd_a0 rs1_a1 lb ; return char in a0 1585 .00050000 .00800500 03000000 1586 # rd_ra rs1_sp !8 ld ; restore ra 1587 .80000000 .00000100 .00008000 03300000 1588 # rd_a1 rs1_sp !16 ld ; restore a1 1589 .80050000 .00000100 .00000001 03300000 1590 # rd_a2 rs1_sp !24 ld ; restore a2 1591 .00060000 .00000100 .00008001 03300000 1592 # rd_sp rs1_sp !32 addi ; deallocate stack 1593 .00010000 .00000100 .00000002 13000000 1594 # rs1_ra jalr ; return 1595 .00800000 67000000 1596 1597 1598 ; Malloc isn't actually required if the program being built fits in the initial memory 1599 ; However, it doesn't take much to add it. 1600 ; Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes 1601 :malloc 1602 # rd_sp rs1_sp !-16 addi ; allocate stack 1603 .00010000 .00000100 .000000FF 13000000 1604 # rs1_sp rs2_ra sd ; protect ra 1605 .00000100 .00001000 23300000 1606 # rs1_sp rs2_a1 @8 sd ; protect a1 1607 .00000100 .0000B000 .00040000 23300000 1608 1609 # rd_a1 rs1_s1 mv ; Store the current pointer 1610 .80050000 .00800400 13000000 1611 # rd_a0 rs1_a0 rs2_s1 add ; Request the number of desired bytes 1612 .00050000 .00000500 .00009000 33000000 1613 # rd_a7 !214 addi ; sys_brk 1614 .80080000 .0000600D 13000000 1615 # ecall ; syscall 1616 73000000 1617 # rd_s1 rs1_a0 mv ; Set our malloc pointer 1618 .80040000 .00000500 13000000 1619 # rd_a0 rs1_a1 mv ; Return the pointer 1620 .00050000 .00800500 13000000 1621 1622 # rd_ra rs1_sp ld ; restore ra 1623 .80000000 .00000100 03300000 1624 # rd_a1 rs1_sp !8 ld ; restore a1 1625 .80050000 .00000100 .00008000 03300000 1626 # rd_sp rs1_sp !16 addi ; deallocate stack 1627 .00010000 .00000100 .00000001 13000000 1628 # rs1_ra jalr ; return 1629 .00800000 67000000 1630 1631 1632 ; fputc function 1633 ; receives CHAR in a0 and load FILE* from s3 1634 ; writes char and returns 1635 :fputc 1636 # rd_sp rs1_sp !-32 addi ; allocate stack 1637 .00010000 .00000100 .000000FE 13000000 1638 # rs1_sp rs2_a0 sd ; protect a0 1639 .00000100 .0000A000 23300000 1640 # rs1_sp rs2_ra @8 sd ; protect ra 1641 .00000100 .00001000 .00040000 23300000 1642 # rs1_sp rs2_a1 @16 sd ; protect a1 1643 .00000100 .0000B000 .00080000 23300000 1644 # rs1_sp rs2_a2 @24 sd ; protect a2 1645 .00000100 .0000C000 .000C0000 23300000 1646 1647 # rd_a7 !64 addi ; sys_write 1648 .80080000 .00000004 13000000 1649 # rd_a0 rs1_s3 mv ; write to output 1650 .00050000 .00800900 13000000 1651 # rd_a1 rs1_sp mv ; Get stack address 1652 .80050000 .00000100 13000000 1653 # rd_a2 !1 addi ; write 1 character 1654 .00060000 .00001000 13000000 1655 # ecall ; syscall 1656 73000000 1657 1658 # rd_a0 rs1_sp ld ; restore a0 1659 .00050000 .00000100 03300000 1660 # rd_ra rs1_sp !8 ld ; restore ra 1661 .80000000 .00000100 .00008000 03300000 1662 # rd_a1 rs1_sp !16 ld ; restore a1 1663 .80050000 .00000100 .00000001 03300000 1664 # rd_a2 rs1_sp !24 ld ; restore a2 1665 .00060000 .00000100 .00008001 03300000 1666 # rd_sp rs1_sp !32 addi ; deallocate stack 1667 .00010000 .00000100 .00000002 13000000 1668 # rs1_ra jalr ; return 1669 .00800000 67000000 1670 1671 1672 :Fail 1673 ; Terminate program with 1 return code 1674 # rd_a7 !93 addi ; sys_exit 1675 .80080000 .0000D005 13000000 1676 # rd_a0 !1 addi ; Return code 1 1677 .00050000 .00001000 13000000 1678 # ecall ; exit(1) 1679 73000000 1680 1681 ; PROGRAM END 1682 1683 :terminators 1684 # " 1685 # " 1686 0A 09 20 00 1687 1688 :comments 1689 # "#;" 1690 23 3B 00 1691 1692 :string_char 1693 # '22 27 00' 1694 22 27 00 1695 1696 :DEFINE_str 1697 # "DEFINE" 1698 44 45 46 49 4E 45 00 1699 1700 :ELF_end