I have a mini bank program written that goes calls multiple functions inside the subrouting deposit, this is the subroutine
deposit:
addi $sp, $sp, -8 #save space on stack
addi $s3, $0, 1 #trigger s3
sw $s3, 0($sp)
sw $ra, 4($sp)
.....
jal AsciiConvert #convert ascii of deposited amount to integer
beq $v0, $0, Err_ACC #if no value to be deposited was inputed print error message
beq $t0, $0, deposit_checking #if check exists returns a 0
beq $t0, 1, deposit_saving #if check exists returns a 1
jal printarray
lw $s3, 0($sp)
lw $ra, 4($sp) # reload $ra so we can return to caller
addi $sp, $sp, 8 # restore $sp, freeing the allocated space
jr $ra
deposit_checking:
... arithmetic operations...
jr $ra
the ascii convert subroutine:
AsciiConvert:
...normal arithemtics...
j ConvertOP
ConvertOP:
lb $s0, 0($a1)
beq $s0, $0, endConvert #end at null terminating
beq $s0,32,endConvert #if found a space
addi $s0, $s0, -48 #convert to int
mul $s2, $s1, 10 #multiply sum by 10
add $s2, $s2, $s0 #sum = sum + previous number
add $s1, $s2, $0 #s1 holds previous value
addi $a1, $a1, 1 #increment adress
add $v0, $s2, $0 #store the number in the return adress
j ConvertOP
endConvert:
jr $ra
When I go into deposit, I jal AsciiConvert and then I go into the deposit_Checking subroutine, however the return address of that deposit_Checking returns me back to the line of jal AsciiConvert and not to the line where I called the deposit_Checking subroutine, leading to an infinite loop between Ascii convert subroutine and deposit_Checking subroutine...can someone please help me?
deposit_checking looks like a subroutine, and you identify it as a subroutine in your post, but, we don't enter subroutines with beq instruction, you're supposed to use jal to call a subroutine.
In machine code, the return address, $ra for MIPS, is effectively a parameter to the subroutine — it tells the subroutine where to resume execution in the caller, where to return to. There are several ways to set the $ra register with a meaningful return address, though of course jal is by far the most common way.
beq transfers control of the processor to the target label (when eq is true) by changing the program counter (pc) though does not provide a (new) $ra value.
By not setting $ra to a new value, its old value is retained. Since the $ra register was last set by the jal AsciiConvert, the jr $ra for the other function goes back there, none the wiser that this was not the right call — as it is the caller's job to set that parameter properly.
And while some instruction sets allow calling on a condition, we wouldn't necessarily want all beqs to capture a return address, because then any function that used beq would have to concern itself with preserving $ra.
Let's also note that these behaviors are all visible during debugging. jr $ra, for example will transfer control to whatever machine instruction is addressed by the value in the $ra register. When you first enter a subroutine/function, there should be a proper return address parameter provided in $ra register, and by the time you get to the end of the function with its final instruction jr $ra, if the value in the $ra register's value has changed from entry, then it won't go back to where it was called from — so we'd be looking for somewhere in between that changes $ra, without restoring it back.
I am trying to convert the indirect addressing to native MIPS instructions
I already understood how to do it but this is a single choice objective question and two options seems exact same to me
Q) lw $t0, #($t1) # $t0 <- M[M[$t1]]
(A)
lw $t1, 0($t1)
lw $t0, 0($t1)
(B)
lw $t0, 0($t1)
lw $t0, 0($t0)
Both of them seem same to give same result in the end or am I missing something
I am struggling to understand what this block of mips instruction does. I want to find out what the register $t0 has after these instructions.
ori $t0 $zero 0xA5C11000
addi $t1 $zero 0x10010000
sw $t0 ($t1)
lb $t0 1($t1)
sh $t0 2($t1)
lw $t0 ($t1)
I know that the registers $t0 and $t1 have A5C11000 and 10010000 in them. Then the sw command stores $t1 at the location of $t0. Lb then offsets $t1 by 1 and stores that at the location 10010001? I don't know what happens after this.
Not quite: sw stores the contents of $t0 at the address in $t1, i.e. 10010000. lb loads a byte from address $t1 + 1 into $t0. sh stores a halfword (the lower 2 bytes of $t0) at address $t1 +2.
Try stepping through the code in the debugger to see what it does.
have a really basic question here.
Can a register have both a value and an address. As in assuming i want to swap between values: 5 stored in t0 and 7 stored in t1
does this code work:
sw $t0, 0($t0)
sw $t1, 0($t1)
lw $t1, 0 ($t0)
lw $t0, 0 ($t1)
Sorry this might sound stupid
Not really for all values, as sw and lw need proper alignment (valid addresses should be multiple of 4).
That is, your code would only work for values multiple of 4, and anyways it would be a bad idea to do so, because you would be basically write garbage on whichever address you are pointing at.
To swap registers without overwriting a third register you can use the following trick:
xor $t0, $t0, $t1
xor $t1, $t0, $t1
xor $t0, $t0, $t1
I have the following MIPS code:
addi $s1, $0, 10
lw $t0, 4($s0)
srl $t1, $t0, 1 [STALL becausee $t0 depends on lw's $t0]
add $t2, $t1, $s1 [STALL because $t1 depends on srl's $t1]
sw $t2, 4($s0)
How can I rearrange it to avoid any stalls. I see that all the 2 to 5 line's sequence can't change. We can only move the first line in between srl and add OR lw and srl. Any ideas?
There are 4 read after write (RAW) dependencies in your code: addi->add, lw->srl, srl->add, add->sw. These can't be fixed as you pointed out.
What you can do is move the addi instruction. I would think the best place to move this instruction would be after the lw because in the MIPS architecture all load instructions use a load delay slot. This means that the instruction immediately after the load does not have access to the contents of the load. If you are using this code in a simulator such as spim or MARS this may not be simulated, but assuming you mean to use the loaded value of $t0 in the srl instruction, your assembly above is actually incorrect. For this to work, there should be a nop in between the lw and srl.
For that reason, it would be best to move the addi in between the lw and srl so as to utilize the lw load delay slot.