Last active
December 28, 2015 00:59
-
-
Save hmil/7417561 to your computer and use it in GitHub Desktop.
A space invaders-like mips game for FPGA4U.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# === 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