Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have code in assembly form and I want to transform it to ะก code. So far I am aware of the fact that A decoder is needed. I have download the rtdec but I can not understand how to use it in order to transform the code.
The code is :
.data
A:
.word 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
.word 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.word 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
B:
.word 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
.word 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
.word 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
C:
.word
.text
li $8, 0
li $9, 0
li $15, 16
li $16, 4
la $10, A
la $11, B
la $12, C
again:
lw $13, 0($10)
lw $14, 0($11)
add $13, $13, $14
sw $13, 0($12)
addi $10, $10,4
addi $11, $11,4
addi $12, $12,4
addi $9, $9,1
blt $9, $15, again
li $9,0
addi $8, $8,1
blt $8, $16, again
li $v0, 10
syscall
The code uses three registers - $10, $11, and $12 - as the current position pointers in the three arrays A, B, and C. Here's the init sequence:
la $10, A
la $11, B
la $12, C
So $10 follows A, $11 follows B, and $12 follows C. Let's see what else happens to those registers:
lw $13, 0($10) loads the word that $10 is pointing at (the one from A)
lw $14, 0($11) loads the word that $11 is pointing at (the one from B)
sw $13, 0($12) stores a register into C
Finally, all three registers are increased by the word size, which is 4:
addi $10, $10,4
addi $11, $11,4
addi $12, $12,4
That is "move on to the next array element in A, B, and C" logic.
Related
I have a question as follows:
Given an array of 32-bit signed integers in the memory and its length in one of the registers, write a MIPS program that counts how many zeros the array contains. Assume that the array starts at Ox12345678, and the length of the array is already stored in $1. The number of zeros should be stored in $2, which mayor may not be initialised with zero at the beginning. Refer to Table 1 for MIPS assembly instructions.
Here is where I have got to in my own head but I have one main question:
1) I think that if I have subroutines, I need to be pushing and then popping data from a stack by using sw $ra, 4($sp) and addi $sp,$sp,-8and sw $fp, 0($sp). However, using my program, I have a break clause which only moves to a subroutine on a condition (if something is $0). So I don't jal to the subroutine, I beq to the subroutine. How can I modify my code to do this?
Here is my current code:
Add $3, $0, $0 #Set a counter to 0, the start of the array
Lui $4, 0x1234
Ori $4, $4, 0x5678 #Store register $4 to start of the array so you can offset
Add $2, $0, $0 #Sets $2 to $0 which is the total number of zeros
Start_for: Beq $3, $1, end_for #If counter is equal to the array length, go to end
Lw $5, 0x0($4) Load the current value of array into temp register $5
Addi $4, $4, 4 #Increment array pointer to next value
Beq $5, $0, increment #Increment the sum by 1 if the array[i] is zero
Addi $3, $3, 1 #Increment counter by 1
J start_for
increment:
Addi $2, $2, 1 #Increment the number of zeros by 1 and add to sum
Jr $ra
End_for: Lui $8, 0xffff
Ori $8, $8, 0xf004 Load the outtray into $8
Lw $8, 0x0($2) Store the number of zeros in the array to the outtray
I want to write code that has a public C interface, but is otherwise implemented entirely in MIPS, mainly as a learning exercise. However, I'm stuck fighting GAS because it seems to assume it knows better than I do.
To illustrate, let's say I want to implement the following in MIPS:
int bar(void)
{
return (4 / 2);
}
As I mentioned above, I want to be able to call ASM routines from C, so we'll need a C code file, bar.c, as well as the MIPS assembly in bar.S.
bar.c:
extern int bar(void);
void _start()
{
int foo = bar();
}
bar.S:
.global bar .text
bar:
addi $2, $0, 4
addi $3, $0, 2
div $2, $3
mflo $2
jr $31
addu $3, $0, $0
mipsel-none-elf-gcc bar.c bar.S -o bar.elf -ffreestanding -nostdinc -nostdlib successfully compiles this, but mipsel-none-elf-objdump -d bar.elf shows that GAS is messing with my bar() code:
00400050 <bar>:
400050: 20020004 addi v0,zero,4
400054: 20030002 addi v1,zero,2
400058: 14600002 bnez v1,400064 <bar+0x14>
40005c: 0043001a div zero,v0,v1
400060: 0007000d break 0x7
400064: 2401ffff li at,-1
400068: 14610004 bne v1,at,40007c <bar+0x2c>
40006c: 3c018000 lui at,0x8000
400070: 14410002 bne v0,at,40007c <bar+0x2c>
400074: 00000000 nop
400078: 0006000d break 0x6
40007c: 00001012 mflo v0
400080: 00001012 mflo v0
400084: 03e00008 jr ra
400088: 00000000 nop
40008c: 00001821 move v1,zero
I don't want the division checks, or delay slot fixups, or the assembler being "helpful" in any way here: I'm perfectly capable of handling those things myself if necessary. How do I tell GAS to just be a dumb assembler?
This one was solved in the comments. GAS accepts a 3-operand version of div where division checks are disabled if the first operand is $0. As for the delay slot, a .set noreorder directive prevents reordering of instructions (duh). Changing the assembly to:
.set noreorder
.global bar .text
bar:
addi $2, $0, 4
addi $3, $0, 2
div $0, $2, $3
mflo $2
jr $31
addu $3, $0, $0
produces the correct output:
00400050 <bar>:
400050: 20020004 addi v0,zero,4
400054: 20030002 addi v1,zero,2
400058: 0043001a div zero,v0,v1
40005c: 00001012 mflo v0
400060: 03e00008 jr ra
400064: 00001821 move v1,zero
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
Our team is trying to create a compiler that's fed code and produces MIPS assembly from it.
To tackle array declaration at the global scope, we create a label for the array in .text and reserve 4 bytes to hold the address pointing to the start of the array in memory.
.text
arr: .space 4
.data
...
li $t0, N # (where N = number of elements in arr)
li $v0, 9 # Load system instruction to allocate dynamic memory
li $t1, 4 # 4 bytes per element
mult $t0, $t1 # Calculates how big the allocated memory has to be in bytes.
mflo $a0 # Loads this value into $a0
syscall # Allocates memory and returns address into $v0
la $s0, arr # load address of arr into $s0
sw $v0, ($s0) # Save allocated memory address into the space reserved in .text
However, the last instruction doesn't seem to be working properly for us.
This image shows exactly where the error occurs and the state of the registers at that time. I'm unsure why it's causing an error.
Edit: some more information on the error produced, updated to encompass the modified instructions at the end
[00400000] 8fa40000 lw $4, 0($29) ; 183: lw $a0 0($sp) # argc
[00400004] 27a50004 addiu $5, $29, 4 ; 184: addiu $a1 $sp 4 # argv
[00400008] 24a60004 addiu $6, $5, 4 ; 185: addiu $a2 $a1 4 # envp
[0040000c] 00041080 sll $2, $4, 2 ; 186: sll $v0 $a0 2
[00400010] 00c23021 addu $6, $6, $2 ; 187: addu $a2 $a2 $v0
[00400014] 0c100009 jal 0x00400024 [main] ; 188: jal main
[00400018] 00000000 nop ; 189: nop
[0040001c] 3402000a ori $2, $0, 10 ; 191: li $v0 10
[00400020] 0000000c syscall ; 192: syscall # syscall 10 (exit)
[00400024] 34080003 ori $8, $0, 3 ; 9: li $t0, 3 # Load immediate value into register $t0
[00400028] 34020009 ori $2, $0, 9 ; 10: li $v0, 9
[0040002c] 34090004 ori $9, $0, 4 ; 11: li $t1, 4
[00400030] 01090018 mult $8, $9 ; 12: mult $t0, $t1
[00400034] 00002012 mflo $4 ; 13: mflo $a0
[00400038] 0000000c syscall ; 14: syscall
[0040003c] 3c101001 lui $16, 4097 [arr0] ; 15: la $s0, arr0
[00400040] ae020000 sw $2, 0($16) ; 16: sw $v0, ($s0)
PC = 400040
EPC = 40003c
Cause = 1c
BadVAddr = 1004002f
Status = 3000ff12
The last instruction sw $v0, arr0($0) = MEM[$0 + arr0] = $v0 which isn't correct. However you'll be given the amount of memory requested and it is needed to save that memory pointer in a register until scope of program. The assignment might look like this,
arr: .space 4
syscall # Allocates memory and returns address into $v0
la $s0, arr # arr is pointer address
st $v0, 0($s0) # start base address of array
Now arr is base address of 4 bytes of memory holding the address of memory content. For good practice it is important to de-allocate the memory assigned back to OS as,
li $v0,10 # return back to OS
syscall
I needed to translate the follwing C code to MIPS64:
#include <stdio.h>
int main() {
int x;
for (x=0;x<10;x++) {
}
return 0;
}
I used codebench to crosscompile this code to MIPS64. The following code was created:
.file 1 "loop.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 1
.abicalls
.option pic0
.text
.align 2
.globl main
.set nomips16
.set nomicromips
.ent main
.type main, #function
main:
.frame $fp,24,$31 # vars= 8, regs= 1/0, args= 0, gp= 8
.mask 0x40000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-24
sw $fp,20($sp)
move $fp,$sp
sw $0,8($fp)
j $L2
nop
$L3:
lw $2,8($fp)
addiu $2,$2,1
sw $2,8($fp)
$L2:
lw $2,8($fp)
slt $2,$2,10
bne $2,$0,$L3
nop
move $2,$0
move $sp,$fp
lw $fp,20($sp)
addiu $sp,$sp,24
j $31
nop
.set macro
.set reorder
.end main
.size main, .-main
.ident "GCC: (Sourcery CodeBench 2012.03-81) 4.6.3"
To check if the code works as expected, I usually use the WINMIPS64 simulator. For one or other reason this simulator does not want to accept this code. It appears that every line of code is wrong. I have been looking at this issue for over a day. I hope someone can help me out with this. What is wrong with this assembly code for the mips64 architecture?
From page 7 of the WINMIPS64 documentation:
The following assembler directives are supported
.data - start of data segment
.text - start of code segment
.code - start of code segment (same as .text)
.org <n> - start address
.space <n> - leave n empty bytes
.asciiz <s> - enters zero terminated ascii string
.ascii <s> - enter ascii string
.align <n> - align to n-byte boundary
.word <n1>,<n2>.. - enters word(s) of data (64-bits)
.byte <n1>,<n2>.. - enter bytes
.word32 <n1>,<n2>.. - enters 32 bit number(s)
.word16 <n1>,<n2>.. - enters 16 bit number(s)
.double <n1>,<n2>.. - enters floating-point number(s)
Get rid of everything that's not in the above list, as it won't run in the simulator.
You'll need to move the .align to before .text
WINMIPS64 expects daddi/daddui instead of addi/addiu, again as per the documentation.
As per the documentation, move $a, $b is not a supported mnemonic. Replace them with daddui $a, $b, 0 instead.
slt needs to be slti.
Finally, the simulator expects an absolute address for j, but you've given it a register. Use jr instead.
At this point I get an infinite loop. This is because the stack pointer doesn't get initialized. The simulator only gives you 0x400 bytes of memory, so go ahead and initialize the stack to 0x400:
.text
daddui $sp,$0,0x400
Now it runs. Since you're running the code by itself, nothing will be in the return register and the final jr $31 will just bring it back to the beginning.
Here's my version:
.align 2
.text
daddui $sp,$0,0x400
main:
daddui $sp,$sp,-24
sw $fp,20($sp)
daddui $fp,$sp,0
sw $0,8($fp)
j $L2
nop
$L3:
lw $2,8($fp)
daddui $2,$2,1
sw $2,8($fp)
$L2:
lw $2,8($fp)
slti $2,$2,10
bne $2,$0,$L3
nop
daddui $2,$0,0
daddui $sp,$fp,0
lw $fp,20($sp)
daddui $sp,$sp,24
jr $31
nop
Consider getting either another compiler or another simulator, because these two clearly hate each other.