Sokoban in RISC-V

October 18, 2025

(Written with my lab partner, Yash Vora.)

# player character position
addi x12, x0, 12 # intentionally out of bounds
jal x0, rendersetup

level4:

# play dimensions
addi x7, x0, 7 # “height”
addi x25, x0, -7 # “height”
addi x8, x0, 81 # total volume (easier than width)
addi x24, x10, -35
addi x24, x24, 51
addi x9, x0, 1024
slli x9, x9, 1
sw x24, 384(x9)

# store the blocks in memory
sw x10, 3(x0)
sw x10, 4(x0)
sw x10, 5(x0)
sw x10, 6(x0)
sw x10, 8(x0)
sw x10, 9(x0)
sw x10, 10(x0)
sw x10, 13(x0)
sw x10, 14(x0)
sw x10, 15(x0)
sw x16, 17(x0)
sw x10, 20(x0)
sw x10, 21(x0)
sw x21, 23(x0)
sw x19, 24(x0)
sw x21, 25(x0)
sw x10, 27(x0)
sw x10, 28(x0)
sw x10, 34(x0)
sw x10, 35(x0)
sw x10, 36(x0)
sw x10, 37(x0)
sw x10, 40(x0)
sw x10, 41(x0)
sw x10, 44(x0)
sw x10, 45(x0)
sw x10, 46(x0)
sw x10, 47(x0)

# player character position
addi x12, x0, 12
jal x0, rendersetup

rendersetup:

# vga store location
addi x9, x0, 1024
slli x9, x9, 1
addi x5, x0, 0 # current mem loc
addi x6, x0, 640 # current vga render loc
addi x6, x6, 10 # current vga render loc
addi x14 x0, 0 # current row number

render:
beq x24, x0, nolvl
addi x26, x10, -35
addi x26, x26, 83
sw x26, 32(x9)
addi x26, x26, -83
addi x26, x26, 79
sw x26, 64(x9)
sw x26, 128(x9)
addi x26, x26, -79
addi x26, x26, 75
sw x26, 96(x9)
addi x26, x26, -75
addi x26, x26, 66
sw x26, 160(x9)
addi x26, x26, -66
addi x26, x26, 65
sw x26, 192(x9)
addi x26, x26, -65
addi x26, x26, 78
sw x26, 224(x9)
addi x9, x9, 256
addi x26, x26, -78
addi x26, x26, 45
sw x26, 0(x9)
addi x26, x26, -45
addi x26, x26, 76
sw x26, 32(x9)
sw x26, 96(x9)
addi x26, x26, -76
addi x26, x26, 86
sw x26, 64(x9)
addi x9, x9, -256

nolvl:
lw x3, 0(x5)
bne x5, x12, rendermem # if x5 = x12, store the current vga loc and render
player
add x13, x6, x0
add x4, x9, x6
sw x11, 0(x4)
beq x3, x21, player_on_box
bne x3, x19, updateloc
sw x20, 0(x4) # player on sprite
jal x0, updateloc

player_on_box:
sw x20, 0(x4) # player on sprite
jal x0, updateloc

rendermem:
add x4, x9, x6
sw x3, 0(x4)

updateloc:
addi x5, x5, 1
addi x6, x6, 1
addi x14, x14, 1
beq x5, x8, mainloop # if x5 = x8, done
bne x14, x7, render # if x14 = x7, skip the rest of the column
addi x6, x6, 32
sub x6, x6, x7
sub x14, x14, x7
jal x0, render

mainloop:

# Bitflag handling for RLUD
addi x18, x0, 1
beq x18 x31 start
and x18, x17, x18
jal x0, wincheck

nvm:
bne x18, x0, rightskip # skip if right pressed
beq x27, x0, right

leftcheck:
addi x18, x0, 2
and x18, x17, x18
bne x18, x0, leftskip # skip if left pressed
beq x28, x0, left

upcheck:
addi x18, x0, 4
and x18, x17, x18
bne x18, x0, upskip # skip if up pressed
beq x29, x0, up

downcheck:
addi x18, x0, 8
and x18, x17, x18
bne x18, x0, downskip # skip if down pressed
beq x30, x0, down

# DO NOT PUT ANY CODE HERE, IT WILL NOT ALWAYS RUN; put it at start of mainloop
beq x0, x0, mainloop

rightskip:
bne x27, x0, rightreset
jal x0, leftcheck

rightreset:
addi x17, x17, -1
jal x0, leftcheck

leftskip:
bne x28, x0, leftreset
jal x0, upcheck

leftreset:
addi x17, x17, -2
jal x0, upcheck

upskip:
bne x29, x0, upreset
jal x0, downcheck

upreset:
addi x17, x17, -4
jal x0, downcheck

downskip:
bne x30, x0, downreset
jal x0, mainloop

downreset:
addi x17, x17, -8
jal x0, mainloop

right:
addi x17, x17, 1 # update bitflag
add x23, x12, x7
lw x15, 0(x23)
beq x15, x10 mainloop
beq x15, x16 boxmoveright
beq x15, x21 boxoffplateright

# if no box, then easy
add x12, x12, x7
addi x13, x13, 32
jal x0, rendersetup

boxmoveright:
add x23, x23, x7
lw x15, 0(x23)
beq x15, x10 mainloop # stop if wall
beq x15, x16 mainloop # stop if another box
beq x15, x21 mainloop # stop if another box-on-plate
add x12, x12, x7
addi x13, x13, 32
beq x15, x19 boxonplateright
sw x0, 0(x12)
sw x16, 0(x23)
jal x0, rendersetup

boxonplateright:
sw x0, 0(x12)
add x23, x12, x7
sw x21, 0(x23)
jal x0, rendersetup

boxoffplateright:
add x23, x23, x7
lw x15, 0(x23)
beq x15, x10 mainloop # stop if wall
beq x15, x16 mainloop # stop if another box
beq x15, x21 mainloop # stop if another box-on-plate
add x12, x12, x7
sw x19, 0(x12)
sw x16, 0(x23)
jal x0, rendersetup

left:
addi x17, x17, 2 # update bitflag
add x23, x12, x25
lw x15, 0(x23)
add x0, x0, x0
beq x15 x10 mainloop
beq x15, x16 boxmoveleft
beq x15, x21 boxoffplateleft
add x12, x12, x25
addi x13, x13, -32
jal x0, rendersetup

boxmoveleft:
add x23, x23, x25
lw x15, 0(x23)
beq x15 x10 mainloop
beq x15 x16 mainloop
beq x15, x21 mainloop # stop if another box-on-plate
add x12, x12, x25
beq x15, x19 boxonplateleft
sw x0, 0(x12)
add x23, x12, x25
sw x16, 0(x23)
jal x0, rendersetup

boxonplateleft:
sw x0, 0(x12)
add x23, x12, x25
sw x21, 0(x23)
jal x0, rendersetup

boxoffplateleft:
add x23, x23, x25
lw x15, 0(x23)
beq x15, x10 mainloop # stop if wall
beq x15, x16 mainloop # stop if another box
beq x15, x21 mainloop # stop if another box-on-plate
add x12, x12, x25
sw x19, 0(x12)
add x23, x12, x25
sw x16, 0(x23)
jal x0, rendersetup

up:
addi x17, x17, 4 # update bitflag
lw x15, -1(x12)
beq x15 x10 mainloop
beq x15, x16 boxmoveup
beq x15, x21 boxoffplateup
addi x12, x12, -1
addi x13, x13, -1
jal x0, rendersetup

boxmoveup:
lw x15 -2(x12)
beq x15 x10 mainloop
beq x15 x16 mainloop
beq x15, x21 mainloop # stop if another box-on-plate
addi x12, x12, -1
addi x13, x13, -1
beq x15, x19 boxonplateup
sw x0, 0(x12)
sw x16, -1(x12)
jal x0, rendersetup

boxonplateup:
sw x0, 0(x12)
sw x21, -1(x12)
jal x0, rendersetup

boxoffplateup:
lw x15, -2(x12)
beq x15, x10 mainloop # stop if wall
beq x15, x16 mainloop # stop if another box
beq x15, x21 mainloop # stop if another box-on-plate
addi x12, x12, -1
sw x19, 0(x12)
beq x15, x19, boxonplateplateup
sw x16, -1(x12)
jal x0, rendersetup

boxonplateplateup:
sw x21, -1(x12)
jal x0, rendersetup

down:
addi x17, x17, 8 # update bitflag
lw x15, 1(x12)
beq x15 x10 mainloop
beq x15, x16 boxmovedown
beq x15, x21 boxoffplatedown
addi x12, x12, 1
addi x13, x13, 1
jal x0, rendersetup

boxmovedown:
lw x15 2(x12)
beq x15 x10 mainloop
beq x15 x16 mainloop
beq x15, x21 mainloop # stop if another box-on-plate
addi x12, x12, 1
addi x13, x13, 1
beq x15, x19 boxonplatedown
sw x0, 0(x12)
sw x16, 1(x12)
jal x0, rendersetup

boxonplatedown:
sw x0, 0(x12)
sw x21, 1(x12)
jal x0, rendersetup

boxoffplatedown:
lw x15, 2(x12)
beq x15, x10 mainloop # stop if wall
beq x15, x16 mainloop # stop if another box
beq x15, x21 mainloop # stop if another box-on-plate
addi x12, x12, 1
sw x19, 0(x12)
beq x15, x19, boxonplateplatedown
sw x16, 1(x12)
jal x0, rendersetup

boxonplateplatedown:
sw x21, 1(x12)
jal x0, rendersetup

wincheck:
addi x24, x0, 0
beq x22, x24, wincheck1
addi x24, x0, 1
beq x22, x24, wincheck2
addi x24, x0, 2
beq x22, x24, wincheck3
addi x24, x0, 3
beq x22, x24, wincheck4

wincheck1:
lw x15 9(x0)
bne x15 x21 nvm
lw x15 26(x0)
bne x15 x21 nvm
addi x22, x22, 1
jal x0, start

wincheck2:
lw x15, 11(x0)
bne x15, x21, nvm
lw x15 48(x0)
bne x15 x21 nvm
lw x15 13(x0)
bne x15 x21 nvm
lw x15 41(x0)
bne x15 x21 nvm
lw x15 43(x0)
bne x15 x21 nvm
lw x15 60(x0)
bne x15 x21 nvm
lw x15 33(x0)
bne x15 x21 nvm
addi x22, x22, 1
jal x0, start

wincheck4:
lw x15 23(x0)
bne x15 x21 nvm
lw x15 24(x0)
bne x15 x21 nvm
lw x15 25(x0)
bne x15 x21 nvm
addi x22, x22, 1
jal x0, start

wincheck3:
bne x31, x0, hard
jal x0, wincheck3

hard:
addi x22, x22, 1
jal x0, start

done: