Skip to content

Commit 4cc6ea5

Browse files
timsherwoodclaude
andcommitted
Add three educational RISC-V assembly programs
Programs for teaching undergraduate assembly programming: 1. hello_asm (Tutorial Level) - First program for beginners with zero assembly experience - Heavily commented walkthrough of program structure - Teaches: la, li, add, ecall, syscalls 1/4/10/11 2. array_stats (Moderate Complexity) - Loop through array to compute sum, min, max - Teaches: lw/sw, loops, branches, memory access - Demonstrates function calls with jal/ret 3. guess_game (Interactive I/O) - Number guessing game with user input - Teaches: read_int syscall, game loops, conditionals - Makes assembly feel like "real" programming Each program includes: - Extensive inline comments - Summary of instructions used - Suggested exercises for students 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 282344b commit 4cc6ea5

9 files changed

Lines changed: 623 additions & 0 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Makefile for array_stats
2+
# Builds a bare-metal RISC-V executable for use with MapacheSPIM
3+
4+
# Cross-compiler prefix (adjust if your toolchain is different)
5+
CROSS = riscv64-unknown-elf-
6+
7+
AS = $(CROSS)as
8+
LD = $(CROSS)ld
9+
10+
# Target name
11+
TARGET = array_stats
12+
13+
# Default target
14+
all: $(TARGET)
15+
16+
$(TARGET): $(TARGET).o
17+
$(LD) -T ../linker.ld -o $@ $<
18+
19+
$(TARGET).o: $(TARGET).s
20+
$(AS) -march=rv64i -mabi=lp64 -o $@ $<
21+
22+
clean:
23+
rm -f $(TARGET) $(TARGET).o
24+
25+
.PHONY: all clean
5.8 KB
Binary file not shown.
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# ============================================================================
2+
# array_stats.s - Array Processing with Loops
3+
# ============================================================================
4+
#
5+
# This program demonstrates:
6+
# 1. Defining arrays in the .data section
7+
# 2. Looping through array elements
8+
# 3. Memory access with lw (load word)
9+
# 4. Tracking multiple values (sum, min, max)
10+
# 5. Conditional branches (blt, bgt, beq)
11+
#
12+
# ============================================================================
13+
14+
.data
15+
16+
# Our array of 8 integers
17+
array: .word 23, 7, 42, 15, 8, 31, 4, 19
18+
array_len: .word 8 # Number of elements
19+
20+
# Output messages
21+
msg_array: .asciz "Array: "
22+
msg_sum: .asciz "Sum: "
23+
msg_min: .asciz "Min: "
24+
msg_max: .asciz "Max: "
25+
msg_count: .asciz "Count: "
26+
space: .asciz " "
27+
newline: .asciz "\n"
28+
29+
.text
30+
.globl _start
31+
32+
# ============================================================================
33+
# _start: Program Entry Point
34+
# ============================================================================
35+
_start:
36+
# First, print the array contents
37+
jal ra, print_array
38+
39+
# Calculate and print statistics
40+
jal ra, calc_stats
41+
42+
# Exit program
43+
li a7, 10
44+
ecall
45+
46+
# ============================================================================
47+
# print_array: Print all elements of the array
48+
# ============================================================================
49+
print_array:
50+
# Save return address (we'll call print functions)
51+
addi sp, sp, -16
52+
sd ra, 0(sp)
53+
sd s0, 8(sp)
54+
55+
# Print "Array: "
56+
la a0, msg_array
57+
li a7, 4
58+
ecall
59+
60+
# Set up loop variables
61+
la s0, array # s0 = pointer to current element
62+
la t0, array_len
63+
lw t1, 0(t0) # t1 = array length (counter)
64+
65+
print_loop:
66+
beqz t1, print_done # If counter == 0, we're done
67+
68+
# Load and print current element
69+
lw a0, 0(s0) # Load word from memory at address s0
70+
li a7, 1 # print_int syscall
71+
ecall
72+
73+
# Print space separator
74+
la a0, space
75+
li a7, 4
76+
ecall
77+
78+
# Move to next element
79+
addi s0, s0, 4 # Move pointer forward by 4 bytes (size of word)
80+
addi t1, t1, -1 # Decrement counter
81+
82+
j print_loop # Continue loop
83+
84+
print_done:
85+
# Print newline
86+
la a0, newline
87+
li a7, 4
88+
ecall
89+
90+
# Restore and return
91+
ld ra, 0(sp)
92+
ld s0, 8(sp)
93+
addi sp, sp, 16
94+
ret
95+
96+
# ============================================================================
97+
# calc_stats: Calculate sum, min, max and print results
98+
# ============================================================================
99+
calc_stats:
100+
# Save return address
101+
addi sp, sp, -8
102+
sd ra, 0(sp)
103+
104+
# Initialize variables
105+
# t2 = sum (starts at 0)
106+
# t3 = min (starts at first element)
107+
# t4 = max (starts at first element)
108+
109+
la t0, array
110+
lw t3, 0(t0) # min = array[0]
111+
lw t4, 0(t0) # max = array[0]
112+
li t2, 0 # sum = 0
113+
114+
# Set up loop
115+
la t0, array # t0 = pointer to current element
116+
la t5, array_len
117+
lw t1, 0(t5) # t1 = array length (counter)
118+
119+
stats_loop:
120+
beqz t1, stats_done # If counter == 0, we're done
121+
122+
# Load current element
123+
lw t5, 0(t0) # t5 = current element
124+
125+
# Add to sum
126+
add t2, t2, t5 # sum += current
127+
128+
# Check if current < min
129+
bge t5, t3, check_max # if current >= min, skip to max check
130+
mv t3, t5 # min = current
131+
132+
check_max:
133+
# Check if current > max
134+
ble t5, t4, next_elem # if current <= max, skip
135+
mv t4, t5 # max = current
136+
137+
next_elem:
138+
# Move to next element
139+
addi t0, t0, 4 # pointer += 4
140+
addi t1, t1, -1 # counter--
141+
j stats_loop
142+
143+
stats_done:
144+
# Now print all the statistics
145+
# t2 = sum, t3 = min, t4 = max
146+
147+
# Save our computed values (syscalls may clobber t registers)
148+
mv s1, t2 # s1 = sum
149+
mv s2, t3 # s2 = min
150+
mv s3, t4 # s3 = max
151+
152+
# Print Sum
153+
la a0, msg_sum
154+
li a7, 4
155+
ecall
156+
mv a0, s1
157+
li a7, 1
158+
ecall
159+
la a0, newline
160+
li a7, 4
161+
ecall
162+
163+
# Print Min
164+
la a0, msg_min
165+
li a7, 4
166+
ecall
167+
mv a0, s2
168+
li a7, 1
169+
ecall
170+
la a0, newline
171+
li a7, 4
172+
ecall
173+
174+
# Print Max
175+
la a0, msg_max
176+
li a7, 4
177+
ecall
178+
mv a0, s3
179+
li a7, 1
180+
ecall
181+
la a0, newline
182+
li a7, 4
183+
ecall
184+
185+
# Print Count
186+
la a0, msg_count
187+
li a7, 4
188+
ecall
189+
la t0, array_len
190+
lw a0, 0(t0)
191+
li a7, 1
192+
ecall
193+
la a0, newline
194+
li a7, 4
195+
ecall
196+
197+
# Restore and return
198+
ld ra, 0(sp)
199+
addi sp, sp, 8
200+
ret
201+
202+
# ============================================================================
203+
# SUMMARY OF NEW INSTRUCTIONS
204+
# ============================================================================
205+
#
206+
# lw rd, offset(rs) - Load Word: rd = memory[rs + offset]
207+
# sw rs, offset(rd) - Store Word: memory[rd + offset] = rs
208+
# sd rs, offset(rd) - Store Doubleword (64-bit)
209+
# ld rd, offset(rs) - Load Doubleword (64-bit)
210+
# beqz rs, label - Branch if Equal to Zero
211+
# bge rs1, rs2, label - Branch if Greater or Equal
212+
# ble rs1, rs2, label - Branch if Less or Equal
213+
# blt rs1, rs2, label - Branch if Less Than
214+
# mv rd, rs - Move (copy register)
215+
# j label - Jump unconditionally
216+
# jal rd, label - Jump and Link (function call)
217+
# ret - Return from function (alias for jalr x0, ra, 0)
218+
#
219+
# ============================================================================
220+
# EXERCISES FOR STUDENTS
221+
# ============================================================================
222+
#
223+
# 1. Add calculation of the average (sum / count)
224+
# 2. Modify the array values and verify the output changes correctly
225+
# 3. Add a function to find the index of the maximum element
226+
# 4. Print the array in reverse order
227+
#
228+
# ============================================================================

examples/riscv/guess_game/Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Makefile for guess_game
2+
# Builds a bare-metal RISC-V executable for use with MapacheSPIM
3+
4+
# Cross-compiler prefix (adjust if your toolchain is different)
5+
CROSS = riscv64-unknown-elf-
6+
7+
AS = $(CROSS)as
8+
LD = $(CROSS)ld
9+
10+
# Target name
11+
TARGET = guess_game
12+
13+
# Default target
14+
all: $(TARGET)
15+
16+
$(TARGET): $(TARGET).o
17+
$(LD) -T ../linker.ld -o $@ $<
18+
19+
$(TARGET).o: $(TARGET).s
20+
$(AS) -march=rv64i -mabi=lp64 -o $@ $<
21+
22+
clean:
23+
rm -f $(TARGET) $(TARGET).o
24+
25+
.PHONY: all clean
26+
5.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)