Skip to content

Instantly share code, notes, and snippets.

@hmil
Last active December 28, 2015 00:59
Show Gist options
  • Save hmil/7417561 to your computer and use it in GitHub Desktop.
Save hmil/7417561 to your computer and use it in GitHub Desktop.
A space invaders-like mips game for FPGA4U.
# === FPGA INVADERS ===
#
#
# VHDL symbols have invaded the FPGA, destroy them all to free your board
# from unpredictable behaviour, mind-fucking bugs and shitty simulations !
#
#
# == Controls ==
#
# +---------+
# | oooo| <- lives remaining
# | |
# | ooo ooo|
# | o o |
# | |
# | o |
# | o |
# | ooo |
# +---------+
# O O O O <-- move right
# ^ | |
# | +-+---- fire
# |
# move left
#
#
# == Ennemies ==
#
# Process:
# oo
# oo
#
# Undefined:
# o o
# o o
# ooo
#
# Signal:
# o
# o
#
# Latch:
# o
# o
# oo
#
#
# == License ==
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# - Substantial portions of this code shall NOT BE USED IN ANY ARCHORD ASSIGNMENT !
#
# -- > Contributions are welcome < --
#
#
# [memo]
# Our mips doesn't have these :
# push :
# addi sp, sp, -4 # Decrement stack pointer by 4
# sw t0, 0x0000(sp) # save t0 to the stack
# pop :
# lw t0, 0x0000(sp) # Copy from stack to $t0
# addi sp, sp, 4 # Increment stack pointer by 4
br text # jumps to text section (actual code)
# Non-code data
spaceship: .word 0x00000207
# @
# @@
# @
aliens:
.word 0x00000202 # signal = aliens(0)
#
# @@
.word 0x00000303 # process = aliens(4)
# @@
# @@
.word 0x00050507 # undefined = aliens(8)
# @@@
# @
# @@@
.word 0x00020206 # latch = aliens(0xc)
#
# @@@
# @
win_screen:
.word 0xf # length
.word 0x0
.word 0x04380402
.word 0x223e0002
.word 0x003e2222
.word 0x2020203e
.word 0x0000003e
.word 0x1020100e
.word 0x000e1020
.word 0x2222223e
.word 0x043e003e
.word 0x003e1008
.word 0x002e0000
.word 0x0
.word 0x0
.word 0x0
#2|@ |@ @@|@@@ |@ |@ |@ | @ |@@@@|@ @ | @ | @|
#4| @ @| @ | @ |@ |@ |@ | @ |@ |@ @@| @ | @|
#8| @ | @ | @ |@ |@ |@ | @ |@ |@ @ |@ @ | @|
#-+----+----+----+----+----+----+----+----+----+----+---+
#1| @ | @ | @ |@ |@ | @ @| @ |@ |@ @ | @@ | |
#2| @ | @@|@@@ |@@@@|@ | @ |@ |@@@@|@ @ | @ | @|
game_over_screen:
.word 0x10
.word 0x0
.word 0x223e0000
.word 0x3e003a2a
.word 0x003e0a0a
.word 0x0408043e
.word 0x2a3e003e
.word 0x00002a2a
.word 0x223e0000
.word 0x003e2222
.word 0x1020100e
.word 0x2a3e000e
.word 0x3e002a2a
.word 0x002e1a0a
.word 0x0
.word 0x0
.word 0x0
#2| @@|@@ @|@@@ |@ |@ @@|@@ | @@|@@@ |@ |@ @@|@@ @|@@@
#4| @ | @| @ |@@ @|@ @ | | @ | @ |@ |@ @ | @| @
#8| @ |@@ @|@@@ |@ @ |@ @@|@@ | @ | @ |@ |@ @@|@@ @|@@@
#-+---+----+----+----+----+----+----+----+----+----+----+----
#1| @ | @ @| @ |@ |@ @ | | @ | @ | @ @| @ | @| @
#2| @@|@@ @| @ |@ |@ @@|@@ | @@|@@@ | @ | @@|@@ @| @
# stages definition : A stage is a set of aliens
# Word n: number of aliens
# n*Word: aliens (sprite offset: 16, posY: 8, posX: 8)
stages:
# one signal in the middle
.word 0x1
.word 0x00000408
# two signals
.word 0x2
.word 0x00000208
.word 0x00000608
# one signal one process
.word 0x2
.word 0x00000207
.word 0x00040508
# 3 signals
.word 0x3
.word 0x00040105
.word 0x00040505
.word 0x00040408
# two signals one process
.word 0x3
.word 0x00000005
.word 0x00000505
.word 0x00040308
# One latch one signal above
.word 0x2
.word 0x00000208
.word 0x000c0204
# One latch two signals
.word 0x3
.word 0x000c0307
.word 0x00000204
.word 0x00000304
# One undefined
.word 0x1
.word 0x00080306
# 6 signals
.word 0x6
.word 0x00000007
.word 0x00000207
.word 0x00000407
.word 0x00000104
.word 0x00000304
.word 0x00000504
# undefined with latches
.word 0x03
.word 0x00080307
.word 0x000c0004
.word 0x000c0504
# escorted undefined
.word 0x05
.word 0x00080307
.word 0x00000009
.word 0x00000609
.word 0x00000005
.word 0x00000605
.word 0x0 # end of stages declaration
fire_delay: .word 0x03
# Registers:
#
# s0 : ship pos [0 - 5]
# s1 : fire delay (zero => can fire)
# s3 : lives
# Memory:
#
# 0x1000 - 0x1014 : player_bullets[6] = (16xMSB: y, 16xLSB: x): Word ; -1 is empty
s_bullet: .word 0x18 # bullets array size
#
# 0x1020 - 0x103C : aliens[8] = Word(sprite_offset: 16bits, y: 8bits, x: 8bits)
s_aliens: .word 0x20 # aliens array size
#
# 0x1040 - 0x107c : alien_bullets[16] = (16xMSB: y, 16xLSB: x): Word ; -1 is empty
s_alienBullet: .word 0x40 # alien bullet array size
#
# 0x1100: current stage offset
# 0x1200 - 0x1208: random number generator
# 0x1300+: graphic ram
text: # Code
addi sp, zero, 0x2000 # initializes stack
addi s0, zero, 2 # initial position: 2
addi s1, zero, 0 # fire-delay: 0
stw zero, 0x1100(zero)
addi s3, zero, 5 # 5 lives
addi a0, zero, 0x1324
addi a1, zero, 0x3754
call init_random
# --- Initialization ---
call load_stage
# bullets
ldw t0, s_bullet(zero) # loads bullets array size
addi t1, zero, -0x1 # prepares value 1 as default
init_bullets:
addi t0, t0, -0x4 # updates loop counter
stw t1, 0x1000(t0) # sets default value in ram
bne t0, zero, init_bullets # loops until all bullets traversed
ldw t0, s_alienBullet(zero)
init_alien_bullets:
addi t0, t0, -0x4 # updates loop counter
stw t1, 0x1040(t0) # sets default value in ram
bne t0, zero, init_alien_bullets # loops until all bullets traversed
loop:
# addi s3, zero, 3 # GOD MODE
# --- INPUT ---
ldw t0, 0x2030(zero) # loads buttons state
# Fire
bne s1, zero, movement # skips if cannot fire
andi t1, t0, 0x6 # filters two middle buttons
addi t2, zero, 0x6
beq t1, t2, movement # if one is pushed pushed
addi sp, sp, -4 # push t0
stw t0, 0x0000(sp)
call fire # fires
ldw t0, 0x0000(sp) # pop t0
addi sp, sp, 4
movement:
# Movement
andi t1, t0, 0x8 # filters fourth button
bne t1, zero, 0x8 # if pushed
addi s0, s0, -0x1 # moves up
call random # and randomizes
andi t1, t0, 0x1 # filters first button
bne t1, zero, 0x4 # if pushed
addi s0, s0, 0x1 # moves down
# --- Physics ---
physics:
# Ship's position
addi t0, zero, -1 # prepares constant -1
bge s0, t0, 0x4 # if ship is below -1
add s0, zero, t0 # set to -1
addi t0, zero, 0x7
blt s0, t0, 0x4 # if ship is >= 0x7
addi s0, zero, 0x6 # set to 6
# Bullets position
ldw t0, s_bullet(zero) # loads bullets array size
addi t1, zero, 0xc # max bullet altitude
phys_bullets:
addi t0, t0, -0x4 # updates loop counter
ldw t2, 0x1000(t0) # loads bullet value
blt t2, zero, phys_bullets_test # if bullet < 0, continue;
addi t2, t2, 0x1 # moves bullet forward
andi t3, t2, 0xffff # masks LSB (x coord)
blt t3, t1, 0x4 # if bullet is too high
addi t2, zero, -0x1 # reset bullet pos
stw t2, 0x1000(t0) # stores new value
phys_bullets_test: bne t0, zero, phys_bullets # loops until all bullets traversed
# computes player collision map
add a0, zero, zero
add a1, zero, s0
ldw a2, spaceship(zero)
call sprite_to_screen
ldw t6, 0x0000(sp) # pop t6 (offset)
addi sp, sp, 4
add t4, v0, zero # saves v0 in t4
# Alien bullets position
ldw t0, s_alienBullet(zero) # loads bullets array size
alien_bullets:
addi t0, t0, -0x4 # updates loop counter
ldw t2, 0x1040(t0) # loads bullet value
blt t2, zero, alien_bullets_test # if bullet < 0, continue;
andi t3, t2, 0xffff # masks LSB (x coord)
blt zero, t3, 0x4 # if bullet is too low
addi t2, zero, 0 # reset bullet pos
addi t2, t2, -0x1 # moves bullet backwards
stw t2, 0x1040(t0) # stores new value
andi a0, t2, 0xffff # puts x coord in a0
srli a1, t2, 0x10 # puts y coord in a1
andi a1, a1, 0xffff # cleans y coord
addi sp, sp, -4
stw t0, 0x0000(sp) # push t0
call xy_to_display
ldw t0, 0x0000(sp) # pop t0
addi sp, sp, 4
blt t6, v0, alien_bullets_test # if bullet word is after player's, continue
and t2, v1, t4 # masks bullet and sprite
beq t2, zero, alien_bullets_test # if collision
addi s3, s3, -1 # sub life
blt zero, s3, 0x4 # if no life
call game_over
alien_bullets_test: bne t0, zero, alien_bullets # loops until all bullets traversed
# Alien collision
ldw t1, s_aliens(zero) # loads alien array size
alien_collis_i: # outer loop
addi t1, t1, -0x4
ldw t3, 0x1020(t1) # loads alien
blt t3, zero, alien_collis_i_end # if alien is null, continue
srli t2, t3, 0x10 # gets sprite offset
ldw a2, aliens(t2) # loads sprite
andi a0, t3, 0xff # puts x coord in a0
srli t2, t3, 0x8 # puts y coord in a1
andi a1, t2, 0xff # and cleans it
#random to know if alien should fire
addi sp, sp, -4
stw t1, 0x0000(sp) # push t1
call random
andi v0, v0, 0x1111
bne v0, zero, 0x4 # if it should
call alien_fire
call sprite_to_screen
ldw t3, 0x0000(sp) # pop t3 (offset)
addi sp, sp, 4
ldw t1, 0x0000(sp) # pop t1
addi sp, sp, 4
add t4, v0, zero # saves v0 in t4
add t5, v1, zero # saves v1 in t5
# offset is in t3, first word in t4, second in t5
ldw t0, s_bullet(zero) # loads bullet array size
alien_collis: # inner loop
addi t0, t0, -0x4
ldw t2, 0x1000(t0) # loads bullet
blt t2, zero, alien_collis_end # if bullet is null, continue
andi a0, t2, 0xffff # puts x coord in a0
srli a1, t2, 0x10 # puts y coord in a1
andi a1, a1, 0xffff # cleans y coord
addi sp, sp, -4
stw t0, 0x0000(sp) # push t0
addi sp, sp, -4
stw t1, 0x0000(sp) # push t1
addi sp, sp, -4
stw t3, 0x0000(sp) # push t3
addi sp, sp, -4
stw t4, 0x0000(sp) # push t4
addi sp, sp, -4
stw t5, 0x0000(sp) # push t5
call xy_to_display
ldw t5, 0x0000(sp) # pop t5
addi sp, sp, 4
ldw t4, 0x0000(sp) # pop t4
addi sp, sp, 4
ldw t3, 0x0000(sp) # pop t3
addi sp, sp, 4
ldw t1, 0x0000(sp) # pop t1
addi sp, sp, 4
ldw t0, 0x0000(sp) # pop t0
addi sp, sp, 4
# v0 is now bullet's screen word, v1 is bullet mask as a word
blt v0, t3, alien_collis_end # if bullet word is below alien's, continue
sub t2, t3, v0 # computes bullet pos relative to sprite
bne t2, zero, 0x8 # if bullet is srite[0]
and t2, v1, t4 # masks bullet and sprite
br 0xc
addi t6, zero, 0x4
bne t2, t6, alien_collis_end # else if bullet is sprite[1]
and t2, v1, t5 # masks bullet and sprite
beq t2, zero, alien_collis_end # if collision
addi t2, zero, -0x1
stw t2, 0x1020(t1) # zeroes current alien
stw t2, 0x1000(t0) # zeroes current bullet
br alien_collis_i_end
alien_collis_end: blt zero, t0, alien_collis
alien_collis_i_end: blt zero, t1, alien_collis_i
# -- Game logic ---
# update fire counter
beq s1, zero, 0x4
addi s1, s1, -0x1
# checks if aliens left
ldw t0, s_aliens(zero)
xor t2, t2, t2
logic_aliens:
addi t0, t0, -4
ldw t1, 0x1020(t0)
blt t1, zero, 0x4
addi t2, zero, 0x1
blt zero, t0, logic_aliens
bne t2, zero, 0x4 # if there is no more alien
call load_next_stage
# --- Drawing ---
call led_clear
# Ship
add a0, zero, zero
add a1, zero, s0
ldw a2, spaceship(zero)
call draw_sprite
# Lives
addi a0, zero, 0xb
addi a1, zero, 0x7
add t0, s3, zero
call led_on
addi t0, t0, -0x1
addi a1, a1, -0x1
blt zero, t0, -0x10
# aliens
ldw t0, s_aliens(zero)
draw_aliens:
addi t0, t0, -0x4
ldw t2, 0x1020(t0) # loads current alien
blt t2, zero, draw_aliens_test # if alien < 0, continue
srli t1, t2, 0x10 # gets sprite offset value (stored in MSB)
ldw a2, aliens(t1) # loads alien sprite
andi a0, t2, 0xff # x coord -> a0
srli a1, t2, 0x8 # accesses y coord
andi a1, a1, 0xff # and cleans the value
call draw_sprite # draws the result
draw_aliens_test: bne t0, zero, draw_aliens
# bullets
ldw t0, s_bullet(zero)
draw_bullets:
addi t0, t0, -0x4 # updates loop counter
ldw t2, 0x1000(t0) # loads bullet value
blt t2, zero, draw_bullets_test # if bullet < 0, continue;
srli a1, t2, 0x10 # puts msb in a1 (y coord)
andi a0, t2, 0xffff # puts lsb in a0 (x coord)
addi sp, sp, -4 # push t0
stw t0, 0x0000(sp)
call led_on # draws bullet
ldw t0, 0x0000(sp) # pop t0
addi sp, sp, 4
draw_bullets_test: bne t0, zero, draw_bullets
# alien bullets
ldw t0, s_alienBullet(zero)
draw_Abullets:
addi t0, t0, -0x4 # updates loop counter
ldw t2, 0x1040(t0) # loads bullet value
blt t2, zero, draw_Abullets_test # if bullet < 0, continue;
srli a1, t2, 0x10 # puts msb in a1 (y coord)
andi a0, t2, 0xffff # puts lsb in a0 (x coord)
addi sp, sp, -4 # push t0
stw t0, 0x0000(sp)
call led_on # draws bullet
ldw t0, 0x0000(sp) # pop t0
addi sp, sp, 4
draw_Abullets_test: bne t0, zero, draw_Abullets
call timer
br loop
# -- GAME UTILITY METHODS ---
game_over:
addi a0, zero, game_over_screen
call sprite_ribbon
call text # restarts the game, text will never return and so do game_over
# Routine that makes player fire a bullet and rests timer
fire:
ldw t0, s_bullet(zero) # loads bullet array size
fire_loop:
addi t0, t0, -0x4 # dec loop pointer
bge t0, zero, 0x4 # if t0 < 0
ret # then return
ldw t2, 0x1000(t0) # load bullet
bge t2, zero, fire_loop # while t2 is not free
addi t1, s0, 0x1 # y coord is s0 + 1
slli t2, t1, 0x10 # put y coord ib t2's MSB
addi t1, zero, 0x1 # x coord is 1
or t2, t2, t1 # put x coord in t2's LSB
stw t2, 0x1000(t0) # stores the result
ldw s1, fire_delay(zero) # resets fire delay
ret
# alien at pos a0, a1 fires
alien_fire:
ldw t0, s_alienBullet(zero) # loads bullet array size
a_fire_loop:
addi t0, t0, -0x4 # dec loop pointer
bge t0, zero, 0x4 # if t0 < 0
ret # then return
ldw t2, 0x1040(t0) # load bullet
bge t2, zero, a_fire_loop # while t2 is not free
addi t2, a1, 0x1 # offsets bullet by 1 on y axis
slli t1, t2, 0x10 # puts y coord
add t1, t1, a0 # combines x and y
stw t1, 0x1040(t0) # stores bullet
ret
clear_stage:
addi s1, zero, 0 # resets fire delay
ldw t0, s_aliens(zero) # loads alien array size
addi t1, zero, -0x1 # -1 is default value
addi t0, t0, -0x4
stw t1, 0x1020(t0)
blt zero, t0, -0xc
ldw t0, s_bullet(zero) # loads bullet array size
addi t0, t0, -0x4
stw t1, 0x1000(t0)
blt zero, t0, -0xc
ret
load_next_stage:
addi sp, sp, -4
stw ra, 0x0000(sp) # push ra
ldw t0, 0x1100(zero) # loads current stage offset
ldw t1, stages(t0) # loads current stage length
addi t1, t1, 0x1 # adds 1 to it
slli t1, t1, 0x2 # multiplies it by 4
add t0, t0, t1 # computes new stage offset
ldw t1, stages(t0) # loads next stage size
bne t1, zero, 0xc # if stage length is 0 (end)
addi a0, zero, win_screen # shows win screen
call sprite_ribbon
br text # restarts
stw t0, 0x1100(zero) # stores new stage offset
call load_stage
ldw ra, 0x0000(sp) # pop ra
addi sp, sp, 4
ret
# Loads current stage in the game
load_stage:
# first clean stage
addi sp, sp, -4
stw ra, 0x0000(sp) # push ra
call clear_stage
ldw ra, 0x0000(sp) # pop ra
addi sp, sp, 4
# then load new one
ldw t0, 0x1100(zero) # loads current stage offset
ldw t1, stages(t0) # loads current stage size (number of aliens)
slli t1, t1, 0x2 # multiply it by 4 so that we have the number of bytes of the stage
add t1, t1, t0 # adds offset to stage size to get real upper bound
xor t3, t3, t3 # dest counter
load_stage_loop:
addi t0, t0, 0x4 # next memory location
addi t3, t3, 0x4
ldw t2, stages(t0) # loads alien i
stw t2, 0x101c(t3) # places it in ram (first offset is 4 so origin is 0x101c)
bne t0, t1, load_stage_loop # branches while offset is not equal to the stage size
ret
# Slows down execution on FPGA board
timer:
#ret # -- UNCOMMENT WHEN TESTING IN SIMULATOR
addi t0, zero, 0x0010
slli t0, t0, 0x10
addi t0, t0, 0x7fff
addi t0, t0, -0x0001
blt zero, t0, -0x8
ret
# random number generator
init_random:
stw a0, 0x1200(zero)
stw a2, 0x1204(zero)
ret
random:
ldw v0, 0x1200(zero)
addi v0, v0, 0x1
stw v0, 0x1200(zero)
ldw v1, 0x1204(zero)
add v1, v0, v1
stw v1, 0x1204(zero)
xor v0, v0, v1
ret
# --- LED UTILS ---
# Scrolls a series of sprites from right to left
# params: a0: address of ribbon
# format: ribbon is: 1 word = length, n words = sprites (left to right)
# memory: uses memory address 0x1300 - 0x130c to store displayed sprites, 0x1310 to store input counter
sprite_ribbon:
# this routines invoques subroutines so we push ra
addi sp, sp, -4
stw ra, 0x0000(sp)
ldw t1, 0(a0) # loads ribbon size in t1
slli t1, t1, 0x2 # multiplies this by 4 to get number of columns ( = number of cycles)
stw a0, 0x1310(zero) # stores input address in memory
# initialize memory
addi t0, zero, 0xc
addi t0, t0, -0x4
stw zero, 0x1300(t0)
bne t0, zero, -0xc
sprite_ribbon_loop:
# if current offset is 0
# then shifts memory and loads next word
andi t0, t1, 0x3
bne t0, zero, sprite_ribbon_skip_update
addi t0, zero, 0xc # upper bound
xor t2, t2, t2 # loop counter
ldw t3, 0x1304(t2) # takes next word
stw t3, 0x1300(t2) # stores it in current location
addi t2, t2, 0x4 # inc counter
bne t0, t2, -0x10
ldw t0, 0x1310(zero) # retreives input pointer
addi t0, t0, 0x4 # inc input word counter
ldw t2, 0x0(t0) # loads next word
stw t2, 0x130c(zero) # and stores it in last position
stw t0, 0x1310(zero) # stores new pointer
sprite_ribbon_skip_update:
addi t1, t1, -1 # decrements general timer
andi t3, t1, 0x3 # computes x offset
# redraw
call led_clear
addi a0, zero, 0xc # initialize pos at 8,0
add a0, a0, t3 # plus offset
add a1, zero, zero
addi t0, zero, 0x10
sprite_ribbon_draw:
addi t0, t0, -0x4
addi a0, a0, -0x4 # moves x pos for next word
ldw a2, 0x1300(t0)
addi sp, sp, -4
stw t1, 0x0000(sp) # push t1
call draw_sprite
ldw t1, 0x0000(sp) # pop t1
addi sp, sp, 4
bne t0, zero, sprite_ribbon_draw
call timer
bne t1, zero, sprite_ribbon_loop
# pop ra before exiting
ldw ra, 0x0000(sp)
addi sp, sp, 4
ret;
# converts an (x,y) pos to display data
# params: a0: x, a1: y
# return: v0: word offset, v1: a word with pixel marked to 1, others 0
xy_to_display:
# y-axis : a1 is the amount of shift for 0x01
addi t2, zero, 0x0001
sll t2, t2, a1
# x-axis
andi t1, a0, 0x3 # masks "shift bytes"
slli t1, t1, 0x3 # converts shift amount to 8*shift
sll v1, t2, t1 # shifts y pattern so that it is placed on x
andi v0, a0, 0xc # concerned word
ret
# Converts a sprite to drawable words
# input: a0: x, a1: y, a2: sprite
# output: stack: offset (from 0x2000), v0: first word, v1: second word
sprite_to_screen:
xor t4, t4, t4 # initializes t4 to 0
addi t5, zero, 0xFF # initializes mask to 0xFF
add t1, zero, a2 # loads a2 in a temporary
sub t3, zero, a1 # absolute value for negative shift
sprite_colshift:
and t2, t1, t5 # isolates column's bytes
blt a1, zero, 0x8 # if shift is positive
sll t2, t2, a1 # shift bits on y axis
br 0x4 # else
srl t2, t2, t3 # negative shift
and t2, t2, t5 # cleans this column
or t4, t4, t2 # adds the current column to sprite
slli t5, t5, 0x8 # switches to next column
bne t5, zero, sprite_colshift
andi t1, a0, 0x3 # masks "shift bytes"
slli t1, t1, 0x3 # converts shift amount to 8*shift
sll v0, t4, t1 # shifts y pattern so that it is placed on x
blt a0, zero, 0x8 # if a0 is positive
andi t3, a0, 0xc # concerned word
br 0x4 # else
addi t3, zero, -0x4 # first byte is below memory
addi sp, sp, -4
stw t3, 0x0000(sp) # push t3
addi t2, zero, 0x20 # prepares value 32
sub t1, t2, t1 # 32 - shift is new shift
srli t1, t1, 0x1 # divides by two new shift amount because otherwise it doesn't fit in srl instr
srl t2, t4, t1 # shifts y for placement in second word
srl v1, t2, t1 # performs srl a second time because shift amound was divided by 2
ret
# draws sprite in a2 at pos (a0, a1)
draw_sprite:
addi sp, sp, -4
stw ra, 0x0000(sp) # push ra
call sprite_to_screen
# v0 is first word, v1 second word
ldw t3, 0x0000(sp) # pop t3 (offset)
addi sp, sp, 4
ldw ra, 0x0000(sp) # pop ra
addi sp, sp, 4
# if first word is negative offset skip
blt t3, zero, draw_sprite_skip_first
ldw t1, 0x2000(t3) # loads previous value
or v0, v0, t1 # combines it with new sprite
stw v0, 0x2000(t3) # draws first part
draw_sprite_skip_first:
# exits if lower byte is at the end of screen (prevents overflow)
addi t2, zero, 0x8
blt t3, t2, 0x4
ret
ldw t1, 0x2004(t3) # loads old value
or v1, v1, t1 # interpolate old value with new one
stw v1, 0x2004(t3) # stores
ret
# switches on led at pos {$a0, $a1}
led_on:
addi sp, sp, -4
stw ra, 0x0000(sp) # push ra
call xy_to_display
ldw ra, 0x0000(sp) # pop ra
addi sp, sp, 4
ldw t3, 0x2000(v0)
or t3, t3, v1
stw t3, 0x2000(v0)
ret
led_clear:
stw zero, 0x2000(zero)
stw zero, 0x2004(zero)
stw zero, 0x2008(zero)
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment