MIPS MIDI Player: problems with playback and skip - mips

I have a couple of questions about my group project. The first question is regarding playback of a MIDI file. Right now our program can playback a type 0 file with about 75% accuracy (if you can even gauge that). Basically, it get "most" of the song right (or really close). It's clearly not playing every sound and some of the ones it does play sound distorted. So if it's playing most of the notes correctly, what could cause it to miss or distort the others?
The second question is concerned with our interrupt handler. I'm trying to adjust the pointer so the program will skip X bytes forward/backward, but if I try the interrupt while the program is running it stalls and locks the program up. If I run through the interrupt step-by-step it won't stall. It seems like I'm either halfway there or totally off the mark (this was working on an earlier version, but probably b/c the playback function wasn't written correctly). If I had to guess I'd say the problem has something to do with the WITH_STATUS and WITHOUT_STATUS functions. Is that right?
Thank you in advance for any help.
PLAY_MIDI:
addi $s5, $0, 0 # temporaries to control speed and volume
addi $t6, $0, 100
addi $t9, $0, 0
addi $sp, $sp, -4 # add a byte to the stack pointer and store the return address there
sw $ra, 0($sp)
addi $t4, $0, 3
LOOP:
lh $t0, DAT_Format
bnez $t0, NO_SUPPORTED
addi $s3, $s3, 1
addi $s1, $s1, -1
lbu $t9, 0($s3) # look for status byte
blez $s1, OFF_LOOP
bltu $t9, 0x80, LOOP
bgeu $t9, 0xa0, LOOP
WITH_STATUS:
lbu $t9, 0($s3)
lb $t6, -1($s3) #sleep time
lb $a1, 1($s3) # load note
lb $a2, 2($s3) # load volume
addi $s3, $s3, 4
addi $s1, $s1, -4
move $s2, $s1 # *** copy $s1 to $s2 for pause/play
j SLEEP
WITHOUT_STATUS:
lb $t6, -1($s3) #sleep time
lb $a1, 0($s3) # load note
lb $a2, 1($s3) # load volume
addi $s3, $s3, 3 #increase stack
addi $s1, $s1, -3
move $s2, $s1 # ** copy $s1 to $s2 for pause/play
SLEEP:
mul $t6, $t6, $t4
li $v0, 32 # sleep until the next note should be played
addu $a0, $0, $t6 # sleep for $t6 ms
syscall
and $a0, $t9,0x0F # load channel
and $t9,$t9,0x000000F0 # load Command
######################################################
## copy $s1 to $s2 for use differentiating between ##
beq $t9, 0x90, PLAY_NOTE_ON ## stop and pause ##
beq $t9, 0x80, PLAY_NOTE_OFF ## $s2 will hold last position of $s1 ##
bgeu $t9, 0xa0, LOOP ######################################################
AFTER_PLAY:
blez $s1, OFF_LOOP
lbu $t0, 0($s3)
bgeu $t0, 0x80, WITH_STATUS
j WITHOUT_STATUS
OFF_LOOP:
bne $s1, $s2, PAUSE_LOOP # get the return address from the stack and decrease the pointer
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra # jump to the address we just loaded
PLAY_NOTE_ON:
li $v0, 60 # add a byte to the stack pointer and store the return address there
syscall
j AFTER_PLAY
PLAY_NOTE_OFF:
li $v0, 61
syscall
j AFTER_PLAY
NO_SUPPORTED:
j EXIT
#### Below is part of the interrupt handler ####
SKIP_FORWARD: addi $s3, $s3, 1 # by adding to $s3 program will move pointer ahead
la $a0, skip_forward # changed from $s3 to $s1 ***
li $v0, 4
syscall
jr $ra
SKIP_BACKWARD: addi $s3, $s3, -1 # by subtracting from $s3 program will move pointer backwards
la $a0, skip_backward # changed $s3 to $s1
li $v0, 4
syscall
jr $ra

Related

Assembly MIPS: Cannot debug floating-point power function

I have been trying to implement a floating-point function in Assembly MIPS 32-bits, and I have not been able to pinpoint the exact fault. It seems to be in the mul.s $fd, $fsrc1, $fsrc2 command, since the contents of the specific floating-point register remain unchanged (I have checked this with syscalls as well, printing the contents in each case) but I seem to be unable to find the fix. Anyone got any ideas? Full code below:
.align 2
.data
number: .float 0.5
.text
.globl main
main:
li $a0, 3
l.s $f12, number
jal power
li $v0, 2
mtc1 $a0, $f0
syscall
li $v0, 17
syscall
power:
#Build stack
subu $sp,$sp,56 # Stack frame is 56 bytes long
sw $a0, 12($sp) # Save Argument 0 ($a0)
swc1 $f12, 8($sp) # Save Argument 1 ($a1) (integer arg)
sw $s0, 56($sp) # Save $s0
sw $s1, 52($sp) # Save $s1
swc1 $f20, 48($sp) # Save $f20
swc1 $f21, 44($sp) # Save $f21
sw $ra, 16($sp) # Save return address
sw $fp, 20($sp) # Save frame pointer
addiu $fp, $sp, 52
#-----------------------------------------------------------------------#
move $s0, $a0 #stores value of n
mov.s $f22, $f12 #stores value of x
li $s1, 0 #initialize counter with 0
powerLoop:
mul.s $f20, $f20, $f20 #y=y*y
addi $s1, $s1, 1 #increase counter
bgtu $s0, $s1, powerLoop #continue loop as long as counter<n
mov.s $f0, $f20 #return the results
#-----------------------------------------------------------------------#
#Pop stack
lw $a0, 12($sp) #Load back $a0
lwc1 $f12, 8($sp) #Load back $f12
lw $s0, 56($sp) # Load $s0
lw $s1, 52($sp) # Load $s1
lwc1 $f20, 48($sp) # Load $f20
lwc1 $f21, 44($sp) # Load $f21
lw $ra, 16($sp) # Restore old value of $ra
lw $fp, 20($sp) # Restore old value of $fp
addiu $sp, $sp, 56 # Pop stack
jr $ra
SOLVED:
Despite some errors in registers, the main error is in the
li $v0, 2
mtc1 $a0, $f0
syscall
FIX:
li $v0, 2
mov.s $f12, $f0
syscall
REASON: $f12 IS ALWAYS, due to convention, the floating-point argument, even for syscalls. It will not print the contents of $a0 but rather $f12!

MIPS Stack Segment can't be Expanded

I'm writing a function that should return the square root of a perfect square recursively as part of a longer assignment.
I was following this mathematical method before I reverted to an even simpler algorithm to see if the error would repeat itself and it did.
The following code:
.data
prompt: .asciiz "num2sqrt: "
.text
.globl main
sqrt:
# save return address & t0
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t0, 4($sp)
# t0 = n
move $t0, $a0
# a0 = n/2
srl $a0, $t0, 1
jal sqrtRecursor
#restore return address & t0
lw $t0, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
sqrtRecursor:
# save return address & t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t1, 4($sp)
# square test
mult $a0, $a0
mflo $t1
beq $t1, $t0, returnAnswer
bne $t1, $t0, newGuess
#restore return address & t1
lw $t1, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
returnAnswer:
move $v0, $a0
newGuess:
# t1 = (((x+1)*guess)/x)/2
# x+1
addi $t1, $t0, 1
# *guess
mult $a0, $t1
mflo $t1
# /x
div $t1, $t0
mflo $t1
# /2
srl $t1, $t1, 1
move $a0, $t1
jal sqrtRecursor
main:
#print "Enter num2sqrt: "
la $a0, prompt
li $v0, 4
syscall
#input num2sqrt
li $v0, 5
syscall
move $s1, $v0
move $a0, $s1
jal sqrt
# print result
move $a0, $v0
li $v0, 1
syscall
# end
li $v0, 10
syscall
returns the following error on QTSpim:
Can't expand stack segment by 12 bytes to 524288 bytes. Use -lstack # with # > 524288
which then hangs the app for a minute or so.
I've double checked that I'm saving and returning all my return addresses and used variables, and also attempted implementing the same algorithm in Java separately (which worked), but have yet been unable to figure out what I need to fix and where.
I've been able to implement a power function before this so I'm not a complete novice and am asking after putting in approximately 5 hours of research and debugging on this.
It could be a stack management problem or an if/else implementation error from the intuition I have about my own code.

MIPS Recursion Errors

Can anybody tell me what is wrong with my recursion code below. It is supposed to be a recursive function of a decimal to binary function. I just can not see what is wrong. I am new to MIPS so I do not fully understand everything but from my understanding this is what I got.
I hardcoded a number in and I am supposed to get the output 101000 but it would not load anything beyond the message.
.data
msg1:.asciiz "Output (40) = "
.text
.globl main
la $a0,msg1 # load string as parameter
li $v0, 4 # load operation "print string"
syscall # request "print string" for msg1
addi $t0, $zero, 40
move $a0, $t0
li $t2, 2
jal d2b
add $a0, $v0, $zero # load the value of $v0 into $a0
li $v0, 1 # load operation "print integer"
syscall # request "print integer"
d2b: li $t1, 0 # t1 = 0
bgt $a0, $t1, skip # if a0 > t1 no
li $v0, 0 # load v0 as 0
jr $ra # print this shit out
skip: subu $sp, $sp, 32 # sp down 32
sw $ra 20($sp) # save $ra
sw $fp, 16($sp) # save $fp
addiu $fp, $sp, 28 # set up $ fp
sw $a0, 0($fp) # save n
divu $a0, $t2 # divide n / 2
mflo $t3 # quota
mfhi $t4 # rem
move $a1, $t4 # rem keep
move $a2, $t3 # quota keep
addi $a1, 10 # adding rem + 10
jal d2b # call recursive —> d2b(n/2)
lw $a0, 0($fp) # restore n
multu $v0, $a2 # rem+10 *d2b(n/2)
lw $ra, 20($sp) # load $ra
lw $fp, 16($sp) # load $fp
addiu $sp, $sp, 32 # pop stack
jr $ra # return

MIPS - Runtime exception at 0x004001e8: fetch address not aligned on word boundary 0x10010001

I am trying to implement puts in MIPS. I have a procedure putchar which prints a char to the screen :
.text
putchar:
lui $t0, 0xffff # base address of memory map
XReady:
lw $t1, 8($t0) #read from transmitter control register
andi $t1, $t1, 0x1 # extract ready bit
beqz $t1, XReady # if 1, store char ; else, loop
sw $a0, 12($t0) # send character to display
jr $ra # return to place in program before function call
In my main subroutine, I set $a0 to the string I want to print and then I call puts :
la $a0, array # defined in .data as -- array: .space 2000 --
gal puts
I get an error fetch address not aligned on word boundary on line 242 of puts (marked with a *)
.text
puts:
addi $sp, $sp, -24 # make room for 6 registers
sw $ra, 20($sp) # save $ra on the stack
sw $s0, 16($sp) # save $s0 on the stack
sw, $s1, 12($sp) # save $s1 on the stack
sw, $s2, 8($sp) # save $s2 on the stack
sw, $s3, 4($sp) # save $s3 on the stack
sw, $s4, 0($sp) # save $s4 on the stack
move $s0, $a0 # copy parameter $a0 into $s0
move $s1, $a1 # copy parameter $a0 into $s1
move $s2, $a2 # copy parameter $a0 into $s2
move $s3, $a3 # copy parameter $a0 into $s3
move $s4, $zero # s4 is a character counter. $s4 = 0
getsLoop:
addi $t0, $zero, 0x00 # Put NULL ascii character inside $t0
sll $t1, $s4, 2 # create buffer storing address ($t1 = $s1 * 4)
add $t2, $s0, $t1 # register #t2 now holds buffer address
* lw $t3, ($s0) # load char into #t3
beq $t3, $t0, exitPuts # exit puts if the current character is the NULL character
move $a0, $t3 # put the character to print inside $a0, accessible by putchar
jal putchar # print char using putchar
addi $s0, $s0, 1 # character count += 1
j getsLoop # Loop to print next character
exitPuts:
lw $s4, 0($sp) # restore stack
lw $s3, 4($sp) # -
lw $s2, 8($sp) # -
lw $s1, 12($sp) # -
lw $s0, 16($sp) # -
lw $ra, 20($sp) # -
addi $sp, $sp, 20 # pop from stack
jr $ra # return
I don't why I'm getting this error... Isn't $s0 the address of array defined in main?
When you use lw you load an entire word (4 bytes, not to be confused with words in natural languages), and that word has to be aligned on a word boundary (the two least significant bits of the address have to be 0).
ASCII characters are typically stored using one byte per character, so you should use the lbu instruction to load them instead of lw.

Unsetting and resetting certain bits

For a homework assignment in school, I need to use a MMIO LED display where each led is exactly 2 bits stored within a byte. For the assignment I need to "move" these LEDs up, down, left, and right. I also need to set the color (I will be using 0x40 for this). Here's my issue:
When I click the "right" arrow to move the LED over 1 column, it remains in the current column when it should be returning to black (0x00). If I click right 4 times (moving over exactly 1 byte), I get another lit LED, leaving the original one there.
Here is my MIPS code:
getLedPattern:
move $t2, $s2
andi $t1, $t2, 0x3 #remainder of x / 4 is in $t0
sll $t0, $t2, 2 #x / 4 is in $t0
beq $t0, 0, case0
beq $t0, 1, case1
beq $t0, 2, case2
case3:
andi $a0, 0xFFFFFFFC
#insert $a1 into bits 0 and 1 of $a0 into $v0
or $v0, $a0, $a1
jr $ra
case2:
andi $a0, 0xFFFFFCFF
#insert $a1 into bits 2 and 3 of $a0 into $v0
#srl $a1, $a1, 2
or $v0, $a0, $a1
jr $ra
case1:
andi $a0, 0xFFFCFFFF
#insert $a1 into bits 4 and 5 of $a0 into $v0
#srl $a1, $a1, 4
or $v0, $a0, $a1
jr $ra
case0:
andi $a0, 0xFCFFFFFF
#insert $a1 into bits 6 and 7 of $a0 into $v0
#srl $a1, $a1, 6
or $v0, $a0, $a1
jr $ra
setLED:
addi $sp, $sp, -20
sw $ra, 0($sp)
sw $t0, 4($sp)
sw $t1, 8($sp)
sw $t2, 12($sp)
sw $t3, 16($sp)
move $t5, $a0
sll $t6, $a1, 5 # y*32
srl $t2, $a2, 2 # x/4
add $t5, $t5, $t6
add $t5, $t5, $t2
lb $a0, 0($t5)
move $a1, $a3
jal getLedPattern
sb $v0, 0($t5)
move $s3, $t5
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
lw $t2, 12($sp)
lw $t3, 16($sp)
addi $sp, $sp, 20
jr $ra
The logic is that it starts out at at memory location 0xFFFFOOO8 (top left LED), moves down one row (+32 bytes) and over x columns (plus x*bits). However, I can't seem to unset the current LED and move it over one. Any help would be appreciated. I believe that my or in getLedPattern: is wrong, but not 100% sure.
Hopefully, getting this correct I will be able to get this correct in a general sense (no LED display).
I guess that your constants for clearing bits are wrong.
try the following instead:
0xfffffffc // or ~0x03
0xfffffff3 // or ~0x0C
0xffffffcf // or ~0x30
0xffffff3f // or ~0xC0
There are other oddity in your code:
s2 is used, but never set
s3 is set, but never used
case1 and case2 will never be reached because $t0 can hold nor 1 neither 2