New paste Repaste Download
## Copyright (C) 2026 Christian Westrom
## 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/>.
# hex0 - A minimal hex loader for RISC-V (bare metal, QEMU virt)
# Reads hex digits from UART, converts pairs to bytes, stores in memory.
# On Ctrl-D, jumps to the loaded code.
; Register use:
; s0: holder (first nibble)
; s1: toggle (1 = first nibble, 0 = second nibble)
; s2: pointer to code buffer
# _start:
# Setup stack pointer
17 31 00 00       # auipc sp, 0x3
13 01 01 18       # addi sp, sp, 384
# Setup code buffer pointer
17 19 00 00       # auipc s2, 0x1
13 09 89 17       # addi s2, s2, 376
# Initialize toggle and holder
93 04 10 00       # addi s1, x0, 1
13 04 00 00       # addi s0, x0, 0
# loop:
EF 00 80 04       # jal ra, read_char
# Check for Ctrl-D
93 02 40 00       # addi t0, x0, 4
63 16 55 00       # bne a0, t0, process_input
EF 00 00 0E       # jal ra, execute_code
6F F0 1F FF       # jal x0, loop
# process_input:
EF 00 40 05       # jal ra, hex
E3 44 05 FE       # blt a0, x0, loop
63 88 04 00       # beq s1, x0, process_second_nibble
# Process first nibble
13 74 F5 00       # andi s0, a0, 0xF
93 04 00 00       # addi s1, x0, 0
6F F0 9F FD       # jal x0, loop
# process_second_nibble:
13 14 44 00       # slli s0, s0, 4
13 75 F5 00       # andi a0, a0, 0xF
33 05 A4 00       # add a0, s0, a0
93 04 10 00       # addi s1, x0, 1
# Write out byte
23 00 A9 00       # sb a0, 0(s2)
# Update our pointer
13 09 19 00       # addi s2, s2, 1
6F F0 DF FB       # jal x0, loop
# read_char:
B7 02 00 10       # lui t0, 0x10000
9B 82 52 00       # addiw t0, t0, 5
# poll_rx:
03 85 02 00       # lb a0, 0(t0)
13 75 15 00       # andi a0, a0, 1
E3 0C 05 FE       # beq a0, x0, poll_rx
B7 02 00 10       # lui t0, 0x10000
03 85 02 00       # lb a0, 0(t0)
67 80 00 00       # jalr x0, ra, 0
# hex:
# Deal with line comments starting with #
93 02 30 02       # addi t0, x0, 0x23
63 00 55 06       # beq a0, t0, ascii_comment
# Deal with line comments starting with ;
93 02 B0 03       # addi t0, x0, 0x3B
63 0C 55 04       # beq a0, t0, ascii_comment
# Deal with all ASCII less than '0'
93 02 00 03       # addi t0, x0, 0x30
63 44 55 04       # blt a0, t0, ascii_other
# Deal with '0' through '9'
93 02 A0 03       # addi t0, x0, 0x3A
63 44 55 02       # blt a0, t0, ascii_num
# Deal with all ASCII less than 'A'
93 02 10 04       # addi t0, x0, 0x41
63 4C 55 02       # blt a0, t0, ascii_other
# Deal with 'A' through 'F'
93 02 70 04       # addi t0, x0, 0x47
63 44 55 02       # blt a0, t0, ascii_high
# Deal with all ASCII less than 'a'
93 02 10 06       # addi t0, x0, 0x61
63 44 55 02       # blt a0, t0, ascii_other
# Deal with 'a' through 'f'
93 02 70 06       # addi t0, x0, 0x67
63 48 55 00       # blt a0, t0, ascii_low
# Deal with everything else
6F 00 C0 01       # jal x0, ascii_other
# ascii_num:
13 05 05 FD       # addi a0, a0, -48
67 80 00 00       # jalr x0, ra, 0
# ascii_low:
13 05 95 FA       # addi a0, a0, -87
67 80 00 00       # jalr x0, ra, 0
# ascii_high:
13 05 95 FC       # addi a0, a0, -55
67 80 00 00       # jalr x0, ra, 0
# ascii_other:
13 05 F0 FF       # addi a0, x0, -1
67 80 00 00       # jalr x0, ra, 0
# ascii_comment:
13 01 01 FF       # addi sp, sp, -16
23 30 11 00       # sd ra, 0(sp)
EF F0 5F F7       # jal ra, read_char
93 02 D0 00       # addi t0, x0, 0xD
E3 18 55 FE       # bne a0, t0, ascii_comment
83 30 01 00       # ld ra, 0(sp)
13 01 01 01       # addi sp, sp, 16
6F F0 DF FD       # jal x0, ascii_other
# execute_code:
# Zero all registers before jump
13 05 00 00       # addi a0, x0, 0
93 05 00 00       # addi a1, x0, 0
13 06 00 00       # addi a2, x0, 0
93 06 00 00       # addi a3, x0, 0
13 07 00 00       # addi a4, x0, 0
93 07 00 00       # addi a5, x0, 0
13 08 00 00       # addi a6, x0, 0
93 08 00 00       # addi a7, x0, 0
93 02 00 00       # addi t0, x0, 0
13 03 00 00       # addi t1, x0, 0
93 03 00 00       # addi t2, x0, 0
13 0E 00 00       # addi t3, x0, 0
93 0E 00 00       # addi t4, x0, 0
13 0F 00 00       # addi t5, x0, 0
93 0F 00 00       # addi t6, x0, 0
13 04 00 00       # addi s0, x0, 0
93 04 00 00       # addi s1, x0, 0
93 09 00 00       # addi s3, x0, 0
13 0A 00 00       # addi s4, x0, 0
93 0A 00 00       # addi s5, x0, 0
13 0B 00 00       # addi s6, x0, 0
93 0B 00 00       # addi s7, x0, 0
13 0C 00 00       # addi s8, x0, 0
93 0C 00 00       # addi s9, x0, 0
13 0D 00 00       # addi s10, x0, 0
93 0D 00 00       # addi s11, x0, 0
# Load the code that we input by hand
97 12 00 00       # auipc t0, 0x1
93 82 42 01       # addi t0, t0, 20
67 80 02 00       # jalr x0, t0, 0
# done:
6F 00 00 00       # jal x0, done
Filename: hex0_riscv64.hex0. Size: 5kb. View raw, , hex, or download this file.

This paste expires on 2026-03-05 08:57:00.407119+00:00. Pasted through web.