I am trying to take in some user input that takes in a length of an array, and the user is able to assign the numbers for every index of that array, and then print it out. The Java code I basically want to do is:
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int[] array = new int[N];
for (int i=0; i<N; i ) {
array[i] = sc.nextInt();
}
for (int i=0; i<N; i ) {
System.out.println(array[i]);
}
This is what I have so far in MIPS, but I'm having trouble accessing the specific indexes of the array.
.data 0x0
array:
.space 4
.text 0x3000
main:
# read in the N (number of elements)
addi $v0, $0, 5 # system call 5 is for reading an integer
syscall # integer value read is in $v0
add $s0, $0, $v0 # copy N into $s0
add $t0, $0, $0 # for (i = 0;... store i in $t0
loop:
beq $t0, $s0, printArray # go to print array if i == N
sll $t1, $t0, 2 # convert "i" to word offset by multiplying by 4
addi $v0, $0, 5 # system call 5 is for reading an integer
syscall # integer value read is in $v0
add $s1, $0, $v0 # copy input into $s1
sw $s1, array($t1) # store input at array[i], where word aligned i is in $t1
addi $t0, $t0, 1 # for (...;...; i increment i
b loop # branch to beginning of loop
printArray:
add $t0, $0, $0 # for (i = 0;... store i in $t0
add $t1, $0, $0
add $t2, $0, $0
j printArrayLoop
printArrayLoop:
beq $t0, $s0, exit # exit if i == N
addi $v0, $0, 1 # system call 1 is for printing an integer
lw $a0, array($t0) # bring the value at index $t0 in array into $a0
syscall # print the integer
# Print a newline
addi $v0, $0, 4 # system call 4 is for printing a string
la $a0, newline # address of last printed integer is in $a0
syscall # print the newline
addi $t0, $t0, 1 # for (...;...; i increment i
b printArrayLoop # jump to beginning of printArrayLoop
exit:
ori $v0, $0, 10
syscall
CodePudding user response:
The index needs to be scaled to make a byte offset, which can then be used together with the base address of the array. Why? Because each integer takes 4 bytes, and in memory, each of those 4 bytes has its own address. The next integer in the array (e.g. at i 1
) starts at an address that is numerically 4 higher than the last one (e.g. at i
). So, we scale indexes by the size of the array element to make a byte offset to access an indexed element of the array.
There's no point to copy $v0
into $s1
, it will store into memory just fine from $v0
.
You've changed the loop from a for-loop in Java to a do-while in assembly, which means that if the user inputs a count of 0 it will work in the Java version, but break in the assembly version, in that it will still ask for at least one input. The Java version will follow this pattern:
int i = 0;
while ( i < N ) {
<for-loop-body>
i ;
}
So, loop-test, loop-body, increment, loop-test, loop-body, increment...
By the syscalls, looks like you're using MARS or QtSpim, and neither of these uses a branch delay slot by default. I guess you are selecting the option for that?
The approach of putting the increment in the branch delay slot will also loop one more time than you're expecting: in the Java version, the increment will happen before the loop exit test, but in the assembly version, after.
It's a very good approach that you started with pseudo code — that often offers considerable clarity that is hard to have writing in assembly from scratch without an algorithm. But you should try to follow your pseudo code more literally, rather than making arbitrary changes in taking it to assembly code.