how to read array in MIPS - arrays

This is code in C language:
while(a<10){
M[a] = a + b;
a++; }
How to rewrite it in assembly language in Mips and don't use pseudo instructions.
M is array of 32bit elements. a in register $s0, b in $s1, $s2 is base address of M array.
And my code it:
addi $s3, $zero, 10
LOOP: add $st1, $s0, $s1
add $t2, $s2, $s0
sw $t1, 0($s2)
addi $s0, $s0, 1
bne $s0, $s3, LOOP
but i think it has problem.
Thank you very much.

If I take this C program and compile it to MIPS assembly:
int main() {
int b = 10;
int a = 20;
int M[20];
while(a<10){
M[a] = a + b;
a++; }
}
Then with my toolchain the MIPS assembly becomes:
.file 1 "Cprogram.c"
# -G value = 8, Cpu = 3000, ISA = 1
# GNU C version cygnus-2.7.2-970404 (mips-mips-ecoff) compiled by GNU C version cygnus-2.7.2-970404.
# options passed: -msoft-float
# options enabled: -fpeephole -ffunction-cse -fkeep-static-consts
# -fpcc-struct-return -fcommon -fverbose-asm -fgnu-linker -msoft-float
# -meb -mcpu=3000
gcc2_compiled.:
__gnu_compiled_c:
.text
.align 2
.globl main
.ent main
main:
.frame $fp,112,$31 # vars= 88, regs= 2/0, args= 16, extra= 0
.mask 0xc0000000,-4
.fmask 0x00000000,0
subu $sp,$sp,112
sw $31,108($sp)
sw $fp,104($sp)
move $fp,$sp
jal __main
li $2,10 # 0x0000000a
sw $2,16($fp)
li $2,20 # 0x00000014
sw $2,20($fp)
$L2:
lw $2,20($fp)
slt $3,$2,10
bne $3,$0,$L4
j $L3
$L4:
lw $2,20($fp)
move $3,$2
sll $2,$3,2
addu $4,$fp,16
addu $3,$2,$4
addu $2,$3,8
lw $3,20($fp)
lw $4,16($fp)
addu $3,$3,$4
sw $3,0($2)
lw $2,20($fp)
addu $3,$2,1
sw $3,20($fp)
j $L2
$L3:
$L1:
move $sp,$fp # sp not trusted here
lw $31,108($sp)
lw $fp,104($sp)
addu $sp,$sp,112
j $31
.end main

Related

C to assembly MIPS-32 [duplicate]

The MIPS assembly code generated by mips-gcc almost, but doesn't quite, run on the Mars MIPS simulator. For example:
The compiler generates "j $31" instead of "jr $31"
The compiler puts .align directives in the text segment, which Mars does not allow.
In addition, the generated assembly is not quite set up so that it will start and stop properly (i.e., no sycall 10 at the end).
These problems are all appear to be easily fixable with a simply script; but, before I re-invent the wheel, I was wondering:
(1) Are there any gcc flags that will make some of these problems go away?
(2) Does anybody know of an existing program that will fix up the mips-gcc output so that it will run on Mars?
(FWIW, I see the same behavior on both gcc 3.3.6 and 4.6.1.)
Are there any gcc flags that will make some of these problems go away?
Short answer is no. Mars uses custom system calls and is very different in calling conventions.
Does anybody know of an existing program that will fix up the mips-gcc output so that it will run on Mars?
I don't know of any automated way to convert it. You can do it only manually. I have done it actually.
Roughly, these are the steps I followed:
0. Use GobBolt compiler explorer to get a beatified raw assembly of your code. They don't use specific gcc options to get this beatified view according to this, so I'm not mentioning any gcc command, but you can set up a local copy of it.
Replace all the syscalls and their calling conventions according to this : https://courses.missouristate.edu/kenvollmar/mars/help/syscallhelp.html
Replace/add the required segment labels (such as .text, .data etc.) along with their required data.
If you have a main function (label) add j main after .text.
(4. Optionally, you can rename the registers to be more readable because as Peter Cordes mentioned in the comments, gcc for mips doesn't support the argument -mregnames)
This is an example I made, it lacks main cause it was intended as a library :
C code :
#include <stdio.h>
#include <stdlib.h>
typedef struct node Node;
struct node {
int data;
struct node *left;
struct node *right;
};
Node *new_node (int data) {
Node *ret = malloc (sizeof (Node)); ret->left = NULL;
ret->data = data;
ret->left = NULL;
ret->right = NULL;
return ret; }
void link (Node *parent, Node *left, Node *right) {
parent->left = left;
parent->right = right;
}
int depth (Node *root) {
if (root == NULL) {
return -1;
}
int left = depth (root->left);
int right = depth (root->right);
return 1 + (left > right? left : right);
}
int even_level_max (Node *root, int level) {
if (root == NULL) {
return 0x80000000;
}
int left = even_level_max(root->left, level + 1);
int right = even_level_max (root->right, level + 1);
int greater = (left > right) ? left : right;
if (level % 2 == 0) {
return (greater > root->data)? greater : root->data;
} else {
return greater;
}
}
Godbolt code :
new_node:
addiu $sp,$sp,-40
sw $31,36($sp)
sw $fp,32($sp)
move $fp,$sp
sw $4,40($fp)
li $4,12 # 0xc
jal malloc
nop
sw $2,24($fp)
lw $2,24($fp)
nop
sw $0,4($2)
lw $2,24($fp)
lw $3,40($fp)
nop
sw $3,0($2)
lw $2,24($fp)
nop
sw $0,4($2)
lw $2,24($fp)
nop
sw $0,8($2)
lw $2,24($fp)
move $sp,$fp
lw $31,36($sp)
lw $fp,32($sp)
addiu $sp,$sp,40
jr $31
nop
link:
addiu $sp,$sp,-8
sw $fp,4($sp)
move $fp,$sp
sw $4,8($fp)
sw $5,12($fp)
sw $6,16($fp)
lw $2,8($fp)
lw $3,12($fp)
nop
sw $3,4($2)
lw $2,8($fp)
lw $3,16($fp)
nop
sw $3,8($2)
nop
move $sp,$fp
lw $fp,4($sp)
addiu $sp,$sp,8
jr $31
nop
depth:
addiu $sp,$sp,-40
sw $31,36($sp)
sw $fp,32($sp)
move $fp,$sp
sw $4,40($fp)
lw $2,40($fp)
nop
bne $2,$0,$L5
nop
li $2,-1 # 0xffffffffffffffff
b $L6
nop
$L5:
lw $2,40($fp)
nop
lw $2,4($2)
nop
move $4,$2
jal depth
nop
sw $2,24($fp)
lw $2,40($fp)
nop
lw $2,8($2)
nop
move $4,$2
jal depth
nop
sw $2,28($fp)
lw $3,24($fp)
lw $2,28($fp)
nop
slt $4,$2,$3
beq $4,$0,$L7
nop
move $2,$3
$L7:
addiu $2,$2,1
$L6:
move $sp,$fp
lw $31,36($sp)
lw $fp,32($sp)
addiu $sp,$sp,40
jr $31
nop
even_level_max:
addiu $sp,$sp,-48
sw $31,44($sp)
sw $fp,40($sp)
move $fp,$sp
sw $4,48($fp)
sw $5,52($fp)
lw $2,48($fp)
nop
bne $2,$0,$L9
nop
li $2,-2147483648 # 0xffffffff80000000
b $L10
nop
$L9:
lw $2,48($fp)
nop
lw $3,4($2)
lw $2,52($fp)
nop
addiu $2,$2,1
move $5,$2
move $4,$3
jal even_level_max
nop
sw $2,24($fp)
lw $2,48($fp)
nop
lw $3,8($2)
lw $2,52($fp)
nop
addiu $2,$2,1
move $5,$2
move $4,$3
jal even_level_max
nop
sw $2,28($fp)
lw $3,24($fp)
lw $2,28($fp)
nop
slt $4,$2,$3
beq $4,$0,$L11
nop
move $2,$3
$L11:
sw $2,32($fp)
lw $2,52($fp)
nop
andi $2,$2,0x1
bne $2,$0,$L12
nop
lw $2,48($fp)
nop
lw $3,0($2)
lw $2,32($fp)
nop
slt $4,$2,$3
beq $4,$0,$L10
nop
move $2,$3
b $L10
nop
$L12:
lw $2,32($fp)
$L10:
move $sp,$fp
lw $31,44($sp)
lw $fp,40($sp)
addiu $sp,$sp,48
jr $31
nop
Converted Mars code :
# Registers:
# a : store results
# t : temporaries
# s : saved
# k : kernel
.text:
j main
new_node: #Node *new_node (int data)
# prologue
addiu $sp,$sp,-40
sw $ra,36($sp)
sw $fp,32($sp)
move $fp,$sp
sw $a0,40($fp) # fp[40] = data
li $v0, 9
li $a0, 12
syscall
sw $v0,24($fp) # fp[24] = sbrk ( sizeof (Node = 12) )
lw $v0,24($fp)
lw $v1,40($fp) # data = fp[40]
sw $v1,0($v0) # ret[0] = data;
lw $v0,24($fp)
sw $zero,4($v0) # ret[4] = NULL;
lw $v0,24($fp)
sw $zero,8($v0) # ret[8] = NULL;
# epilogue
lw $v0,24($fp)
move $sp,$fp
lw $ra,36($sp)
lw $fp,32($sp)
addiu $sp,$sp,40
jr $ra
nop
link: # int depth (Node *root)
# prologue
addiu $sp,$sp,-8
sw $fp,4($sp)
move $fp,$sp
#store arguments
sw $a0,8($fp)
sw $a1,12($fp)
sw $a2,16($fp)
#parent -> left = left;
lw $v0,8($fp)
lw $v1,12($fp)
sw $v1,4($v0)
sw $a1,4($a0)
# parent -> right = right
lw $v0,8($fp)
lw $v1,16($fp)
sw $v1,8($v0)
sw $a2,8($a0)
# epilogue
move $sp,$fp
lw $fp,4($sp)
addiu $sp,$sp,8
jr $ra
nop
depth: # int depth (Node *root)
# prologue
addiu $sp,$sp,-40
sw $ra,36($sp)
sw $fp,32($sp)
move $fp,$sp
sw $a0,40($fp) # fp[40] = root
lw $v0,40($fp)
bne $v0,$zero,L5
li $v0,-1
b L6 #if (root == NULL) return -1;
L5:
lw $v0,40($fp)
lw $v0,4($v0)
move $a0,$v0 # a0 = root -> left
jal depth # depth(a0)
sw $v0,24($fp) # fp[24] = depth(a0)
lw $v0,40($fp)
lw $v0,8($v0)
move $a0,$v0 # a0 = root -> right
jal depth # depth(a0)
sw $v0,28($fp) # fp[28] = depth(a0)
lw $v1,24($fp) # v0 = right
lw $v0,28($fp) # v1 = left
slt $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
beq $a0,$zero,L7
move $v0,$v1 # executed when v1 > v0
L7:
addiu $v0,$v0,1 # executed when v0 < v1
L6:
# epilogue
move $sp,$fp
lw $ra,36($sp)
lw $fp,32($sp)
addiu $sp,$sp,40
jr $ra
even_level_max:
# prologue
addiu $sp,$sp,-48
sw $ra,44($sp)
sw $fp,40($sp)
move $fp,$sp
sw $a0,48($fp) # fp[48] = root
sw $a1,52($fp) # fp[52] = level
lw $v0,48($fp)
bne $v0,$zero,L9
li $v0, 0x80000000
b L10 # if (root == NULL) return 0x80000000;
L9: # root != NULL
lw $v0,48($fp)
lw $v1,4($v0) # v1 = root -> left
lw $v0,52($fp)
addiu $v0,$v0,1 # v0 = level + 1
move $a1,$v0
move $a0,$v1
jal even_level_max
sw $v0,24($fp) # fp[24] = left = even_level_max(root -> left, level +1)
lw $v0,48($fp)
lw $v1,8($v0) # v1 = root -> right
lw $v0,52($fp)
addiu $v0,$v0,1 # v0 = level + 1
move $a1,$v0
move $a0,$v1
jal even_level_max
sw $v0,28($fp) # fp[28] = right = even_level_max(root -> right, level + 1)
lw $v1,24($fp) # v1 = right
lw $v0,28($fp) # v0 = left
slt $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
beq $a0,$zero,L11
move $v0,$v1
L11:
sw $v0,32($fp) # fp[32] = greater
lw $v0,52($fp) # v0 = level
andi $v0,$v0,0x1 # v0 & 1
bne $v0,$zero,L12
lw $v0,48($fp) # v0 = root
lw $v1,0($v0) # v1 = data
lw $v0,32($fp) # v0 = greater
slt $a0,$v0,$v1 # a0 = v1 > v0 ? 0 : 1
beq $a0,$zero,L10 # return greater
move $v0,$v1 # v0 = data
b L10 # return data
L12:
lw $v0,32($fp) # return greater
L10:
# epilogue
move $sp,$fp
lw $ra,44($sp)
lw $fp,40($sp)
addiu $sp,$sp,48
jr $ra

Array indexing in a for-loop in MIPS assembly

I need to implement this code in the MARS emulator:
int x[10] = { /* initial values */ } ;
int i;
for(i=0; i<10; i++){
print i;
}
for (i=0; i<10; i++){
x[i] = 2*i+1;
print x[i];
}
Heres what I have:
.data
i: .word 0
x: .word 1,2,3,4,5,6,7,8,9,10
.align 2
.text
.globl main
main:
lw $t0, i
lw $t1, x
li $t4, 4
jal L0
li $t0, 0
jal L1
li $v0, 10 # terminate
syscall
L0:
li $v0, 1
la $a0, ($t0)
syscall
addi $t0, $t0, 1
bge $t0,10, RETURN #goto L1 if NOT n<0
b L0
L1:
li $v0, 1
la $a0, ($t1)
syscall
mul $t2, $t0, $t4
lw $t1, x + ($t2) #########this line#########
addi $t0, $t0, 1
bge $t0,10, RETURN
b L1
RETURN:
jr $ra
I commented next to the line that I believe to be the source of my problem. That is essentially the line that is referencing x[i]. I multiplied i by 4 and added that value to x, in attempt to reference the appropriate word in the array. I don't know how to properly implement this concept.
Thanks for the help.
You need to do something like this:
L1:
la $a1,x # $a1 = &x
L2: # do {
addu $a0,$t0,$t0 # $a0 = i*2
addiu $a0,$a0,1 # $a0 = i*2 + 1
sw $a0,($a1) # x[i] = i*2 + 1
addiu $a1,$a1,4 # a1 = &x[i+1]
li $v0,1 # print_int
syscall # print_int(i*2 + 1)
addiu $t0,$t0,1 # i++
bne $t0,10,L2 # } while (i != 10)
jr $ra
And stuff like la $a0, ($t0) looks really weird. Please use the much clearer move $a0, $t0 instead.

I can't understand a portion of code from a MIPS problem

So, I have a problem which translates a C program that calculates the sum of n numbers with a function with a variable number of parameters.
#include<stdarg.h>
int sum(int n, ...){
int i,s;
va_list l;
va_start(l,n);
s=0;
for(i=0;i<n;++i) s+=va_arg(l,int);
va_end(l);
return s;
}
int s;
void main(){
s=sum(3,1,2,3);
s=sum(2,10,20);
}
Here is the MIPS code (ignore the comments), but I can't understand the part below bge, specifically the $t0 operations, what exactly happens when it adds 4 to $t0, I know that if it stores an integer it will simply add 4 to that number, and if I refer to the $sp, then add $sp, 4 would mean the pop operation. I'm really confused about what is happening on that part.
.data
s: .space 4
.text
main:
subu $sp,16 # incarcam parametrii, conform conventiei C
li $t0,3
sw $t0,12($sp)
li $t0,2
sw $t0,8($sp)
li $t0,1
sw $t0,4($sp)
li $t0,3
sw $t0,0($sp)
jal sum # functia returneaza in $v0
addu $sp,16 # descarcam atatia par. cati am incarcat (adica 4 parametri)
sw $v0,s # val. ret. este in $v0
# acum s contine 6
subu $sp,12
li $t0,20
sw $t0,8($sp)
li $t0,10
sw $t0,4($sp)
li $t0,2
sw $t0,0($sp)
jal sum
addu $sp,12 # acum am incarcat doar 3 par., deci descarc doar 3 par.
sw $v0,s
# acum s contine 30
li $v0,10
syscall
sum: # primeste o stiva de forma $sp:(n)()()()...
subu $sp,16 # rezerv loc pt. salvat $fp si pentru i,s,l din functie
sw $fp,12($sp)
addiu $fp,$sp,12
# acum stiva este $sp:(l)(s)(i)$fp:($fp v)(n)()()()...
addu $t0,$fp,8
sw $t0,-12($fp) # va_start(l,n); avem $sp:(l)(s)(i)$fp:($fp v)(n)l:()()...
sw $zero,-8($fp) # s=0
sw $zero,-4($fp) # i=0
sum_et1:
lw $t0,-4($fp)
lw $t1,4($fp)
bge $t0,$t1,sum_et2 # daca i>=n iesim
lw $t0,-12($fp)
addu $t0,4 # 4 este sizeof(int)
sw $t0,-12($fp)
lw $t0,-4($t0) # 4 este sizeof(int)
lw $t1,-8($fp)
add $t1,$t1,$t0
sw $t1,-8($fp) # s+=va_arg(i,int)
lw $t0,-4($fp)
add $t0,1
sw $t0,-4($fp) # ++i
b sum_et1
sum_et2:
# in aceasta implementare nu avem ce executa pentru va_end(l)
lw $v0,-8($fp)
lw $fp,0($fp)
addu $sp,16
jr $ra
My MIPS assembly is very rusty, but it would seem:
lw $t0,-12($fp) # load va_list l
addu $t0,4 # increment l to the next int argument
sw $t0,-12($fp) # store l
lw $t0,-4($t0) # load the argument pointed to by l (still in $t0)
lw $t1,-8($fp) # load sum
add $t1,$t1,$t0 # add the argument to sum
sw $t1,-8($fp) # store sum
lw $t0,-4($fp) # load i
add $t0,1 # increment i by 1
sw $t0,-4($fp) # store i
I suppose the confusing part is that va_list l contains a pointer internally, and is incremented inside the va_arg macro.

Translating a C statement into MIPS assembly instructions?

I have another homework question that, like the last question I asked on this site, wasn't explained well by the teacher nor the textbook. Here's the question:
Translate this C statement into MIPS assembly instructions:
B[8] = A[i-j];
Assume variables f, g, h, i and j and are assigned to registers $s0, $s1, $s2, $s3, and $s4, respectively. Assume the base addresses of the arrays A and B are in registers $s6 and $s7, respectively.
Now, where I'm stuck is adding the two variables and using the result as an offset. So far, I have the following:
sub $t0, $s3, $s4 # add values to get offset amount, store in $t0
sll $t1, $t0,2 # multiply the offset by 4, store in $t1
Now, I don't know if I can use $t1 as an offset to access that array element. It looks like the textbook only uses numbers (e.g. 4($s7)) instead of registers (e.g. $t1($s7)) What do I do next?
A compiler can only translate complete program, so here's a complete program that includes your instruction, with its translating into MIPS asembly instrution. I hope you can study what's being done here and draw some conclusions.
int main() {
int i = 3;
int j = 2;
int B[3] = {10, 20, 30};
int A[3] = {100, 200, 300};
B[8] = A[i-j];
}
MIPS for the above:
.file 1 "Cprogram.c"
# -G value = 8, Cpu = 3000, ISA = 1
# GNU C version cygnus-2.7.2-970404 (mips-mips-ecoff) compiled by GNU C version cygnus-2.7.2-970404.
# options passed: -msoft-float
# options enabled: -fpeephole -ffunction-cse -fkeep-static-consts
# -fpcc-struct-return -fcommon -fverbose-asm -fgnu-linker -msoft-float
# -meb -mcpu=3000
gcc2_compiled.:
__gnu_compiled_c:
.rdata
.align 2
$LC0:
.word 10
.word 20
.word 30
.align 2
$LC1:
.word 100
.word 200
.word 300
.text
.align 2
.globl main
.ent main
main:
.frame $fp,64,$31 # vars= 40, regs= 2/0, args= 16, extra= 0
.mask 0xc0000000,-4
.fmask 0x00000000,0
subu $sp,$sp,64
sw $31,60($sp)
sw $fp,56($sp)
move $fp,$sp
jal __main
li $2,3 # 0x00000003
sw $2,16($fp)
li $2,2 # 0x00000002
sw $2,20($fp)
addu $2,$fp,24
la $3,$LC0
lw $4,0($3)
lw $5,4($3)
lw $6,8($3)
sw $4,0($2)
sw $5,4($2)
sw $6,8($2)
addu $2,$fp,40
la $3,$LC1
lw $4,0($3)
lw $5,4($3)
lw $6,8($3)
sw $4,0($2)
sw $5,4($2)
sw $6,8($2)
lw $2,16($fp)
lw $3,20($fp)
subu $2,$2,$3
move $3,$2
sll $2,$3,2
addu $3,$fp,16
addu $2,$2,$3
addu $3,$2,24
lw $2,0($3)
sw $2,56($fp)
$L1:
move $sp,$fp # sp not trusted here
lw $31,60($sp)
lw $fp,56($sp)
addu $sp,$sp,64
j $31
.end main

how to transform array from C to mips

I have code C :
for (i=0; i<98; i++) {
C[i] = A[i+1] - B[i+2] * A[1];
}
first address of array A,B,C are A000h,B000h,C000h
and i transform to mips
addi $a0,$zero,A000h
addi $a1,$zero,B000h
addi $a2,$zero,C000h
li $t0,1
li $t1,98
loop:
addi $a0,0
addi $t2,$a0,4
addi $a1,8
addi $a2,0
lw $t3,0($a0)
lw $t4,4($t2)
lw $t5,8($a1)
mult $t5,$t5,$t3
sub $t6,$t4,$t5
sw $t6,0($a2)
addi $t0,1
bne $t0,$t1,loop
plz check it,thank
You can compile C to MIPS assembly and look at the output if it helps. The following C:
int main ()
{
int i;
int A[99], B[99], C[99];
for (i=0; i<98; i++) {
C[i] = A[i+1] - B[i+2] * A[1];
}
}
compiles with my compiler to this MIPS code
.file 1 "loop.c"
# -G value = 8, Cpu = 3000, ISA = 1
# GNU C version cygnus-2.7.2-970404 (mips-mips-ecoff) compiled by GNU C version cygnus-2.7.2-970404.
# options passed: -msoft-float
# options enabled: -fpeephole -ffunction-cse -fkeep-static-consts
# -fpcc-struct-return -fcommon -fverbose-asm -fgnu-linker -msoft-float
# -meb -mcpu=3000
gcc2_compiled.:
__gnu_compiled_c:
.text
.align 2
.globl main
.ent main
main:
.frame $fp,1232,$31 # vars= 1208, regs= 2/0, args= 16, extra= 0
.mask 0xc0000000,-4
.fmask 0x00000000,0
subu $sp,$sp,1232
sw $31,1228($sp)
sw $fp,1224($sp)
move $fp,$sp
jal __main
sw $0,16($fp)
$L2:
lw $2,16($fp)
slt $3,$2,98
bne $3,$0,$L5
j $L3
$L5:
lw $2,16($fp)
move $3,$2
sll $2,$3,2
addu $4,$fp,16
addu $3,$2,$4
addu $2,$3,808
addu $3,$fp,28
lw $4,16($fp)
move $5,$4
sll $4,$5,2
addu $3,$3,$4
addu $4,$fp,432
lw $5,16($fp)
move $6,$5
sll $5,$6,2
addu $4,$4,$5
lw $5,0($4)
lw $4,28($fp)
mult $5,$4
lw $3,0($3)
mflo $7
subu $4,$3,$7
sw $4,0($2)
$L4:
lw $2,16($fp)
addu $3,$2,1
sw $3,16($fp)
j $L2
$L3:
$L1:
move $sp,$fp # sp not trusted here
lw $31,1228($sp)
lw $fp,1224($sp)
addu $sp,$sp,1232
j $31
.end main

Resources