~oriansj/bootstrap-seeds

e027b7f9da2092d41d4d249c5a6e7ce5c991cf07 — Andrius Štikonas 4 months ago 4d3bc3b
Sync riscv bootstrap seeds (only comment updates.
5 files changed, 529 insertions(+), 685 deletions(-)

M POSIX/riscv32/hex0_riscv32.hex0
M POSIX/riscv32/kaem-minimal.hex0
M POSIX/riscv64/hex0_riscv64.hex0
D POSIX/riscv64/kaem-micro.hex0
M POSIX/riscv64/kaem-minimal.hex0
M POSIX/riscv32/hex0_riscv32.hex0 => POSIX/riscv32/hex0_riscv32.hex0 +71 -71
@@ 1,6 1,6 @@
## Copyright (C) 2021 Ekaitz Zarraga
## Copyright (C) 2021 Andrius Štikonas
## Copyright (C) 2021 Gabriel Wicki
## Copyright (C) 2021,2022 Gabriel Wicki
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify


@@ 72,142 72,142 @@ F3 00              # e_machine Indicating RISC-V
01 00 00 00        # ph_align

# :_start ; (0x0600054)
    13 0A 00 00    # RD_S4 MV                 ; Initialize register
    83 25 81 00    # RD_A1 RS1_SP !8 LW       ; Input file name
    13 0A 00 00    # rd_s4 mv                 ; Initialize register
    83 25 81 00    # rd_a1 rs1_sp !8 lw       ; Input file name

    ; Open input file and store FD in s2
    93 08 80 03    # RD_A7 !56 ADDI           ; sys_openat
    13 05 C0 F9    # RD_A0 !-100 ADDI         ; AT_FDCWD
    13 06 00 00    # RD_A2 MV                 ; read only
    73 00 00 00    # ECALL
    13 09 05 00    # RD_S2 RS1_A0 MV          ; Save fd in for later
    93 08 80 03    # rd_a7 !56 addi           ; sys_openat
    13 05 C0 F9    # rd_a0 !-100 addi         ; AT_FDCWD
    13 06 00 00    # rd_a2 mv                 ; read only
    73 00 00 00    # ecall
    13 09 05 00    # rd_s2 rs1_a0 mv          ; Save fd in s2 for later

    ; Open output file and store the FD in s3
    13 05 C0 F9    # RD_A0 !-100 ADDI         ; AT_FDCWD
    83 25 C1 00    # RD_A1 RS1_SP !12 LW      ; Output file (argument 3)
    13 06 10 24    # RD_A2 !577 ADDI          ; octal 00001101
    13 05 C0 F9    # rd_a0 !-100 addi         ; AT_FDCWD
    83 25 C1 00    # rd_a1 rs1_sp !12 lw      ; Output file (argument 3)
    13 06 10 24    # rd_a2 !577 addi          ; octal 00001101
    ; O_TRUNC   00001000
    ; O_CREAT   00000100
    ; O_WRONLY  00000001
    ; OCTAL!

    93 06 00 1C    # RD_A3 !448 ADDI          ; Set read, write, execute permission on user
    93 06 00 1C    # rd_a3 !448 addi          ; Set read, write, execute permission on user
    ; S_IRWXU  00700
    ; OCTAL!

    73 00 00 00    # ECALL
    93 09 05 00    # RD_S3 RS1_A0 MV          ; Save fd in for later
    73 00 00 00    # ecall
    93 09 05 00    # rd_s3 rs1_a0 mv          ; Save fd in s3 for later

# :next_byte ; (0x0600088)
    93 08 F0 03    # RD_A7 !63 ADDI           ; sys_read
    13 05 09 00    # RD_A0 RS1_S2 MV          ; File descriptor
    93 05 01 00    # RD_A1 RS1_SP MV          ; Buffer
    13 06 10 00    # RD_A2 !1 ADDI            ; Size of what we want to read (set for all subsequent syscalls)
    73 00 00 00    # ECALL
    93 08 F0 03    # rd_a7 !63 addi           ; sys_read
    13 05 09 00    # rd_a0 rs1_s2 mv          ; File descriptor
    93 05 01 00    # rd_a1 rs1_sp mv          ; Buffer
    13 06 10 00    # rd_a2 !1 addi            ; Size of what we want to read (set for all subsequent syscalls)
    73 00 00 00    # ecall

    ; If the file ended (0 bytes read) terminate
    63 00 05 0C    # RS1_A0 @terminate BEQZ
    63 00 05 0C    # rs1_a0 @terminate beqz
                   # +192B

    ; Check if it's a comment
    03 05 01 00    # RD_A0 RS1_SP LB
    93 02 30 02    # RD_T0 !0x23 ADDI
    63 08 55 00    # RS1_A0 RS2_T0 @loop BEQ  ; a0 eq to '#'
    03 05 01 00    # rd_a0 rs1_sp lb
    93 02 30 02    # rd_t0 !0x23 addi
    63 08 55 00    # rs1_a0 rs2_t0 @loop beq  ; a0 eq to '#'
                   # +16B
    93 02 B0 03    # RD_T0 !0x3B ADDI
    63 04 55 00    # RS1_A0 RS2_T0 @loop BEQ  ; a0 eq to ';'
    93 02 B0 03    # rd_t0 !0x3B addi
    63 04 55 00    # rs1_a0 rs2_t0 @loop beq  ; a0 eq to ';'
                   # +8B
    6F 00 80 02    # $not_comment JAL
    6F 00 80 02    # $not_comment jal
                   # +40B
# :loop ; (0x06000B8)
        13 05 09 00    # RD_A0 RS1_S2 MV   ; File descriptor
        73 00 00 00    # ECALL             ; sys_read
        13 05 09 00    # rd_a0 rs1_s2 mv   ; File descriptor
        73 00 00 00    # ecall             ; sys_read

        ; If the file ended (0 bytes read) terminate
        63 0E 05 08    # RS1_A0 @terminate BEQZ
        63 0E 05 08    # rs1_a0 @terminate beqz
                       # +156B
        ; Check if read byte is the end of the comment,
        ; in the case it is continue processing
        03 05 01 00     # RD_A0 RS1_SP LB
        93 02 A0 00     # RD_T0 !0xA ADDI
        E3 0E 55 FA     # RS1_A0 RS2_T0 @next_byte BEQ ; a0 eq to \n
        ; Check if read byte is the end of the comment (i.e. a newline character),
        ; in that case we continue processing
        03 05 01 00     # rd_a0 rs1_sp lb
        93 02 A0 00     # rd_t0 !0xA addi
        E3 0E 55 FA     # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \n
                        # -68B
        93 02 D0 00     # RD_T0 !0xD ADDI
        E3 0A 55 FA     # RS1_A0 RS2_T0 @next_byte BEQ ; a0 eq to \r
        93 02 D0 00     # rd_t0 !0xD addi
        E3 0A 55 FA     # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \r
                        # -76B
    6F F0 1F FE    # $loop JAL
    6F F0 1F FE    # $loop jal
# :not_comment ; (0x06000DC)
    ; Check if it's a hex character:
    ; in the case it's not, ignores and reads next byte
    03 05 01 00    # RD_A0 RS1_SP LB
    03 05 01 00    # rd_a0 rs1_sp lb

    ; Is it between '0' and '9'?
    93 02 00 03    # RD_T0 !48 ADDI           ; '0' character
    63 4A 55 00    # RS1_A0 RS2_T0 @uppercase_alpha BLT
    93 02 00 03    # rd_t0 !48 addi           ; '0' character
    63 4A 55 00    # rs1_a0 rs2_t0 @uppercase_alpha blt
                   # +20B
    93 02 90 03    # RD_T0 !57 ADDI           ; '9' character
    63 C6 A2 00    # RS1_T0 RS2_A0 @uppercase_alpha BLT
    93 02 90 03    # rd_t0 !57 addi           ; '9' character
    63 C6 A2 00    # rs1_t0 rs2_a0 @uppercase_alpha blt
                   # +12B
    13 05 05 FD    # RD_A0 RS1_A0 !-48 ADDI
    6F 00 00 03    # $hex_read JAL
    13 05 05 FD    # rd_a0 rs1_a0 !-48 addi
    6F 00 00 03    # $hex_read jal
                   # +48B
# :uppercase_alpha ; (0x06000F8)
    ; Is it between 'A' and 'F'?
    93 02 10 04    # RD_T0 !65 ADDI           ; 'A' character
    63 4A 55 00    # RS1_A0 RS2_T0 @lowercase_alpha BLT
    93 02 10 04    # rd_t0 !65 addi           ; 'A' character
    63 4A 55 00    # rs1_a0 rs2_t0 @lowercase_alpha blt
                   # +20B
    93 02 60 04    # RD_T0 !70 ADDI           ; 'F' character
    63 C6 A2 00    # RS1_T0 RS2_A0 @lowercase_alpha BLT
    93 02 60 04    # rd_t0 !70 addi           ; 'F' character
    63 C6 A2 00    # rs1_t0 rs2_a0 @lowercase_alpha blt
                   # +12B
    13 05 95 FC    # RD_A0 RS1_A0 !-55 ADDI
    6F 00 80 01    # $hex_read JAL
    13 05 95 FC    # rd_a0 rs1_a0 !-55 addi
    6F 00 80 01    # $hex_read jal
                   # +24B
# :lowercase_alpha ; (0x0600110)
    ; Is it between 'a' and 'f'?
    93 02 10 06    # RD_T0 !97 ADDI           ; 'a' character
    E3 4A 55 F6    # RS1_A0 RS2_T0 @next_byte BLT ; Not hex, continue reading
    93 02 10 06    # rd_t0 !97 addi           ; 'a' character
    E3 4A 55 F6    # rs1_a0 rs2_t0 @next_byte blt ; Not hex, continue reading
                   # -140B
    93 02 60 06    # RD_T0 !102 ADDI          ; 'f' character
    E3 C6 A2 F6    # RS1_T0 RS2_A0 @next_byte BLT ; Not hex, continue reading
    93 02 60 06    # rd_t0 !102 addi          ; 'f' character
    E3 C6 A2 F6    # rs1_t0 rs2_a0 @next_byte blt ; Not hex, continue reading
                   # -148B
    13 05 95 FA    # RD_A0 RS1_A0 !-87 ADDI
    13 05 95 FA    # rd_a0 rs1_a0 !-87 addi
# :hex_read ; (0x0600124)
    ; END check hex -- leaves the half byte in a0

    63 18 0A 00    # RS1_S4 @combine BNEZ     ; if toggle != 0 -> combine
    63 18 0A 00    # rs1_s4 @combine bnez     ; if toggle != 0 -> combine
                   # +16B
    ; Toggle == 0, we need to prepare for later
    93 0A 05 00    # RD_S5 RS1_A0 MV          ; Load hold
    93 0A 05 00    # rd_s5 rs1_a0 mv          ; Load hold

    13 0A 10 00    # RD_S4 !1 ADDI            ; Set toggle
    6F F0 9F F5    # $next_byte JAL           ; Read next byte
    13 0A 10 00    # rd_s4 !1 addi            ; Set toggle
    6F F0 9F F5    # $next_byte jal           ; Read next byte
                   # -168B

# :combine ; (0x0600134)
    ; Combine half bytes
    93 95 4A 00    # RD_A1 RS1_S5 RS2_X4 SLLI ; Shift logical left 4 times
    33 05 B5 00    # RD_A0 RS1_A0 RS2_A1 ADD  ; Combine two half bytes
    93 95 4A 00    # rd_a1 rs1_s5 rs2_x4 slli ; Shift logical left 4 times
    33 05 B5 00    # rd_a0 rs1_a0 rs2_a1 add  ; Combine two half bytes
    ; Leaves the full byte in a0

    ; Values are combined, now we write in the file
    23 00 A1 00    # RS1_SP RS2_A0 SB         ; Store prepared byte in buffer
    93 08 00 04    # RD_A7 !64 ADDI           ; sys_write
    13 85 09 00    # RD_A0 RS1_S3 MV          ; file descriptor (stdout)
    93 05 01 00    # RD_A1 RS1_SP MV          ; string address
    73 00 00 00    # ECALL
    23 00 A1 00    # rs1_sp rs2_a0 sb         ; Store prepared byte in buffer
    93 08 00 04    # rd_a7 !64 addi           ; sys_write
    13 85 09 00    # rd_a0 rs1_s3 mv          ; file descriptor (stdout)
    93 05 01 00    # rd_a1 rs1_sp mv          ; string address
    73 00 00 00    # ecall

    ; Update globals
    13 0A 00 00    # RD_S4 MV                 ; Clear toggle
    93 0A 00 00    # RD_S5 MV                 ; Clear hold
    13 0A 00 00    # rd_s4 mv                 ; Clear toggle
    93 0A 00 00    # rd_s5 mv                 ; Clear hold

    ; Read next byte
    6F F0 1F F3    # $next_byte JAL
    6F F0 1F F3    # $next_byte jal
                   # -208B

# :terminate  ; (0x60015C)
    ; Terminate program with 0 return code
    93 08 D0 05    # RD_A7 !93 ADDI           ; sys_exit
    73 00 00 00    # ECALL
    93 08 D0 05    # rd_a7 !93 addi           ; sys_exit
    73 00 00 00    # ecall
# PROGRAM END

# :ELF_end ; (0x600164)

M POSIX/riscv32/kaem-minimal.hex0 => POSIX/riscv32/kaem-minimal.hex0 +191 -191
@@ 68,113 68,113 @@ F3 00              ## e_machine Indicating RISC-V
# s4: command_done
# s6: malloc pointer

    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; Input file name
    13 07 00 00     # RD_A4 MV                          ; Initialize register (set *rusage = NULL in waitid)
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; Input file name
    13 07 00 00     # rd_a4 mv                          ; Initialize register (set *rusage = NULL in waitid)

    63 16 06 00     # RS1_A2 @_start_out BNEZ           ; Use input file if specified
    63 16 06 00     # rs1_a2 @_start_out bnez           ; Use input file if specified
                    # +12B

    # Else use kaem.riscv32
    17 06 00 00     # RD_A2 ~default_file AUIPC         ; load address of default_file
    13 06 86 2E     # RD_A2 RS1_A2 !default_file ADDI   ; into register a2
    17 06 00 00     # rd_a2 ~default_file auipc         ; load address of default_file
    13 06 86 2E     # rd_a2 rs1_a2 !default_file addi   ; into register a2
                    # +744B

# :_start_out ; (0x0600064)

    # Open input file and store FD in s2
    93 08 80 03     # RD_A7 !56 ADDI                    ; sys_openat
    13 05 C0 F9     # RD_A0 !-100 ADDI                  ; AT_FDCWD
    93 05 06 00     # RD_A1 RS1_A2 MV                   ; file name
    13 06 00 00     # RD_A2 ADDI                        ; read only
    73 00 00 00     # ECALL                             ; syscall
    63 40 05 2C     # RS1_A0 @Fail BLTZ                 ; Error opening file
    93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
    13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
    93 05 06 00     # rd_a1 rs1_a2 mv                   ; file name
    13 06 00 00     # rd_a2 addi                        ; read only
    73 00 00 00     # ecall                             ; syscall
    63 40 05 2C     # rs1_a0 @Fail bltz                 ; Error opening file
                    # +704B
    13 09 05 00     # RD_S2 RS1_A0 MV                   ; Save fd in for later
    13 09 05 00     # rd_s2 rs1_a0 mv                   ; Save fd in for later

    # Prepare heap memory
    93 08 60 0D     # RD_A7 !214 ADDI                   ; sys_brk
    13 05 00 00     # RD_A0 MV                          ; Get current brk
    73 00 00 00     # ECALL                             ; syscall
    13 0B 05 00     # RD_S6 RS1_A0 MV                   ; Set our malloc pointer
    93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    13 05 00 00     # rd_a0 mv                          ; Get current brk
    73 00 00 00     # ecall                             ; syscall
    13 0B 05 00     # rd_s6 rs1_a0 mv                   ; Set our malloc pointer

# Using a1 for tokens and a2 for tokens[i]
# :main_loop ; (0x0600090)
    13 05 10 00     # RD_A0 !1 ADDI                     ; 256 * sizeof(char*)
    13 15 B5 00     # RD_A0 RS1_A0 RS2_X11 SLLI         ; 2048 = 1 << 11
    EF 00 00 1F     # RD_RA $malloc JAL                 ; allocate space
    13 05 10 00     # rd_a0 !1 addi                     ; 256 * sizeof(char*)
    13 15 B5 00     # rd_a0 rs1_a0 rs2_x11 slli         ; 2048 = 1 << 11
    EF 00 00 1F     # rd_ra $malloc jal                 ; allocate space
                    # +496B
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; set tokens pointer
    13 06 05 00     # RD_A2 RS1_A0 MV                   ; set tokens[i] pointer (i=0)
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; set tokens pointer
    13 06 05 00     # rd_a2 rs1_a0 mv                   ; set tokens[i] pointer (i=0)

    13 0A 00 00     # RD_S4 MV                          ; command_done = 0
    13 0A 00 00     # rd_s4 mv                          ; command_done = 0

# :collect_command ; (0x06000A8)
    EF 00 C0 0D     # RD_RA $collect_token JAL          ; Get another token
    EF 00 C0 0D     # rd_ra $collect_token jal          ; Get another token
                    # +220B
    63 06 05 00     # RS1_A0 @collect_command_comment BEQZ ; if NULL == result then it is a comment, don't store
    63 06 05 00     # rs1_a0 @collect_command_comment beqz ; if NULL == result then it is a comment, don't store
                    # +12B

    23 20 A6 00     # RS1_A2 RS2_A0 SW                  ; tokens[i] = result
    13 06 46 00     # RD_A2 RS1_A2 !4 ADDI              ; i = i + 1 (sizeof(char*) = 4)
    23 20 A6 00     # rs1_a2 rs2_a0 sw                  ; tokens[i] = result
    13 06 46 00     # rd_a2 rs1_a2 !4 addi              ; i = i + 1 (sizeof(char*) = 4)

# :collect_command_comment ; (0x06000B8)
    E3 08 0A FE     # RS1_S4 @collect_command BEQZ      ; keep looping if 0 == command_done
    E3 08 0A FE     # rs1_s4 @collect_command beqz      ; keep looping if 0 == command_done
                    # -16B

    # Deal with line comments
    E3 8A C5 FC     # RS1_A1 RS2_A2 @main_loop BEQ      ; keep looping if comment
    E3 8A C5 FC     # rs1_a1 rs2_a2 @main_loop beq      ; keep looping if comment
                    # -44B

    EF 00 40 07     # RD_RA $print_command JAL          ; print the command
    EF 00 40 07     # rd_ra $print_command jal          ; print the command
                    # +116B
    03 A5 05 00     # RD_A0 RS1_A1 LW                   ; program = tokens[0]
    63 08 05 26     # RS1_A0 @Fail BEQZ                 ; Error, no program
    03 A5 05 00     # rd_a0 rs1_a1 lw                   ; program = tokens[0]
    63 08 05 26     # rs1_a0 @Fail beqz                 ; Error, no program
                    # +624B

    13 01 C1 FF     # RD_SP RS1_SP !-4 ADDI             ; allocate stack
    23 20 B1 00     # RS1_SP RS2_A1 SW                  ; protect tokens
    13 01 C1 FF     # rd_sp rs1_sp !-4 addi             ; allocate stack
    23 20 B1 00     # rs1_sp rs2_a1 sw                  ; protect tokens

    93 08 C0 0D     # RD_A7 !220 ADDI                   ; sys_clone
    13 05 10 01     # RD_A0 !17 ADDI                    ; SIGCHLD flag
    93 05 00 00     # RD_A1 MV                          ; Child uses duplicate of parent's stack
    73 00 00 00     # ECALL                             ; syscall
    93 08 C0 0D     # rd_a7 !220 addi                   ; sys_clone
    13 05 10 01     # rd_a0 !17 addi                    ; SIGCHLD flag
    93 05 00 00     # rd_a1 mv                          ; Child uses duplicate of parent's stack
    73 00 00 00     # ecall                             ; syscall

    83 25 01 00     # RD_A1 RS1_SP LW                   ; restore tokens
    13 01 41 00     # RD_SP RS1_SP !4 ADDI              ; deallocate stack
    83 25 01 00     # rd_a1 rs1_sp lw                   ; restore tokens
    13 01 41 00     # rd_sp rs1_sp !4 addi              ; deallocate stack

    63 46 05 24     # RS1_A0 @Fail BLTZ                 ; if f == -1 no child was created
    63 46 05 24     # rs1_a0 @Fail bltz                 ; if f == -1 no child was created
                    # +588B
    63 1A 05 00     # RS1_A0 @collect_command_parent BNEZ ; if f == 0 it is child
    63 1A 05 00     # rs1_a0 @collect_command_parent bnez ; if f == 0 it is child
                    # +20B

    # Deal with child case
    93 08 D0 0D     # RD_A7 !221 ADDI                   ; sys_execve
    03 A5 05 00     # RD_A0 RS1_A1 LW                   ; program = tokens[0]
    73 00 00 00     # ECALL                             ; execve(program, tokens)
    EF 00 80 23     # RD_RA $Fail JAL                   ; Exit with an error
    93 08 D0 0D     # rd_a7 !221 addi                   ; sys_execve
    03 A5 05 00     # rd_a0 rs1_a1 lw                   ; program = tokens[0]
    73 00 00 00     # ecall                             ; execve(program, tokens)
    EF 00 80 23     # rd_ra $Fail jal                   ; Exit with an error
                    # +568B

# :collect_command_parent ; (0x0600104)
    93 08 F0 05     # RD_A7 !95 ADDI                    ; sys_waitid
    13 05 00 00     # RD_A0 MV                          ; set idtype = P_ALL
    17 06 00 00     # RD_A2 ~info AUIPC                 ; a2 = siginfo_t &info
    13 06 A6 26     # RD_A2 RS1_A2 !info ADDI
    93 08 F0 05     # rd_a7 !95 addi                    ; sys_waitid
    13 05 00 00     # rd_a0 mv                          ; set idtype = P_ALL
    17 06 00 00     # rd_a2 ~info auipc                 ; a2 = siginfo_t &info
    13 06 A6 26     # rd_a2 rs1_a2 !info addi
                    # +618B
    93 06 40 00     # RD_A3 !4 MV                       ; set *options = WEXITED
    73 00 00 00     # ECALL                             ; syscall
    93 06 40 00     # rd_a3 !4 mv                       ; set *options = WEXITED
    73 00 00 00     # ecall                             ; syscall

    # Check if child exited
    03 26 46 01     # RD_A2 RS1_A2 !20 LW               ; status = info->si_status
    E3 08 06 F6     # RS1_A2 @main_loop BEQZ            ; Loop if 0 == status
    03 26 46 01     # rd_a2 rs1_a2 !20 lw               ; status = info->si_status
    E3 08 06 F6     # rs1_a2 @main_loop beqz            ; Loop if 0 == status
                    # -144B

# :abort ; (0x0600124)
    17 05 00 00     # RD_A0 ~hard AUIPC                 ; Get error string
    13 05 25 23     # RD_A0 RS1_A0 !hard ADDI           ; Get error string
    17 05 00 00     # rd_a0 ~hard auipc                 ; Get error string
    13 05 25 23     # rd_a0 rs1_a0 !hard addi           ; Get error string
                    # +562B
    EF 00 80 18     # RD_RA $File_Print JAL             ; Print it
    EF 00 80 18     # rd_ra $File_Print jal             ; Print it
                    # +392B
    6F 00 80 20     # $Fail JAL                         ; Exit with failure
    6F 00 80 20     # $Fail jal                         ; Exit with failure
                    # +520B




@@ 182,37 182,37 @@ F3 00              ## e_machine Indicating RISC-V
# Receives tokens[j] in a1 and tokens[i] in a2
# Modifies a0
# :print_command ; (0x0600134)
    13 01 41 FF     # RD_SP RS1_SP !-12 ADDI            ; allocate stack
    23 20 11 00     # RS1_SP RS2_RA SW                  ; protect ra
    23 22 B1 00     # RS1_SP RS2_A1 @4 SW               ; protect a1
    23 24 C1 00     # RS1_SP RS2_A2 @8 SW               ; protect a2
    13 01 41 FF     # rd_sp rs1_sp !-12 addi            ; allocate stack
    23 20 11 00     # rs1_sp rs2_ra sw                  ; protect ra
    23 22 B1 00     # rs1_sp rs2_a1 @4 sw               ; protect a1
    23 24 C1 00     # rs1_sp rs2_a2 @8 sw               ; protect a2

    17 05 00 00     # RD_A0 ~prefix AUIPC               ; Get prefix " +> "
    13 05 D5 20     # RD_A0 RS1_A0 !prefix ADDI         ; Get prefix " +> "
    17 05 00 00     # rd_a0 ~prefix auipc               ; Get prefix " +> "
    13 05 D5 20     # rd_a0 rs1_a0 !prefix addi         ; Get prefix " +> "
                    # +525B
    EF 00 80 16     # RD_RA $File_Print JAL             ; print it
    EF 00 80 16     # rd_ra $File_Print jal             ; print it
                    # +360B

# :print_command_loop ; (0x0600150)
    03 A5 05 00     # RD_A0 RS1_A1 LW                   ; get tokens[j]
    EF 00 00 16     # RD_RA $File_Print JAL             ; print it
    03 A5 05 00     # rd_a0 rs1_a1 lw                   ; get tokens[j]
    EF 00 00 16     # rd_ra $File_Print jal             ; print it
                    # +352B
    93 85 45 00     # RD_A1 RS1_A1 !4 ADDI              ; j = j + 1
    13 05 00 02     # RD_A0 !32 ADDI                    ; a0 = ' '
    EF 00 40 19     # RD_RA $fputc JAL                  ; print it
    93 85 45 00     # rd_a1 rs1_a1 !4 addi              ; j = j + 1
    13 05 00 02     # rd_a0 !32 addi                    ; a0 = ' '
    EF 00 40 19     # rd_ra $fputc jal                  ; print it
                    # +404B
    E3 96 C5 FE     # RS1_A1 RS2_A2 @print_command_loop BNE ; continue if j < i, otherwise keep looping
    E3 96 C5 FE     # rs1_a1 rs2_a2 @print_command_loop bne ; continue if j < i, otherwise keep looping
                    # -20B

    13 05 A0 00     # RD_A0 !10 ADDI                    ; a0 = '\n'
    EF 00 80 18     # RD_RA $fputc JAL                  ; print it
    13 05 A0 00     # rd_a0 !10 addi                    ; a0 = '\n'
    EF 00 80 18     # rd_ra $fputc jal                  ; print it
                    # +392B

    83 20 01 00     # RD_RA RS1_SP LW                   ; restore ra
    83 25 41 00     # RD_A1 RS1_SP !4 LW                ; restore a1
    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; restore a2
    13 01 C1 00     # RD_SP RS1_SP !12 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 20 01 00     # rd_ra rs1_sp lw                   ; restore ra
    83 25 41 00     # rd_a1 rs1_sp !4 lw                ; restore a1
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; restore a2
    13 01 C1 00     # rd_sp rs1_sp !12 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# collect_token function


@@ 220,83 220,83 @@ F3 00              ## e_machine Indicating RISC-V
# Overwrites a0
# Uses a0 as c, a1 as token and a2 as token[i]
# :collect_token ; (0x0600184)
    13 01 41 FF     # RD_SP RS1_SP !-12 ADDI            ; allocate stack
    23 20 11 00     # RS1_SP RS2_RA SW                  ; protect ra
    23 22 B1 00     # RS1_SP RS2_A1 @4 SW               ; protect a1
    23 24 C1 00     # RS1_SP RS2_A2 @8 SW               ; protect a2
    13 01 41 FF     # rd_sp rs1_sp !-12 addi            ; allocate stack
    23 20 11 00     # rs1_sp rs2_ra sw                  ; protect ra
    23 22 B1 00     # rs1_sp rs2_a1 @4 sw               ; protect a1
    23 24 C1 00     # rs1_sp rs2_a2 @8 sw               ; protect a2

    37 15 00 00     # RD_A0 ~4096 LUI                   ; 4096 * sizeof(char)
    EF 00 00 0F     # RD_RA $malloc JAL                 ; allocate space
    37 15 00 00     # rd_a0 ~4096 lui                   ; 4096 * sizeof(char)
    EF 00 00 0F     # rd_ra $malloc jal                 ; allocate space
                    # +240B
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; token = malloc(max_string)
    13 06 05 00     # RD_A2 RS1_A0 MV                   ; i = 0; set token[i]
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; token = malloc(max_string)
    13 06 05 00     # rd_a2 rs1_a0 mv                   ; i = 0; set token[i]

# :collect_token_loop ; (0x06001A4)
    EF 00 40 0A     # RD_RA $fgetc JAL                  ; read character
    EF 00 40 0A     # rd_ra $fgetc jal                  ; read character
                    # +164B

    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; if character == EOF
    63 00 55 18     # RS1_A0 RS2_T0 @Done BEQ           ; We are done
    93 02 C0 FF     # rd_t0 !-4 addi                    ; if character == EOF
    63 00 55 18     # rs1_a0 rs2_t0 @Done beq           ; We are done
                    # +384B

    93 02 00 02     # RD_T0 !32 ADDI                    ; if c == ' '
    63 06 55 04     # RS1_A0 RS2_T0 @collect_token_done BEQ ; Space terminates token
    93 02 00 02     # rd_t0 !32 addi                    ; if c == ' '
    63 06 55 04     # rs1_a0 rs2_t0 @collect_token_done beq ; Space terminates token
                    # +76B

    93 02 90 00     # RD_T0 !9 ADDI                     ; if c == '\t'
    63 02 55 04     # RS1_A0 RS2_T0 @collect_token_done BEQ ; Tab terminates token
    93 02 90 00     # rd_t0 !9 addi                     ; if c == '\t'
    63 02 55 04     # rs1_a0 rs2_t0 @collect_token_done beq ; Tab terminates token
                    # +68B

    93 02 A0 00     # RD_T0 !10 ADDI                    ; continue if c == '\n'
    63 16 55 00     # RS1_A0 RS2_T0 @collect_token_comment BNE ; otherwise check next
    93 02 A0 00     # rd_t0 !10 addi                    ; continue if c == '\n'
    63 16 55 00     # rs1_a0 rs2_t0 @collect_token_comment bne ; otherwise check next
                    # +12B

    # newline
    13 0A 10 00     # RD_S4 !1 ADDI                     ; command_done = true
    6F 00 40 03     # $collect_token_done JAL           ; Done with current command
    13 0A 10 00     # rd_s4 !1 addi                     ; command_done = true
    6F 00 40 03     # $collect_token_done jal           ; Done with current command
                    # +52B

# :collect_token_comment ; (0x06001D0)
    93 02 30 02     # RD_T0 !35 ADDI                    ; if c == '#'
    63 18 55 00     # RS1_A0 RS2_T0 @collect_token_escape BNE ; otherwise check next
    93 02 30 02     # rd_t0 !35 addi                    ; if c == '#'
    63 18 55 00     # rs1_a0 rs2_t0 @collect_token_escape bne ; otherwise check next
                    # +16B

    # It is a line comment
    EF 00 80 04     # RD_RA $collect_comment JAL        ; Read whole comment
    EF 00 80 04     # rd_ra $collect_comment jal        ; Read whole comment
                    # +72B
    13 0A 10 00     # RD_S4 !1 ADDI                     ; command_done = true
    EF 00 00 02     # RD_RA $collect_token_done JAL     ; Done
    13 0A 10 00     # rd_s4 !1 addi                     ; command_done = true
    EF 00 00 02     # rd_ra $collect_token_done jal     ; Done
                    # +32B

# :collect_token_escape ; (0x06001E4)
    93 02 C0 05     # RD_T0 !92 ADDI                    ; if c == '\'
    63 16 55 00     # RS1_A0 RS2_T0 @collect_token_other BNE ; otherwise just store it
    93 02 C0 05     # rd_t0 !92 addi                    ; if c == '\'
    63 16 55 00     # rs1_a0 rs2_t0 @collect_token_other bne ; otherwise just store it
                    # +12B

    # Escape character
    EF 00 C0 05     # RD_RA $fgetc JAL                  ; Read the char to drop
    EF 00 C0 05     # rd_ra $fgetc jal                  ; Read the char to drop
                    # +92B
    EF 00 00 01     # RD_RA $collect_token_done JAL     ; We are done
    EF 00 00 01     # rd_ra $collect_token_done jal     ; We are done
                    # +16B

# :collect_token_other ; (0x06001F4)
    23 00 A6 00     # RS1_A2 RS2_A0 SB                  ; token[i] = c
    13 06 16 00     # RD_A2 RS1_A2 !1 ADDI              ; i = i + 1
    6F F0 9F FA     # $collect_token_loop JAL           ; Read another character
    23 00 A6 00     # rs1_a2 rs2_a0 sb                  ; token[i] = c
    13 06 16 00     # rd_a2 rs1_a2 !1 addi              ; i = i + 1
    6F F0 9F FA     # $collect_token_loop jal           ; Read another character
                    # -88B

# :collect_token_done ; (0x0600200)
    63 94 C5 00     # RS1_A1 RS2_A2 @collect_token_good BNE ; return the token unless
    63 94 C5 00     # rs1_a1 rs2_a2 @collect_token_good bne ; return the token unless
                    # +8B
    93 05 00 00     # RD_A1 MV                          ; i == 0, then token = NULL
    93 05 00 00     # rd_a1 mv                          ; i == 0, then token = NULL

# :collect_token_good ; (0x0600208)
    13 85 05 00     # RD_A0 RS1_A1 MV                   ; Return token
    83 20 01 00     # RD_RA RS1_SP LW                   ; restore ra
    83 25 41 00     # RD_A1 RS1_SP !4 LW                ; restore a1
    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; restore a2
    13 01 C1 00     # RD_SP RS1_SP !12 ADDI             ; Deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    13 85 05 00     # rd_a0 rs1_a1 mv                   ; Return token
    83 20 01 00     # rd_ra rs1_sp lw                   ; restore ra
    83 25 41 00     # rd_a1 rs1_sp !4 lw                ; restore a1
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; restore a2
    13 01 C1 00     # rd_sp rs1_sp !12 addi             ; Deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# collect_comment function


@@ 305,51 305,51 @@ F3 00              ## e_machine Indicating RISC-V
# uses a0 as c
# Just throws away everything it reads
# :collect_comment ; (0x0600220)
    13 01 C1 FF     # RD_SP RS1_SP !-4 ADDI             ; allocate stack
    23 20 11 00     # RS1_SP RS2_RA SW                  ; protect ra
    13 01 C1 FF     # rd_sp rs1_sp !-4 addi             ; allocate stack
    23 20 11 00     # rs1_sp rs2_ra sw                  ; protect ra

    EF 00 00 02     # RD_RA $fgetc JAL                  ; c = fgetc(input)
    EF 00 00 02     # rd_ra $fgetc jal                  ; c = fgetc(input)
                    # +32B
    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; if c == EOF
    63 04 55 10     # RS1_A0 RS2_T0 @Fail BEQ           ; Abort
    93 02 C0 FF     # rd_t0 !-4 addi                    ; if c == EOF
    63 04 55 10     # rs1_a0 rs2_t0 @Fail beq           ; Abort
                    # +264B

    93 02 A0 00     # RD_T0 !10 ADDI                    ; if c == '\n'
    E3 14 55 FE     # RS1_A0 RS2_T0 @collect_comment BNE ; loop
    93 02 A0 00     # rd_t0 !10 addi                    ; if c == '\n'
    E3 14 55 FE     # rs1_a0 rs2_t0 @collect_comment bne ; loop
                    # -24B

    83 20 01 00     # RD_RA RS1_SP LW                   ; restore ra
    13 01 41 00     # RD_SP RS1_SP !4 ADDI              ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 20 01 00     # rd_ra rs1_sp lw                   ; restore ra
    13 01 41 00     # rd_sp rs1_sp !4 addi              ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# fgetc function ; (0x0600248)
# Loads FILE* from s2
# Returns -4 (EOF) or char in a0
# :fgetc
    13 01 41 FF     # RD_SP RS1_SP !-12 ADDI            ; allocate stack
    23 22 B1 00     # RS1_SP RS2_A1 @4 SW               ; protect a1
    23 24 C1 00     # RS1_SP RS2_A2 @8 SW               ; protect a2
    13 01 41 FF     # rd_sp rs1_sp !-12 addi            ; allocate stack
    23 22 B1 00     # rs1_sp rs2_a1 @4 sw               ; protect a1
    23 24 C1 00     # rs1_sp rs2_a2 @8 sw               ; protect a2

    93 08 F0 03     # RD_A7 !63 ADDI                    ; sys_read
    93 05 01 00     # RD_A1 RS1_SP MV                   ; Get stack address
    13 05 09 00     # RD_A0 RS1_S2 MV                   ; read from input file
    13 06 10 00     # RD_A2 !1 ADDI                     ; read 1 character
    73 00 00 00     # ECALL                             ; syscall
    93 08 F0 03     # rd_a7 !63 addi                    ; sys_read
    93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    13 05 09 00     # rd_a0 rs1_s2 mv                   ; read from input file
    13 06 10 00     # rd_a2 !1 addi                     ; read 1 character
    73 00 00 00     # ecall                             ; syscall

    63 16 05 00     # RS1_A0 @fgetc_done BNEZ           ; Check if nothing was read
    63 16 05 00     # rs1_a0 @fgetc_done bnez           ; Check if nothing was read
                    # +12B

# :fgetc_fail ; (0x060026C)
    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; Use -4 as EOF
    23 80 55 00     # RS1_A1 RS2_T0 SB                  ; Store EOF in *a1
    93 02 C0 FF     # rd_t0 !-4 addi                    ; Use -4 as EOF
    23 80 55 00     # rs1_a1 rs2_t0 sb                  ; Store EOF in *a1

# :fgetc_done ; (0x0600274)
    03 85 05 00     # RD_A0 RS1_A1 LB                   ; return char in a0
    83 25 41 00     # RD_A1 RS1_SP !4 LW                ; restore a1
    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; restore a2
    13 01 C1 00     # RD_SP RS1_SP !12 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    03 85 05 00     # rd_a0 rs1_a1 lb                   ; return char in a0
    83 25 41 00     # rd_a1 rs1_sp !4 lw                ; restore a1
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; restore a2
    13 01 C1 00     # rd_sp rs1_sp !12 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# Malloc isn't actually required if the program being built fits in the initial memory


@@ 357,83 357,83 @@ F3 00              ## e_machine Indicating RISC-V
# Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes

# :malloc ; (0x0600288)
    13 01 C1 FF     # RD_SP RS1_SP !-4 ADDI             ; allocate stack
    23 20 B1 00     # RS1_SP RS2_A1 SW                  ; protect a1
    13 01 C1 FF     # rd_sp rs1_sp !-4 addi             ; allocate stack
    23 20 B1 00     # rs1_sp rs2_a1 sw                  ; protect a1

    93 05 0B 00     # RD_A1 RS1_S6 MV                   ; Store the current pointer
    33 05 65 01     # RD_A0 RS1_A0 RS2_S6 ADD           ; Request the number of desired bytes
    93 08 60 0D     # RD_A7 !214 ADDI                   ; sys_brk
    73 00 00 00     # ECALL                             ; syscall
    13 0B 05 00     # RD_S6 RS1_A0 MV                   ; Set our malloc pointer
    13 85 05 00     # RD_A0 RS1_A1 MV                   ; Return the pointer
    93 05 0B 00     # rd_a1 rs1_s6 mv                   ; Store the current pointer
    33 05 65 01     # rd_a0 rs1_a0 rs2_s6 add           ; Request the number of desired bytes
    93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    73 00 00 00     # ecall                             ; syscall
    13 0B 05 00     # rd_s6 rs1_a0 mv                   ; Set our malloc pointer
    13 85 05 00     # rd_a0 rs1_a1 mv                   ; Return the pointer

    83 25 01 00     # RD_A1 RS1_SP LW                   ; restore a1
    13 01 41 00     # RD_SP RS1_SP !4 ADDI              ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 25 01 00     # rd_a1 rs1_sp lw                   ; restore a1
    13 01 41 00     # rd_sp rs1_sp !4 addi              ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# File_Print function
# Receives CHAR* in a0
# calls fputc for every non-null char
# :File_Print ; (0x06002B4)
    13 01 41 FF     # RD_SP RS1_SP !-12 ADDI            ; allocate stack
    23 20 11 00     # RS1_SP RS2_RA SW                  ; protect ra
    23 22 B1 00     # RS1_SP RS2_A1 @4 SW               ; protect a1
    23 24 C1 00     # RS1_SP RS2_A2 @8 SW               ; protect a2
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; protect a0
    13 01 41 FF     # rd_sp rs1_sp !-12 addi            ; allocate stack
    23 20 11 00     # rs1_sp rs2_ra sw                  ; protect ra
    23 22 B1 00     # rs1_sp rs2_a1 @4 sw               ; protect a1
    23 24 C1 00     # rs1_sp rs2_a2 @8 sw               ; protect a2
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; protect a0

    63 0C 05 00     # RS1_A0 @File_Print_Done BEQZ      ; Protect against nulls
    63 0C 05 00     # rs1_a0 @File_Print_Done beqz      ; Protect against nulls
                    # +24B

# :File_Print_Loop ; (0x06002CC)
    03 C5 05 00     # RD_A0 RS1_A1 LBU                  ; Read byte
    63 08 05 00     # RS1_A0 @File_Print_Done BEQZ      ; Stop at NULL
    03 C5 05 00     # rd_a0 rs1_a1 lbu                  ; Read byte
    63 08 05 00     # rs1_a0 @File_Print_Done beqz      ; Stop at NULL
                    # +16B

    EF 00 00 02     # RD_RA $fputc JAL                  ; print it
    EF 00 00 02     # rd_ra $fputc jal                  ; print it
                    # +32B
    93 85 15 00     # RD_A1 RS1_A1 !1 ADDI              ; S = S + 1
    6F F0 1F FF     # $File_Print_Loop JAL              ; Keep printing
    93 85 15 00     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
    6F F0 1F FF     # $File_Print_Loop jal              ; Keep printing
                    # -16B

# :File_Print_Done ; (0x06002E0)
    83 20 01 00     # RD_RA RS1_SP LW                   ; restore ra
    83 25 41 00     # RD_A1 RS1_SP !4 LW                ; restore a1
    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; restore a2
    13 01 C1 00     # RD_SP RS1_SP !12 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 20 01 00     # rd_ra rs1_sp lw                   ; restore ra
    83 25 41 00     # rd_a1 rs1_sp !4 lw                ; restore a1
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; restore a2
    13 01 C1 00     # rd_sp rs1_sp !12 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# fputc function
# receives CHAR in a0 and load FILE* from stdout
# writes char and returns
# :fputc ; (0x06002F4)
    13 01 41 FF     # RD_SP RS1_SP !-12 ADDI            ; allocate stack
    23 20 A1 00     # RS1_SP RS2_A0 SW                  ; protect a0
    23 22 B1 00     # RS1_SP RS2_A1 @4 SW               ; protect a1
    23 24 C1 00     # RS1_SP RS2_A2 @8 SW               ; protect a2

    93 08 00 04     # RD_A7 !64 ADDI                    ; sys_write
    13 05 10 00     # RD_A0 !1 ADDI                     ; write to stdout
    93 05 01 00     # RD_A1 RS1_SP MV                   ; Get stack address
    13 06 10 00     # RD_A2 !1 ADDI                     ; write 1 character
    73 00 00 00     # ECALL                             ; syscall

    03 25 01 00     # RD_A0 RS1_SP LW                   ; restore a0
    83 25 41 00     # RD_A1 RS1_SP !4 LW                ; restore a1
    03 26 81 00     # RD_A2 RS1_SP !8 LW                ; restore a2
    13 01 C1 00     # RD_SP RS1_SP !12 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    13 01 41 FF     # rd_sp rs1_sp !-12 addi            ; allocate stack
    23 20 A1 00     # rs1_sp rs2_a0 sw                  ; protect a0
    23 22 B1 00     # rs1_sp rs2_a1 @4 sw               ; protect a1
    23 24 C1 00     # rs1_sp rs2_a2 @8 sw               ; protect a2

    93 08 00 04     # rd_a7 !64 addi                    ; sys_write
    13 05 10 00     # rd_a0 !1 addi                     ; write to stdout
    93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    13 06 10 00     # rd_a2 !1 addi                     ; write 1 character
    73 00 00 00     # ecall                             ; syscall

    03 25 01 00     # rd_a0 rs1_sp lw                   ; restore a0
    83 25 41 00     # rd_a1 rs1_sp !4 lw                ; restore a1
    03 26 81 00     # rd_a2 rs1_sp !8 lw                ; restore a2
    13 01 C1 00     # rd_sp rs1_sp !12 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# :Done ; (0x060032C)
    # Terminate program with 0 return code
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    13 05 00 00     # RD_A0 MV                          ; Return code 0
    73 00 00 00     # ECALL                             ; syscall
    93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    13 05 00 00     # rd_a0 mv                          ; Return code 0
    73 00 00 00     # ecall                             ; syscall

# :Fail ; (0x0600338)
    # Terminate program with 1 return code
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    13 05 10 00     # RD_A0 !1 ADDI                     ; Return code 1
    73 00 00 00     # ECALL                             ; syscall
    93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    13 05 10 00     # rd_a0 !1 addi                     ; Return code 1
    73 00 00 00     # ecall                             ; syscall
# PROGRAM END

# :default_file ; (0x0600344)

M POSIX/riscv64/hex0_riscv64.hex0 => POSIX/riscv64/hex0_riscv64.hex0 +71 -71
@@ 1,6 1,6 @@
## Copyright (C) 2021 Ekaitz Zarraga
## Copyright (C) 2021 Andrius Štikonas
## Copyright (C) 2021 Gabriel Wicki
## Copyright (C) 2021,2022 Gabriel Wicki
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify


@@ 70,142 70,142 @@ F3 00              ## e_machine Indicating RISC-V
01 00 00 00 00 00 00 00 ## Required alignment

# :_start ; (0x0600078)
    13 0A 00 00    # RD_S4 MV                 ; Initialize register
    83 35 01 01    # RD_A1 RS1_SP !16 LD      ; Input file name
    13 0A 00 00    # rd_s4 mv                 ; Initialize register
    83 35 01 01    # rd_a1 rs1_sp !16 ld      ; Input file name

    ; Open input file and store FD in s2
    93 08 80 03    # RD_A7 !56 ADDI           ; sys_openat
    13 05 C0 F9    # RD_A0 !-100 ADDI         ; AT_FDCWD
    13 06 00 00    # RD_A2 MV                 ; read only
    73 00 00 00    # ECALL
    13 09 05 00    # RD_S2 RS1_A0 MV          ; Save fd in for later
    93 08 80 03    # rd_a7 !56 addi           ; sys_openat
    13 05 C0 F9    # rd_a0 !-100 addi         ; AT_FDCWD
    13 06 00 00    # rd_a2 mv                 ; read only
    73 00 00 00    # ecall
    13 09 05 00    # rd_s2 rs1_a0 mv          ; Save fd in s2 for later

    ; Open output file and store the FD in s3
    13 05 C0 F9    # RD_A0 !-100 ADDI         ; AT_FDCWD
    83 35 81 01    # RD_A1 RS1_SP !24 LD      ; Output file (argument 3)
    13 06 10 24    # RD_A2 !577 ADDI          ; octal 00001101
    13 05 C0 F9    # rd_a0 !-100 addi         ; AT_FDCWD
    83 35 81 01    # rd_a1 rs1_sp !24 ld      ; Output file (argument 3)
    13 06 10 24    # rd_a2 !577 addi          ; octal 00001101
    ; O_TRUNC   00001000
    ; O_CREAT   00000100
    ; O_WRONLY  00000001
    ; OCTAL!

    93 06 00 1C    # RD_A3 !448 ADDI          ; Set read, write, execute permission on user
    93 06 00 1C    # rd_a3 !448 addi          ; Set read, write, execute permission on user
    ; S_IRWXU  00700
    ; OCTAL!

    73 00 00 00    # ECALL
    93 09 05 00    # RD_S3 RS1_A0 MV          ; Save fd in for later
    73 00 00 00    # ecall
    93 09 05 00    # rd_s3 rs1_a0 mv          ; Save fd in s3 for later

# :next_byte ; (0x06000AC)
    93 08 F0 03    # RD_A7 !63 ADDI           ; sys_read
    13 05 09 00    # RD_A0 RS1_S2 MV          ; File descriptor
    93 05 01 00    # RD_A1 RS1_SP MV          ; Buffer
    13 06 10 00    # RD_A2 !1 ADDI            ; Size of what we want to read (set for all subsequent syscalls)
    73 00 00 00    # ECALL
    93 08 F0 03    # rd_a7 !63 addi           ; sys_read
    13 05 09 00    # rd_a0 rs1_s2 mv          ; File descriptor
    93 05 01 00    # rd_a1 rs1_sp mv          ; Buffer
    13 06 10 00    # rd_a2 !1 addi            ; Size of what we want to read (set for all subsequent syscalls)
    73 00 00 00    # ecall

    ; If the file ended (0 bytes read) terminate
    63 00 05 0C    # RS1_A0 @terminate BEQZ
    63 00 05 0C    # rs1_a0 @terminate beqz
                   # +192B

    ; Check if it's a comment
    03 05 01 00    # RD_A0 RS1_SP LB
    93 02 30 02    # RD_T0 !0x23 ADDI
    63 08 55 00    # RS1_A0 RS2_T0 @loop BEQ  ; a0 eq to '#'
    03 05 01 00    # rd_a0 rs1_sp lb
    93 02 30 02    # rd_t0 !0x23 addi
    63 08 55 00    # rs1_a0 rs2_t0 @loop beq  ; a0 eq to '#'
                   # +16B
    93 02 B0 03    # RD_T0 !0x3B ADDI
    63 04 55 00    # RS1_A0 RS2_T0 @loop BEQ  ; a0 eq to ';'
    93 02 B0 03    # rd_t0 !0x3B addi
    63 04 55 00    # rs1_a0 rs2_t0 @loop beq  ; a0 eq to ';'
                   # +8B
    6F 00 80 02    # $not_comment JAL
    6F 00 80 02    # $not_comment jal
                   # +40B
# :loop ; (0x06000DC)
        13 05 09 00    # RD_A0 RS1_S2 MV   ; File descriptor
        73 00 00 00    # ECALL             ; sys_read
        13 05 09 00    # rd_a0 rs1_s2 mv   ; File descriptor
        73 00 00 00    # ecall             ; sys_read

        ; If the file ended (0 bytes read) terminate
        63 0E 05 08    # RS1_A0 @terminate BEQZ
        63 0E 05 08    # rs1_a0 @terminate beqz
                       # +156B
        ; Check if read byte is the end of the comment,
        ; in the case it is continue processing
        03 05 01 00     # RD_A0 RS1_SP LB
        93 02 A0 00     # RD_T0 !0xA ADDI
        E3 0E 55 FA     # RS1_A0 RS2_T0 @next_byte BEQ ; a0 eq to \n
        ; Check if read byte is the end of the comment (i.e. a newline character),
        ; in that case we continue processing
        03 05 01 00     # rd_a0 rs1_sp lb
        93 02 A0 00     # rd_t0 !0xA addi
        E3 0E 55 FA     # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \n
                        # -68B
        93 02 D0 00     # RD_T0 !0xD ADDI
        E3 0A 55 FA     # RS1_A0 RS2_T0 @next_byte BEQ ; a0 eq to \r
        93 02 D0 00     # rd_t0 !0xD addi
        E3 0A 55 FA     # rs1_a0 rs2_t0 @next_byte beq ; a0 eq to \r
                        # -76B
    6F F0 1F FE    # $loop JAL
    6F F0 1F FE    # $loop jal
# :not_comment ; (0x0600100)
    ; Check if it's a hex character:
    ; in the case it's not, ignores and reads next byte
    03 05 01 00    # RD_A0 RS1_SP LB
    03 05 01 00    # rd_a0 rs1_sp lb

    ; Is it between '0' and '9'?
    93 02 00 03    # RD_T0 !48 ADDI           ; '0' character
    63 4A 55 00    # RS1_A0 RS2_T0 @uppercase_alpha BLT
    93 02 00 03    # rd_t0 !48 addi           ; '0' character
    63 4A 55 00    # rs1_a0 rs2_t0 @uppercase_alpha blt
                   # +20B
    93 02 90 03    # RD_T0 !57 ADDI           ; '9' character
    63 C6 A2 00    # RS1_T0 RS2_A0 @uppercase_alpha BLT
    93 02 90 03    # rd_t0 !57 addi           ; '9' character
    63 C6 A2 00    # rs1_t0 rs2_a0 @uppercase_alpha blt
                   # +12B
    13 05 05 FD    # RD_A0 RS1_A0 !-48 ADDI
    6F 00 00 03    # $hex_read JAL
    13 05 05 FD    # rd_a0 rs1_a0 !-48 addi
    6F 00 00 03    # $hex_read jal
                   # +48B
# :uppercase_alpha ; (0x060011C)
    ; Is it between 'A' and 'F'?
    93 02 10 04    # RD_T0 !65 ADDI           ; 'A' character
    63 4A 55 00    # RS1_A0 RS2_T0 @lowercase_alpha BLT
    93 02 10 04    # rd_t0 !65 addi           ; 'A' character
    63 4A 55 00    # rs1_a0 rs2_t0 @lowercase_alpha blt
                   # +20B
    93 02 60 04    # RD_T0 !70 ADDI           ; 'F' character
    63 C6 A2 00    # RS1_T0 RS2_A0 @lowercase_alpha BLT
    93 02 60 04    # rd_t0 !70 addi           ; 'F' character
    63 C6 A2 00    # rs1_t0 rs2_a0 @lowercase_alpha blt
                   # +12B
    13 05 95 FC    # RD_A0 RS1_A0 !-55 ADDI
    6F 00 80 01    # $hex_read JAL
    13 05 95 FC    # rd_a0 rs1_a0 !-55 addi
    6F 00 80 01    # $hex_read jal
                   # +24B
# :lowercase_alpha ; (0x0600134)
    ; Is it between 'a' and 'f'?
    93 02 10 06    # RD_T0 !97 ADDI           ; 'a' character
    E3 4A 55 F6    # RS1_A0 RS2_T0 @next_byte BLT ; Not hex, continue reading
    93 02 10 06    # rd_t0 !97 addi           ; 'a' character
    E3 4A 55 F6    # rs1_a0 rs2_t0 @next_byte blt ; Not hex, continue reading
                   # -140B
    93 02 60 06    # RD_T0 !102 ADDI          ; 'f' character
    E3 C6 A2 F6    # RS1_T0 RS2_A0 @next_byte BLT ; Not hex, continue reading
    93 02 60 06    # rd_t0 !102 addi          ; 'f' character
    E3 C6 A2 F6    # rs1_t0 rs2_a0 @next_byte blt ; Not hex, continue reading
                   # -148B
    13 05 95 FA    # RD_A0 RS1_A0 !-87 ADDI
    13 05 95 FA    # rd_a0 rs1_a0 !-87 addi
# :hex_read ; (0x0600148)
    ; END check hex -- leaves the half byte in a0

    63 18 0A 00    # RS1_S4 @combine BNEZ     ; if toggle != 0 -> combine
    63 18 0A 00    # rs1_s4 @combine bnez     ; if toggle != 0 -> combine
                   # +16B
    ; Toggle == 0, we need to prepare for later
    93 0A 05 00    # RD_S5 RS1_A0 MV          ; Load hold
    93 0A 05 00    # rd_s5 rs1_a0 mv          ; Load hold

    13 0A 10 00    # RD_S4 !1 ADDI            ; Set toggle
    6F F0 9F F5    # $next_byte JAL           ; Read next byte
    13 0A 10 00    # rd_s4 !1 addi            ; Set toggle
    6F F0 9F F5    # $next_byte jal           ; Read next byte
                   # -168B

# :combine ; (0x0600158)
    ; Combine half bytes
    93 95 4A 00    # RD_A1 RS1_S5 RS2_X4 SLLI ; Shift logical left 4 times
    33 05 B5 00    # RD_A0 RS1_A0 RS2_A1 ADD  ; Combine two half bytes
    93 95 4A 00    # rd_a1 rs1_s5 rs2_x4 slli ; Shift logical left 4 times
    33 05 B5 00    # rd_a0 rs1_a0 rs2_a1 add  ; Combine two half bytes
    ; Leaves the full byte in a0

    ; Values are combined, now we write in the file
    23 00 A1 00    # RS1_SP RS2_A0 SB         ; Store prepared byte in buffer
    93 08 00 04    # RD_A7 !64 ADDI           ; sys_write
    13 85 09 00    # RD_A0 RS1_S3 MV          ; file descriptor (stdout)
    93 05 01 00    # RD_A1 RS1_SP MV          ; string address
    73 00 00 00    # ECALL
    23 00 A1 00    # rs1_sp rs2_a0 sb         ; Store prepared byte in buffer
    93 08 00 04    # rd_a7 !64 addi           ; sys_write
    13 85 09 00    # rd_a0 rs1_s3 mv          ; file descriptor (stdout)
    93 05 01 00    # rd_a1 rs1_sp mv          ; string address
    73 00 00 00    # ecall

    ; Update globals
    13 0A 00 00    # RD_S4 MV                 ; Clear toggle
    93 0A 00 00    # RD_S5 MV                 ; Clear hold
    13 0A 00 00    # rd_s4 mv                 ; Clear toggle
    93 0A 00 00    # rd_s5 mv                 ; Clear hold

    ; Read next byte
    6F F0 1F F3    # $next_byte JAL
    6F F0 1F F3    # $next_byte jal
                   # -208B

# :terminate  ; (0x600180)
    ; Terminate program with 0 return code
    93 08 D0 05    # RD_A7 !93 ADDI           ; sys_exit
    73 00 00 00    # ECALL
    93 08 D0 05    # rd_a7 !93 addi           ; sys_exit
    73 00 00 00    # ecall
# PROGRAM END

# :ELF_end ; (0x600188)

D POSIX/riscv64/kaem-micro.hex0 => POSIX/riscv64/kaem-micro.hex0 +0 -156
@@ 1,156 0,0 @@
## Copyright (C) 2021 Andrius Štikonas
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## stage0 is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with stage0.  If not, see <http://www.gnu.org/licenses/>.

# This is not a real kaem but instead a small hardcoded script to build
# and launch kaem-minimal.
# It first uses hex0-seed to build hex0.
# Then uses hex0 to build kaem-minimal and starts it.

# It expects hex0_riscv64.hex0 and kaem-minimal.hex0 files to be in the current directory.
# Path to hex0-seed is assumed to be ../bootstrap-seeds/POSIX/riscv64/hex0-seed
# However it is the last thing in the binary, so updating it is trivial and
# does not affect anything else in the file.

# Register use:
# s1: address to pointer array of program and arguments to be executed
# s2: have_hex0

## ELF Header
#:ELF_base
7F 45 4C 46        ## e_ident[EI_MAG0-3] ELF's magic number

02                 ## e_ident[EI_CLASS] Indicating 64 bit
01                 ## e_ident[EI_DATA] Indicating little endianness
01                 ## e_ident[EI_VERSION] Indicating original elf

03                 ## e_ident[EI_OSABI] Set at 3 for Linux
00                 ## e_ident[EI_ABIVERSION] Ignored for Statically linked executables

00 00 00 00 00 00 00 ## e_ident[EI_PAD]
02 00              ## e_type Indicating Executable
F3 00              ## e_machine Indicating RISC-V
01 00 00 00        ## e_version Indicating original elf

78 00 60 00 00 00 00 00 ## e_entry Address of the entry point (Number of bytes this header is + Base Address)
40 00 00 00 00 00 00 00 ## e_phoff Address of program header table
00 00 00 00 00 00 00 00 ## e_shoff Address of section header table

00 00 00 00        ## e_flags
40 00              ## e_ehsize Indicating our 64 Byte header

38 00              ## e_phentsize size of a program header table
01 00              ## e_phnum number of entries in program table

00 00              ## e_shentsize size of a section header table
00 00              ## e_shnum number of entries in section table

00 00              ## e_shstrndx index of the section names

## Program Header
#:ELF_program_headers
01 00 00 00             ## p_type
07 00 00 00             ## Flags
00 00 00 00 00 00 00 00 ## p_offset

00 00 60 00 00 00 00 00 ## p_vaddr
00 00 60 00 00 00 00 00 ## p_physaddr

69 01 00 00 00 00 00 00 ## p_filesz
69 01 00 00 00 00 00 00 ## p_memsz

01 00 00 00 00 00 00 00 ## Required alignment

#:ELF_text
# :_start ; (0x0600078)

    97 04 00 00     # RD_S1 ~argv_hex0 AUIPC            ; hex0-seed hex0_riscv64.hex0 hex0    
    93 84 84 05     # RD_S1 RS1_S1 !argv_hex0 ADDI      # +88B

    6F 00 00 01     # $clone JAL                        ; jump to clone
                    # +16B

# :kaem_minimal ; (0x0600084)
    97 04 00 00     # RD_S1 ~argv_kaem AUIPC            ; hex0 kaem-minimal.hex0 kaem
    93 84 C4 06     # RD_S1 RS1_S1 !argv_kaem ADDI
                    # +108B

    13 49 F9 FF     # RD_S2 RS1_S2 NOT                  ; s2 = !s2

# :clone ; (0x0600090)
    93 08 C0 0D     # RD_A7 !220 ADDI                   ; sys_clone
    13 05 10 01     # RD_A0 !17 ADDI                    ; SIGCHLD flag
    73 00 00 00     # ECALL                             ; syscall

    63 1E 05 00     # RS1_A0 @parent BNEZ               ; if f == 0 it is child
                    # +28B

    # Deal with child case
# :execve ; (0x06000a0)
    03 B5 04 00     # RD_A0 RS1_S1 LD                   ; program

    93 08 D0 0D     # RD_A7 !221 ADDI                   ; sys_execve
    93 85 04 00     # RD_A1 RS1_S1 MV                   ; argv
    73 00 00 00     # ECALL                             ; execve(program, argv)

    # Terminate child program (only happens on error)
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    73 00 00 00     # ECALL                             ; syscall

# :parent ; (0x06000b8)
    93 08 40 10     # RD_A7 !260 ADDI                   ; sys_wait4
    73 00 00 00     # ECALL                             ; syscall
    E3 02 09 FC     # RS1_S2 @kaem_minimal BEQZ         ; Now build kaem
                    # -60B

# :start_kaem ; (0x06000c4)
    97 04 00 00     # RD_S1 ~argv_kaem_minimal AUIPC ; kaem
    93 84 C4 03     # RD_S1 RS1_S1 !argv_kaem_minimal ADDI
                    # +60B
    6F F0 5F FD     # $execve JAL                       ; execve into kaem-minimal
                    # -44B

# PROGRAM END

# :argv_hex0 ; (0x06000d0)
    3E 01 60 00 00 00 00 00    # &hex0_seed
    10 01 60 00 00 00 00 00    # &hex0_source ; (0x06000d8)
    22 01 60 00 00 00 00 00    # &hex0_out    ; (0x06000e0)
    00 00 00 00 00 00 00 00

# :argv_kaem ; (0x06000f0)
    22 01 60 00 00 00 00 00    # &hex0_out
    27 01 60 00 00 00 00 00    # &kaem_source  ; (0x06000f8)
# :argv_kaem_minimal ; (0x0600100)
    39 01 60 00 00 00 00 00    # &kaem_out
    00 00 00 00 00 00 00 00

# :hex0_source ; (0x0600110)
    68 65 78 30 5F 72 69 73 63 76 36 34 2E 68 65 78 30 00 ; hex0_riscv64.hex0

# :hex0_out ; (0x0600122)
    68 65 78 30 00                                        ; hex0

# :kaem_source ; (0x0600127)
    6B 61 65 6D 2D 6D 69 6E 69 6D 61 6C 2E 68 65 78 30 00 ; kaem-minimal.hex0

# :kaem_out ; (0x0600139)
    6B 61 65 6D 00                                        ; kaem

# Put this one last to make updating hardcoded path trivial
# :hex0_seed ; (0x060013e)
    2E 2E 2F 62 6F 6F 74 73 74 72 61 70 2D 73 65 65 64 73
    2F 50 4F 53 49 58 2F 72 69 73 63 76 36 34 2F 68 65 78
    30 2D 73 65 65 64 00                                  ; ../bootstrap-seeds/POSIX/riscv64/hex0-seed

M POSIX/riscv64/kaem-minimal.hex0 => POSIX/riscv64/kaem-minimal.hex0 +196 -196
@@ 68,122 68,122 @@ B2 03 00 00 00 00 00 00 ## p_memsz
# s4: command_done
# s6: malloc pointer

    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; Input file name
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; Input file name

    63 16 06 00     # RS1_A2 @_start_out BNEZ           ; Use input file if specified
    63 16 06 00     # rs1_a2 @_start_out bnez           ; Use input file if specified
                    # +12B

    # Else use kaem.riscv64
    17 06 00 00     # RD_A2 ~default_file AUIPC         ; load address of default_file
    13 06 06 30     # RD_A2 RS1_A2 !default_file ADDI   ; into register a2
    17 06 00 00     # rd_a2 ~default_file auipc         ; load address of default_file
    13 06 06 30     # rd_a2 rs1_a2 !default_file addi   ; into register a2
                    # +768B

# :_start_out ; (0x0600088)

    # Open input file and store FD in s2
    93 08 80 03     # RD_A7 !56 ADDI                    ; sys_openat
    13 05 C0 F9     # RD_A0 !-100 ADDI                  ; AT_FDCWD
    93 05 06 00     # RD_A1 RS1_A2 MV                   ; file name
    13 06 00 00     # RD_A2 ADDI                        ; read only
    73 00 00 00     # ECALL                             ; syscall
    63 4C 05 2C     # RS1_A0 @Fail BLTZ                 ; Error opening file
    93 08 80 03     # rd_a7 !56 addi                    ; sys_openat
    13 05 C0 F9     # rd_a0 !-100 addi                  ; AT_FDCWD
    93 05 06 00     # rd_a1 rs1_a2 mv                   ; file name
    13 06 00 00     # rd_a2 addi                        ; read only
    73 00 00 00     # ecall                             ; syscall
    63 4C 05 2C     # rs1_a0 @Fail bltz                 ; Error opening file
                    # +728B
    13 09 05 00     # RD_S2 RS1_A0 MV                   ; Save fd in for later
    13 09 05 00     # rd_s2 rs1_a0 mv                   ; Save fd in for later

    # Prepare heap memory
    93 08 60 0D     # RD_A7 !214 ADDI                   ; sys_brk
    13 05 00 00     # RD_A0 MV                          ; Get current brk
    73 00 00 00     # ECALL                             ; syscall
    13 0B 05 00     # RD_S6 RS1_A0 MV                   ; Set our malloc pointer
    93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    13 05 00 00     # rd_a0 mv                          ; Get current brk
    73 00 00 00     # ecall                             ; syscall
    13 0B 05 00     # rd_s6 rs1_a0 mv                   ; Set our malloc pointer

# Using a1 for tokens and a2 for tokens[i]
# :main_loop ; (0x06000B4)
    13 05 10 00     # RD_A0 !1 ADDI                     ; 256 * sizeof(char*)
    13 15 B5 00     # RD_A0 RS1_A0 RS2_X11 SLLI         ; 2048 = 1 << 11
    EF 00 80 20     # RD_RA $malloc JAL                 ; allocate space
    13 05 10 00     # rd_a0 !1 addi                     ; 256 * sizeof(char*)
    13 15 B5 00     # rd_a0 rs1_a0 rs2_x11 slli         ; 2048 = 1 << 11
    EF 00 80 20     # rd_ra $malloc jal                 ; allocate space
                    # +520B
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; set tokens pointer
    13 06 05 00     # RD_A2 RS1_A0 MV                   ; set tokens[i] pointer (i=0)
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; set tokens pointer
    13 06 05 00     # rd_a2 rs1_a0 mv                   ; set tokens[i] pointer (i=0)

    93 09 00 00     # RD_S3 MV                          ; status = 0
    13 0A 00 00     # RD_S4 MV                          ; command_done = 0
    93 09 00 00     # rd_s3 mv                          ; status = 0
    13 0A 00 00     # rd_s4 mv                          ; command_done = 0

# :collect_command ; (0x06000D0)
    EF 00 00 0F     # RD_RA $collect_token JAL          ; Get another token
    EF 00 00 0F     # rd_ra $collect_token jal          ; Get another token
                    # +240B
    63 06 05 00     # RS1_A0 @collect_command_comment BEQZ ; if NULL == result then it is a comment, don't store
    63 06 05 00     # rs1_a0 @collect_command_comment beqz ; if NULL == result then it is a comment, don't store
                    # +12B

    23 30 A6 00     # RS1_A2 RS2_A0 SD                  ; tokens[i] = result
    13 06 86 00     # RD_A2 RS1_A2 !8 ADDI              ; i = i + 1 (sizeof(char*) = 8)
    23 30 A6 00     # rs1_a2 rs2_a0 sd                  ; tokens[i] = result
    13 06 86 00     # rd_a2 rs1_a2 !8 addi              ; i = i + 1 (sizeof(char*) = 8)

# :collect_command_comment ; (0x06000E0)
    E3 08 0A FE     # RS1_S4 @collect_command BEQZ      ; keep looping if 0 == command_done
    E3 08 0A FE     # rs1_s4 @collect_command beqz      ; keep looping if 0 == command_done
                    # -16B

    # Deal with line comments
    E3 88 C5 FC     # RS1_A1 RS2_A2 @main_loop BEQ      ; keep looping if comment
    E3 88 C5 FC     # rs1_a1 rs2_a2 @main_loop beq      ; keep looping if comment
                    # -48B

    EF 00 80 08     # RD_RA $print_command JAL          ; print the command
    EF 00 80 08     # rd_ra $print_command jal          ; print the command
                    # +136B
    03 B5 05 00     # RD_A0 RS1_A1 LD                   ; program = tokens[0]
    63 02 05 28     # RS1_A0 @Fail BEQZ                 ; Error, no program
    03 B5 05 00     # rd_a0 rs1_a1 ld                   ; program = tokens[0]
    63 02 05 28     # rs1_a0 @Fail beqz                 ; Error, no program
                    # +644B

    13 01 81 FF     # RD_SP RS1_SP !-8 ADDI             ; allocate stack
    23 30 B1 00     # RS1_SP RS2_A1 SD                  ; protect tokens
    13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; allocate stack
    23 30 B1 00     # rs1_sp rs2_a1 sd                  ; protect tokens

    93 08 C0 0D     # RD_A7 !220 ADDI                   ; sys_clone
    13 05 10 01     # RD_A0 !17 ADDI                    ; SIGCHLD flag
    93 05 00 00     # RD_A1 MV                          ; Child uses duplicate of parent's stack
    73 00 00 00     # ECALL                             ; syscall
    93 08 C0 0D     # rd_a7 !220 addi                   ; sys_clone
    13 05 10 01     # rd_a0 !17 addi                    ; SIGCHLD flag
    93 05 00 00     # rd_a1 mv                          ; Child uses duplicate of parent's stack
    73 00 00 00     # ecall                             ; syscall

    83 35 01 00     # RD_A1 RS1_SP LD                   ; restore tokens
    13 01 81 00     # RD_SP RS1_SP !8 ADDI              ; deallocate stack
    83 35 01 00     # rd_a1 rs1_sp ld                   ; restore tokens
    13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack

    63 40 05 26     # RS1_A0 @Fail BLTZ                 ; if f == -1 no child was created
    63 40 05 26     # rs1_a0 @Fail bltz                 ; if f == -1 no child was created
                    # +608B
    63 1A 05 00     # RS1_A0 @collect_command_parent BNEZ ; if f == 0 it is child
    63 1A 05 00     # rs1_a0 @collect_command_parent bnez ; if f == 0 it is child
                    # +20B

    # Deal with child case
    93 08 D0 0D     # RD_A7 !221 ADDI                   ; sys_execve
    03 B5 05 00     # RD_A0 RS1_A1 LD                   ; program = tokens[0]
    73 00 00 00     # ECALL                             ; execve(program, tokens)
    EF 00 C0 24     # RD_RA $Fail JAL                   ; Exit with an error
    93 08 D0 0D     # rd_a7 !221 addi                   ; sys_execve
    03 B5 05 00     # rd_a0 rs1_a1 ld                   ; program = tokens[0]
    73 00 00 00     # ecall                             ; execve(program, tokens)
    EF 00 C0 24     # rd_ra $Fail jal                   ; Exit with an error
                    # +588B

# :collect_command_parent ; (0x060012C)
    93 08 40 10     # RD_A7 !260 ADDI                   ; sys_wait4
    13 06 00 00     # RD_A2 MV                          ; set options = 0
    93 06 00 00     # RD_A3 MV                          ; set *ruseage = NULL
    73 00 00 00     # ECALL                             ; syscall
    93 08 40 10     # rd_a7 !260 addi                   ; sys_wait4
    13 06 00 00     # rd_a2 mv                          ; set options = 0
    93 06 00 00     # rd_a3 mv                          ; set *ruseage = NULL
    73 00 00 00     # ecall                             ; syscall

    # wait4 returns wstatus pointer, from which we can extract child's exit status
    # Check if child exited
    83 B5 05 00     # RD_A1 RS1_A1 LD                   ; Dereference wstatus pointer
    93 02 F0 07     # RD_T0 !0x7f ADDI                  ; t0 = 0x7f
    B3 F2 55 00     # RD_T0 RS1_A1 RS2_T0 AND           ; WTERMSIG(s) ((s) & 0x7f)
    63 9C 02 00     # RS1_T0 @abort BNEZ                ; Something went wrong, child did not exit
    83 B5 05 00     # rd_a1 rs1_a1 ld                   ; Dereference wstatus pointer
    93 02 F0 07     # rd_t0 !0x7f addi                  ; t0 = 0x7f
    B3 F2 55 00     # rd_t0 rs1_a1 rs2_t0 and           ; WTERMSIG(s) ((s) & 0x7f)
    63 9C 02 00     # rs1_t0 @abort bnez                ; Something went wrong, child did not exit
                    # +24B

    # Check exit status: WEXITSTATUS(s) (((s) & 0xff00) >> 8)
    B7 02 01 00     # RD_T0 ~0xff00 LUI                 ; 0xff00 = 0xffff - 0xff = 2^16 - 2^8
    9B 82 02 F0     # RD_T0 RS1_T0 !-256 ADDIW          ; t0 = 0xff00
    B3 F2 55 00     # RD_T0 RS1_A1 RS2_T0 AND           ; (s) & 0xff00
    93 D9 82 00     # RD_S3 RS1_T0 RS2_X8 SRLI          ; Shift right by 8 to get status
    B7 02 01 00     # rd_t0 ~0xff00 lui                 ; 0xff00 = 0xffff - 0xff = 2^16 - 2^8
    9B 82 02 F0     # rd_t0 rs1_t0 !-256 addiw          ; t0 = 0xff00
    B3 F2 55 00     # rd_t0 rs1_a1 rs2_t0 and           ; (s) & 0xff00
    93 D9 82 00     # rd_s3 rs1_t0 rs2_x8 srli          ; Shift right by 8 to get status

    E3 8C 09 F4     # RS1_S3 @main_loop BEQZ            ; Loop if 0 == status
    E3 8C 09 F4     # rs1_s3 @main_loop beqz            ; Loop if 0 == status
                    # -168B

# :abort ; (0x0600160)
    17 05 00 00     # RD_A0 ~hard AUIPC                 ; Get error string
    13 05 25 23     # RD_A0 RS1_A0 !hard ADDI           ; Get error string
    17 05 00 00     # rd_a0 ~hard auipc                 ; Get error string
    13 05 25 23     # rd_a0 rs1_a0 !hard addi           ; Get error string
                    # +562B
    EF 00 80 18     # RD_RA $File_Print JAL             ; Print it
    EF 00 80 18     # rd_ra $File_Print jal             ; Print it
                    # +392B
    6F 00 80 20     # $Fail JAL                         ; Exit with failure
    6F 00 80 20     # $Fail jal                         ; Exit with failure
                    # +520B




@@ 191,37 191,37 @@ B2 03 00 00 00 00 00 00 ## p_memsz
# Receives tokens[j] in a1 and tokens[i] in a2
# Modifies a0
# :print_command ; (0x0600170)
    13 01 81 FE     # RD_SP RS1_SP !-24 ADDI            ; allocate stack
    23 30 11 00     # RS1_SP RS2_RA SD                  ; protect ra
    23 34 B1 00     # RS1_SP RS2_A1 @8 SD               ; protect a1
    23 38 C1 00     # RS1_SP RS2_A2 @16 SD              ; protect a2
    13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; allocate stack
    23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2

    17 05 00 00     # RD_A0 ~prefix AUIPC               ; Get prefix " +> "
    13 05 D5 20     # RD_A0 RS1_A0 !prefix ADDI         ; Get prefix " +> "
    17 05 00 00     # rd_a0 ~prefix auipc               ; Get prefix " +> "
    13 05 D5 20     # rd_a0 rs1_a0 !prefix addi         ; Get prefix " +> "
                    # +525B
    EF 00 80 16     # RD_RA $File_Print JAL             ; print it
    EF 00 80 16     # rd_ra $File_Print jal             ; print it
                    # +360B

# :print_command_loop ; (0x060018C)
    03 B5 05 00     # RD_A0 RS1_A1 LD                   ; get tokens[j]
    EF 00 00 16     # RD_RA $File_Print JAL             ; print it
    03 B5 05 00     # rd_a0 rs1_a1 ld                   ; get tokens[j]
    EF 00 00 16     # rd_ra $File_Print jal             ; print it
                    # +352B
    93 85 85 00     # RD_A1 RS1_A1 !8 ADDI              ; j = j + 1
    13 05 00 02     # RD_A0 !32 ADDI                    ; a0 = ' '
    EF 00 40 19     # RD_RA $fputc JAL                  ; print it
    93 85 85 00     # rd_a1 rs1_a1 !8 addi              ; j = j + 1
    13 05 00 02     # rd_a0 !32 addi                    ; a0 = ' '
    EF 00 40 19     # rd_ra $fputc jal                  ; print it
                    # +404B
    E3 96 C5 FE     # RS1_A1 RS2_A2 @print_command_loop BNE ; continue if j < i, otherwise keep looping
    E3 96 C5 FE     # rs1_a1 rs2_a2 @print_command_loop bne ; continue if j < i, otherwise keep looping
                    # -20B

    13 05 A0 00     # RD_A0 !10 ADDI                    ; a0 = '\n'
    EF 00 80 18     # RD_RA $fputc JAL                  ; print it
    13 05 A0 00     # rd_a0 !10 addi                    ; a0 = '\n'
    EF 00 80 18     # rd_ra $fputc jal                  ; print it
                    # +392B

    83 30 01 00     # RD_RA RS1_SP LD                   ; restore ra
    83 35 81 00     # RD_A1 RS1_SP !8 LD                ; restore a1
    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; restore a2
    13 01 81 01     # RD_SP RS1_SP !24 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; restore a2
    13 01 81 01     # rd_sp rs1_sp !24 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# collect_token function


@@ 229,83 229,83 @@ B2 03 00 00 00 00 00 00 ## p_memsz
# Overwrites a0
# Uses a0 as c, a1 as token and a2 as token[i]
# :collect_token ; (0x06001C0)
    13 01 81 FE     # RD_SP RS1_SP !-24 ADDI            ; allocate stack
    23 30 11 00     # RS1_SP RS2_RA SD                  ; protect ra
    23 34 B1 00     # RS1_SP RS2_A1 @8 SD               ; protect a1
    23 38 C1 00     # RS1_SP RS2_A2 @16 SD              ; protect a2
    13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; allocate stack
    23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2

    37 15 00 00     # RD_A0 ~4096 LUI                   ; 4096 * sizeof(char)
    EF 00 00 0F     # RD_RA $malloc JAL                 ; allocate space
    37 15 00 00     # rd_a0 ~4096 lui                   ; 4096 * sizeof(char)
    EF 00 00 0F     # rd_ra $malloc jal                 ; allocate space
                    # +240B
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; token = malloc(max_string)
    13 06 05 00     # RD_A2 RS1_A0 MV                   ; i = 0; set token[i]
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; token = malloc(max_string)
    13 06 05 00     # rd_a2 rs1_a0 mv                   ; i = 0; set token[i]

# :collect_token_loop ; (0x06001E0)
    EF 00 40 0A     # RD_RA $fgetc JAL                  ; read character
    EF 00 40 0A     # rd_ra $fgetc jal                  ; read character
                    # +164B

    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; if character == EOF
    63 00 55 18     # RS1_A0 RS2_T0 @Done BEQ           ; We are done
    93 02 C0 FF     # rd_t0 !-4 addi                    ; if character == EOF
    63 00 55 18     # rs1_a0 rs2_t0 @Done beq           ; We are done
                    # +384B

    93 02 00 02     # RD_T0 !32 ADDI                    ; if c == ' '
    63 06 55 04     # RS1_A0 RS2_T0 @collect_token_done BEQ ; Space terminates token
    93 02 00 02     # rd_t0 !32 addi                    ; if c == ' '
    63 06 55 04     # rs1_a0 rs2_t0 @collect_token_done beq ; Space terminates token
                    # +76B

    93 02 90 00     # RD_T0 !9 ADDI                     ; if c == '\t'
    63 02 55 04     # RS1_A0 RS2_T0 @collect_token_done BEQ ; Tab terminates token
    93 02 90 00     # rd_t0 !9 addi                     ; if c == '\t'
    63 02 55 04     # rs1_a0 rs2_t0 @collect_token_done beq ; Tab terminates token
                    # +68B

    93 02 A0 00     # RD_T0 !10 ADDI                    ; continue if c == '\n'
    63 16 55 00     # RS1_A0 RS2_T0 @collect_token_comment BNE ; otherwise check next
    93 02 A0 00     # rd_t0 !10 addi                    ; continue if c == '\n'
    63 16 55 00     # rs1_a0 rs2_t0 @collect_token_comment bne ; otherwise check next
                    # +12B

    # newline
    13 0A 10 00     # RD_S4 !1 ADDI                     ; command_done = true
    6F 00 40 03     # $collect_token_done JAL           ; Done with current command
    13 0A 10 00     # rd_s4 !1 addi                     ; command_done = true
    6F 00 40 03     # $collect_token_done jal           ; Done with current command
                    # +52B

# :collect_token_comment ; (0x060020C)
    93 02 30 02     # RD_T0 !35 ADDI                    ; if c == '#'
    63 18 55 00     # RS1_A0 RS2_T0 @collect_token_escape BNE ; otherwise check next
    93 02 30 02     # rd_t0 !35 addi                    ; if c == '#'
    63 18 55 00     # rs1_a0 rs2_t0 @collect_token_escape bne ; otherwise check next
                    # +16B

    # It is a line comment
    EF 00 80 04     # RD_RA $collect_comment JAL        ; Read whole comment
    EF 00 80 04     # rd_ra $collect_comment jal        ; Read whole comment
                    # +72B
    13 0A 10 00     # RD_S4 !1 ADDI                     ; command_done = true
    EF 00 00 02     # RD_RA $collect_token_done JAL     ; Done
    13 0A 10 00     # rd_s4 !1 addi                     ; command_done = true
    EF 00 00 02     # rd_ra $collect_token_done jal     ; Done
                    # +32B

# :collect_token_escape ; (0x0600220)
    93 02 C0 05     # RD_T0 !92 ADDI                    ; if c == '\'
    63 16 55 00     # RS1_A0 RS2_T0 @collect_token_other BNE ; otherwise just store it
    93 02 C0 05     # rd_t0 !92 addi                    ; if c == '\'
    63 16 55 00     # rs1_a0 rs2_t0 @collect_token_other bne ; otherwise just store it
                    # +12B

    # Escape character
    EF 00 C0 05     # RD_RA $fgetc JAL                  ; Read the char to drop
    EF 00 C0 05     # rd_ra $fgetc jal                  ; Read the char to drop
                    # +92B
    EF 00 00 01     # RD_RA $collect_token_done JAL     ; We are done
    EF 00 00 01     # rd_ra $collect_token_done jal     ; We are done
                    # +16B

# :collect_token_other ; (0x0600230)
    23 00 A6 00     # RS1_A2 RS2_A0 SB                  ; token[i] = c
    13 06 16 00     # RD_A2 RS1_A2 !1 ADDI              ; i = i + 1
    6F F0 9F FA     # $collect_token_loop JAL           ; Read another character
    23 00 A6 00     # rs1_a2 rs2_a0 sb                  ; token[i] = c
    13 06 16 00     # rd_a2 rs1_a2 !1 addi              ; i = i + 1
    6F F0 9F FA     # $collect_token_loop jal           ; Read another character
                    # -88B

# :collect_token_done ; (0x060023C)
    63 94 C5 00     # RS1_A1 RS2_A2 @collect_token_good BNE ; return the token unless
    63 94 C5 00     # rs1_a1 rs2_a2 @collect_token_good bne ; return the token unless
                    # +8B
    93 05 00 00     # RD_A1 MV                          ; i == 0, then token = NULL
    93 05 00 00     # rd_a1 mv                          ; i == 0, then token = NULL

# :collect_token_good ; (0x0600244)
    13 85 05 00     # RD_A0 RS1_A1 MV                   ; Return token
    83 30 01 00     # RD_RA RS1_SP LD                   ; Restore ra
    83 35 81 00     # RD_A1 RS1_SP !8 LD                ; Restore a1
    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; Restore a2
    13 01 81 01     # RD_SP RS1_SP !24 ADDI             ; Deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    13 85 05 00     # rd_a0 rs1_a1 mv                   ; Return token
    83 30 01 00     # rd_ra rs1_sp ld                   ; Restore ra
    83 35 81 00     # rd_a1 rs1_sp !8 ld                ; Restore a1
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; Restore a2
    13 01 81 01     # rd_sp rs1_sp !24 addi             ; Deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# collect_comment function


@@ 314,51 314,51 @@ B2 03 00 00 00 00 00 00 ## p_memsz
# uses a0 as c
# Just throws away everything it reads
# :collect_comment ; (0x060025C)
    13 01 81 FF     # RD_SP RS1_SP !-8 ADDI             ; allocate stack
    23 30 11 00     # RS1_SP RS2_RA SD                  ; protect ra
    13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; allocate stack
    23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra

    EF 00 00 02     # RD_RA $fgetc JAL                  ; c = fgetc(input)
    EF 00 00 02     # rd_ra $fgetc jal                  ; c = fgetc(input)
                    # +32B
    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; if c == EOF
    63 04 55 10     # RS1_A0 RS2_T0 @Fail BEQ           ; Abort
    93 02 C0 FF     # rd_t0 !-4 addi                    ; if c == EOF
    63 04 55 10     # rs1_a0 rs2_t0 @Fail beq           ; Abort
                    # +264B

    93 02 A0 00     # RD_T0 !10 ADDI                    ; if c == '\n'
    E3 14 55 FE     # RS1_A0 RS2_T0 @collect_comment BNE ; loop
    93 02 A0 00     # rd_t0 !10 addi                    ; if c == '\n'
    E3 14 55 FE     # rs1_a0 rs2_t0 @collect_comment bne ; loop
                    # -24B

    83 30 01 00     # RD_RA RS1_SP LD                   ; restore ra
    13 01 81 00     # RD_SP RS1_SP !8 ADDI              ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# fgetc function
# Loads FILE* from s2
# Returns -4 (EOF) or char in a0
# :fgetc ; (0x0600284)
    13 01 81 FE     # RD_SP RS1_SP !-24 ADDI            ; allocate stack
    23 34 B1 00     # RS1_SP RS2_A1 @8 SD               ; protect a1
    23 38 C1 00     # RS1_SP RS2_A2 @16 SD              ; protect a2
    13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; allocate stack
    23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2

    93 08 F0 03     # RD_A7 !63 ADDI                    ; sys_read
    93 05 01 00     # RD_A1 RS1_SP MV                   ; Get stack address
    13 05 09 00     # RD_A0 RS1_S2 MV                   ; read from input file
    13 06 10 00     # RD_A2 !1 ADDI                     ; read 1 character
    73 00 00 00     # ECALL                             ; syscall
    93 08 F0 03     # rd_a7 !63 addi                    ; sys_read
    93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    13 05 09 00     # rd_a0 rs1_s2 mv                   ; read from input file
    13 06 10 00     # rd_a2 !1 addi                     ; read 1 character
    73 00 00 00     # ecall                             ; syscall

    63 16 05 00     # RS1_A0 @fgetc_done BNEZ           ; Check if nothing was read
    63 16 05 00     # rs1_a0 @fgetc_done bnez           ; Check if nothing was read
                    # +12B

# :fgetc_fail ; (0x06002A8)
    93 02 C0 FF     # RD_T0 !-4 ADDI                    ; Use -4 as EOF
    23 80 55 00     # RS1_A1 RS2_T0 SB                  ; Store EOF in *a1
    93 02 C0 FF     # rd_t0 !-4 addi                    ; Use -4 as EOF
    23 80 55 00     # rs1_a1 rs2_t0 sb                  ; Store EOF in *a1

# :fgetc_done ; (0x06002B0)
    03 85 05 00     # RD_A0 RS1_A1 LB                   ; return char in a0
    83 35 81 00     # RD_A1 RS1_SP !8 LD                ; restore a1
    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; restore a2
    13 01 81 01     # RD_SP RS1_SP !24 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    03 85 05 00     # rd_a0 rs1_a1 lb                   ; return char in a0
    83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; restore a2
    13 01 81 01     # rd_sp rs1_sp !24 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return


# Malloc isn't actually required if the program being built fits in the initial memory


@@ 366,83 366,83 @@ B2 03 00 00 00 00 00 00 ## p_memsz
# Requires MALLOC pointer to be initialized and a0 to have the number of desired bytes

# :malloc ; (0x06002C4)
    13 01 81 FF     # RD_SP RS1_SP !-8 ADDI             ; allocate stack
    23 30 B1 00     # RS1_SP RS2_A1 SD                  ; protect a1
    13 01 81 FF     # rd_sp rs1_sp !-8 addi             ; allocate stack
    23 30 B1 00     # rs1_sp rs2_a1 sd                  ; protect a1

    93 05 0B 00     # RD_A1 RS1_S6 MV                   ; Store the current pointer
    33 05 65 01     # RD_A0 RS1_A0 RS2_S6 ADD           ; Request the number of desired bytes
    93 08 60 0D     # RD_A7 !214 ADDI                   ; sys_brk
    73 00 00 00     # ECALL                             ; syscall
    13 0B 05 00     # RD_S6 RS1_A0 MV                   ; Set our malloc pointer
    13 85 05 00     # RD_A0 RS1_A1 MV                   ; Return the pointer
    93 05 0B 00     # rd_a1 rs1_s6 mv                   ; Store the current pointer
    33 05 65 01     # rd_a0 rs1_a0 rs2_s6 add           ; Request the number of desired bytes
    93 08 60 0D     # rd_a7 !214 addi                   ; sys_brk
    73 00 00 00     # ecall                             ; syscall
    13 0B 05 00     # rd_s6 rs1_a0 mv                   ; Set our malloc pointer
    13 85 05 00     # rd_a0 rs1_a1 mv                   ; Return the pointer

    83 35 01 00     # RD_A1 RS1_SP LD                   ; restore a1
    13 01 81 00     # RD_SP RS1_SP !8 ADDI              ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 35 01 00     # rd_a1 rs1_sp ld                   ; restore a1
    13 01 81 00     # rd_sp rs1_sp !8 addi              ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# File_Print function
# Receives CHAR* in a0
# calls fputc for every non-null char
# :File_Print ; (0x06002F0)
    13 01 81 FE     # RD_SP RS1_SP !-24 ADDI            ; allocate stack
    23 30 11 00     # RS1_SP RS2_RA SD                  ; protect ra
    23 34 B1 00     # RS1_SP RS2_A1 @8 SD               ; protect a1
    23 38 C1 00     # RS1_SP RS2_A2 @16 SD              ; protect a2
    93 05 05 00     # RD_A1 RS1_A0 MV                   ; protect a0
    13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; allocate stack
    23 30 11 00     # rs1_sp rs2_ra sd                  ; protect ra
    23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2
    93 05 05 00     # rd_a1 rs1_a0 mv                   ; protect a0

    63 0C 05 00     # RS1_A0 @File_Print_Done BEQZ      ; Protect against nulls
    63 0C 05 00     # rs1_a0 @File_Print_Done beqz      ; Protect against nulls
                    # +24B

# :File_Print_Loop ; (0x0600308)
    03 C5 05 00     # RD_A0 RS1_A1 LBU                  ; Read byte
    63 08 05 00     # RS1_A0 @File_Print_Done BEQZ      ; Stop at NULL
    03 C5 05 00     # rd_a0 rs1_a1 lbu                  ; Read byte
    63 08 05 00     # rs1_a0 @File_Print_Done beqz      ; Stop at NULL
                    # +16B

    EF 00 00 02     # RD_RA $fputc JAL                  ; print it
    EF 00 00 02     # rd_ra $fputc jal                  ; print it
                    # +32B
    93 85 15 00     # RD_A1 RS1_A1 !1 ADDI              ; S = S + 1
    6F F0 1F FF     # $File_Print_Loop JAL              ; Keep printing
    93 85 15 00     # rd_a1 rs1_a1 !1 addi              ; S = S + 1
    6F F0 1F FF     # $File_Print_Loop jal              ; Keep printing
                    # -16B

# :File_Print_Done ; (0x060031C)
    83 30 01 00     # RD_RA RS1_SP LD                   ; restore ra
    83 35 81 00     # RD_A1 RS1_SP !8 LD                ; restore a1
    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; restore a2
    13 01 81 01     # RD_SP RS1_SP !24 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    83 30 01 00     # rd_ra rs1_sp ld                   ; restore ra
    83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; restore a2
    13 01 81 01     # rd_sp rs1_sp !24 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# fputc function
# receives CHAR in a0 and load FILE* from stdout
# writes char and returns
# :fputc ; (0x0600330)
    13 01 81 FE     # RD_SP RS1_SP !-24 ADDI            ; allocate stack
    23 30 A1 00     # RS1_SP RS2_A0 SD                  ; protect a0
    23 34 B1 00     # RS1_SP RS2_A1 @8 SD               ; protect a1
    23 38 C1 00     # RS1_SP RS2_A2 @16 SD              ; protect a2

    93 08 00 04     # RD_A7 !64 ADDI                    ; sys_write
    13 05 10 00     # RD_A0 !1 ADDI                     ; write to stdout
    93 05 01 00     # RD_A1 RS1_SP MV                   ; Get stack address
    13 06 10 00     # RD_A2 !1 ADDI                     ; write 1 character
    73 00 00 00     # ECALL                             ; syscall

    03 35 01 00     # RD_A0 RS1_SP LD                   ; restore a0
    83 35 81 00     # RD_A1 RS1_SP !8 LD                ; restore a1
    03 36 01 01     # RD_A2 RS1_SP !16 LD               ; restore a2
    13 01 81 01     # RD_SP RS1_SP !24 ADDI             ; deallocate stack
    67 80 00 00     # RS1_RA JALR                       ; return
    13 01 81 FE     # rd_sp rs1_sp !-24 addi            ; allocate stack
    23 30 A1 00     # rs1_sp rs2_a0 sd                  ; protect a0
    23 34 B1 00     # rs1_sp rs2_a1 @8 sd               ; protect a1
    23 38 C1 00     # rs1_sp rs2_a2 @16 sd              ; protect a2

    93 08 00 04     # rd_a7 !64 addi                    ; sys_write
    13 05 10 00     # rd_a0 !1 addi                     ; write to stdout
    93 05 01 00     # rd_a1 rs1_sp mv                   ; Get stack address
    13 06 10 00     # rd_a2 !1 addi                     ; write 1 character
    73 00 00 00     # ecall                             ; syscall

    03 35 01 00     # rd_a0 rs1_sp ld                   ; restore a0
    83 35 81 00     # rd_a1 rs1_sp !8 ld                ; restore a1
    03 36 01 01     # rd_a2 rs1_sp !16 ld               ; restore a2
    13 01 81 01     # rd_sp rs1_sp !24 addi             ; deallocate stack
    67 80 00 00     # rs1_ra jalr                       ; return

# :Done ; (0x0600368)
    # Terminate program with 0 return code
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    13 05 00 00     # RD_A0 MV                          ; Return code 0
    73 00 00 00     # ECALL                             ; syscall
    93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    13 05 00 00     # rd_a0 mv                          ; Return code 0
    73 00 00 00     # ecall                             ; syscall

# :Fail ; (0x0600374)
    # Terminate program with 1 return code
    93 08 D0 05     # RD_A7 !93 ADDI                    ; sys_exit
    13 05 10 00     # RD_A0 !1 ADDI                     ; Return code 1
    73 00 00 00     # ECALL                             ; syscall
    93 08 D0 05     # rd_a7 !93 addi                    ; sys_exit
    13 05 10 00     # rd_a0 !1 addi                     ; Return code 1
    73 00 00 00     # ecall                             ; syscall
# PROGRAM END

# :default_file ; (0x0600380)