Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert C to MIPS - Nested Arrays

Tags:

c

assembly

mips

I am studying the MIPS assembly language and came across this example in the book and to me it seems incorrect. If it is it wouldn't be the first mistake I found in this book.

The variables f and g are assigned registers $s0 and $s1 respectively, the base addresses for the arrays A and B are $s6 and $s7 respectively.

The c code example is:

f = g - A[B[4]];

And the corresponding MIPS assembly provided is:

lw  $t0, 16($s7)
lw  $s0, 0($t0)
sub $s0, $s1, $s0

From my understanding the above MIPS code would load some random data from memory at the address provided by $t0 and then subtract it from $s1 and not access the index $t0 of the array denoted in $s6.

The correct MIPS assembly from my understanding would be along the lines of:

lw  $t0, 4($s7)
add $t0, $t0, $s6
sll $t0, $t0, 2
lw  $s0, 0($t0)
sub $s0, $s1, $s0

I am correct that this is an error in the book or am I misunderstanding something.


Edit: Fixed an error in the corrected mips code as pointed out by Chris Dodd

like image 202
MitMaro Avatar asked Oct 23 '22 22:10

MitMaro


1 Answers

This is for anyone (possibly CprE 381 students) who may stumble upon this looking for a good example. The OP's edited code is still incorrect. The offset in the first load word function should be 16. It could be 4 if the memory width is 32 bits, but then the shift/multiplication would not be needed. Assuming the memory is 8 bits wide, the add and shift functions need to be switched. In OP's code, it's multiplying the address of A[B[4] / 4] by 4. Shifting/multiplying first will get the correct index. The correct code is:

lw  $t0, 16($s7)   # gets the value of B[4]
                   # offset could be 4 depending on memory width
                   # but then the shift would not be needed
sll $t0, $t0, 2    # this multiplies the index by 4 to get the address offset
add $t0, $t0, $s6  # adds the base address of A and the offset
lw  $t0, 0($t0)    # loads the value at the address
sub $s0, $s1, $t0  # performs subtraction and stores in f

In case anyone is confused about the whole offset of 16 vs 4 and whether the shift is needed, let me explain. If the memory width is 32 bits then an entire 32-bit integer can be stored in one memory location. If this is the case, then the array index is the same as the address offset. However, if the memory is only 8 bits (1 byte) wide, then a 32-bit integer is stored across 4 memory locations (1 address for each byte). This is why you need to shift the index by 2 (or multiply by 4) to get the correct address offset.

like image 98
Kollin Avatar answered Oct 27 '22 00:10

Kollin