Unsetting and resetting certain bits - mips

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

Related

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.

MARS emulator for MIPS Error: address out of range 0x20000000

I am not sure where I am messing up, but I am using the MARS emulator for MIPS and am running into an error at my
lw $s6, 0($s7) #s6 now holds c[i] line.
here is my error:
Error in C:\Programming\mips1.asm line 14: Runtime exception at 0x00400020: address out of range 0x20000000
Go: execution terminated with errors.
.text
.globl main
main:
add $s0, $zero, $zero
lui $s3, 0x2000
addi $s5, $zero, 100
addi $sp, $sp, -8
Loop:
slt $t2, $s0, $s5
beq $zero, $t2, Exit
sll $s7, $s0, 2
add $s7, $s7, $s3 #s7 is now the address of c[i]
lw $s6, 0($s7) #s6 now holds c[i]
slt $t3, $s0, $s1 #set t3 if i is less than a
bne $zero, $t3, Else
sw $s2, 0($s7) #stores b into c[i]
add $s0, $s0, 1
j Loop
Else: add $s2, $zero, $s6
add $s0, $s0, 1
j Loop
Exit: addi $sp, $sp, 8
li $v0, 10
syscall
I solved it, turns out I needed an address that was lower in order for it to be a part of the heap. MARS heap starts at 0x10040000 and moves up.
I changed 0x2000 to 0x1005 and it worked in MARS

MIPS bubble sort algorithm not printing

I am currently beginning to study the MIPS language and I am trying to write a bubble sort code in MIPS, but I guess I have made a mistake somewhere and i can't seem to find it. I believe I am storing elements properly but I don't know why it is not working. Here is a picture of my code:
.data
array: .space 100
i: .word 0
j: .word 0
temp: .word
.text
la $s2, i
la $s3, j
la $s4, temp
li $v0,5
syscall
move $s0, $v0 #array size
li $v0, 8
la $a0, array
li $a1, 100
move $s1, $a0 #actual array(with elements)
syscall
move $a0, $s0 #size becomes argument
move $a1, $s1 #array becomes argument
jal BubbleSort
li $v0, 4
move $a0, $v0
syscall
li $v0, 10
syscall
BubbleSort:
move $s0, $a0
move $s1, $a1
j ExternalLoop
ExternalLoop:
slt $t0,$s2, $s0 #for(i=0;I<N;i++)
beq $t0, $zero, ExitLoop
j InternalLoop
addi $s2, $s2,1 #i++
li $s3, 0 #reset j after every iteration
InternalLoop:
slt $t1, $s3, $s0 #for(j=0;J<N;j++)
beq $t1, $zero, ExitLoop
#array[j]=s1+4*j :
#sll $t2, $s3, 2
#add $s1, $s1, $t2
lb $t3, 0($s1) #array[j]
lb $t4, 4($s1) #array[j+1]
#swapping:
move $s4, $t3
move $t3, $t4
move $t4, $s4
sb $t5, 0($t3)
addi $s3, $s3, 1 #j++
j InternalLoop
move $v0, $t5
ExitLoop:
jr $ra
Maybe my mistake is somewhere at the end where I am storing the return values but I don't know. Can anyone help?

Attempt to execute non-instruction in mips assembler?

.data
stack: .word 3, 2
.text
.globl main
main:
la $s1, stack #assign stack start memory to $s1
addi $t3, $t3, 0 #clear $t3
addi $t3, $t3, 4 #assign 4 to $t3
add $s1, $s1, $t3 #second member of stack
lw $t1, 0($s1) #d2
addi $t3, $t3, -4 #move $t3 forward
add $s1, $s1, $t3 #first member of stack
lw $t0, 0($s1) #d1
add $t0, $t0, $t1 #d1 = d1 +d2
sw $t0, 0($s1) #store new d1 at d1's location
I'm trying to create a mips program, which gets last-1 and last member of the stack, and add them, and store it. I don't care about addi $t3, $t3, 4 or stack: .word 3, 2 it's just for test.
However, when I run this at qtspim I got an error message "attempt to execute non-instruction at 0x0040004c" please enlighten me as to what the problem is.
You need to end your program with a jr $ra, otherwise the processor will just keep executing whatever random instructions that happen to come after the sw $t0, 0($s1).

MIPS MIDI Player: problems with playback and skip

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