lui $v0,%hi(length)
lw $v1,%lo(length)($v0)
li $v0,3 # 0x3
bne $v0,$zero,1f
div $zero,$v1,$v0
break 7
mfhi $v0
mflo $v0
sw $v0,28($fp)
lw $a1,28($fp)
lui $v0,%hi(game_over)
addiu $a0,$v0,%lo(game_over)
jal printf
nop
When I try running this for my MIPS code, it comes up with this error:
Your program produced these errors:
spim: (parser) Unknown character on line 180 of file measurement.s
lui $v0,%hi(length)
spim: (parser) syntax error on line 181 of file measurement.s
Instruction references undefined symbol at 0x00400038
[0x00400038] 0x0c000000 jal 0x00000000 [init_measure] ; 159: jal init_measure
Do I need to substitute %hi and $lo for something else in the code?
EDIT For the following code:
sw $v0,16($fp)
lui $a0,%hi(grid)
lw $v1,12($fp)
nop
move $v0,$v1
sll $v0,$v0,4
subu $v0,$v0,$v1
addiu $v1,$a0,%lo(grid)
addu $v1,$v0,$v1
lw $v0,16($fp)
And
lui $v0,%hi(column)
lb $v0,%lo(column)($v0)
nop
sw $v0,12($fp)
lui $v0,%hi(column)
addiu $v1,$v0,%lo(column)
lw $v0,8($fp)
nop
addiu $v1,$v0,-1
lui $v0,%hi(growth)
sw $v1,%lo(growth)($v0)
b true
nop
Will I be substituting %hi and % lo it in a similar manner or differently?
Those seem to be operators not supported by spim. %LO(label) should give you the lowest half of the address of label, and %HI(label) the upper half.
You can substitute these two instructions:
lui $v0,%hi(length)
lw $v1,%lo(length)($v0)
with this:
la $v0,length
lw $v1,0($v0)
So we use la pseudoinstruction to load the whole address of the label onto a register (in the example $v0) then you directly load its memory contents using 0 as the lw offset. Note that la pseudoinstruction would use 2 instructions for an arbitrary label address (and leave $at with the upper half address).
Also note that in your code $v0 would still hold the upper half of the label address whereas in the second snippet it will contain the whole address.
Similarily, instead of
lui $v0,%hi(game_over)
addiu $a0,$v0,%lo(game_over)
you can just issue:
la $a0, game_over
In this case, your code would end with $a0 having the address of game_over label (as in the second snippet), and $v0 holding the lower half of that address. la pseudoinstruction will leave the upper half of the label on $at
Related
I've read through some Q&As about this error on here, but I still don't understand what it means. I have a code in which I try to calculate p(n, r) and I keep getting this error: "line 26: Runtime exception at 0x00400044: fetch address not aligned on word boundary 0x00000006". I don't understand how it's not aligned since to my own knowledge, I haven't manipulated the address.
# n and r are assumed to be integers and n > r
.data
textN: .asciiz "enter n: "
textR: .asciiz "enter r: "
.text
main:
li $v0, 4
la $a0, textN
syscall
li $v0, 6
syscall
move $t0, $v0
li $v0, 4
la $a0, textR
syscall
li $v0, 5
syscall
move $t1, $v0
move $a0, $t0
jal Factorial
la $t7, ($v0)
l.s $f0, ($t7) #line 26
sub $a0, $t0, $t1
jal Factorial
la $t7, ($v0)
l.s $f1, ($t7)
div.s $f12, $f0, $f1
li $v0, 2
syscall
jr $ra
Factorial:
beq $a0, 1, Exception
subi $sp, $sp, 8
sw $t0, ($sp)
sw $t1, 4($sp)
move $t0, $a0
move $v0, $a0
Loop:
subi $t0, $t0, 1
beq $t0, $zero, Exit
sub $t1, $a0, $t0
mul $v0, $v0, $t1
Exit:
lw $t0, ($sp)
lw $t1, 4($sp)
addi $sp, $sp, 8
jr $ra
Exception:
addi $v0, $v0, 1
jr $ra
At first, I hadn't included the la instruction and line 26 was l.s $f0, ($v0). I assumed that the current update to line 26 and 27 was what was missing, but the error I'm receiving has remained unchanged.
I think you're a bit confused about what parentheses really mean.
li $t0,8
move $t1,$t0 ;copy the number 8 from $t0 into $t1.
lw $t2,($t0) ;load the four bytes at memory address 0x00000008 into $t2
Essentially, parentheses around a register are the pointer star * in C, and la $t0, myLabel is the same as typename* ptr = &myLabel;. (I used li in the example above because a memory address is a number itself, but that's not usually what you would do if you really were dereferencing a pointer.)
Your function factorial is intended to return an int, so you don't want to dereference that value. Assembly has no type safety at all, and lets you treat any register as a pointer to memory at any time.
The actual source of your error message, however, has to do with a limitation of the MIPS CPU. Your input value for the factorial function was 3, right? I could tell by the error message. Rather than trying to copy the number 6 to $f1 (which wouldn't work for other reasons) you were trying to load the 4 bytes at memory address 0x00000006. This won't work, because MIPS can't use lw or sw to read/write 32-bit values at memory addresses that aren't aligned, i.e. not a multiple of 4. Trying to do so will result in a runtime error. But it's clear that's not what you wanted to do anyway.
For our coursework we had to write code in MARS to calculate the memory address of a given coordinate.
.globl main
.data
amountOfRows: .word 16 # The mount of rows of pixels
amountOfColumns: .word 32 # The mount of columns of pixels
promptRows: .asciiz "Please enter the row number:\n"
promptCols: .asciiz "Please enter the column number:\n"
msgShowMemoryAddress: .asciiz "The memory address for the pixel is:\n"
msgErrorValues: .asciiz "The entered value for row/column is invalid, please enter a valid value:\n"
.text
###################################################################################
translate_coordinates:
sw $fp, 0($sp) # push old frame pointer (dynamic link)
move $fp, $sp # frame pointer now points to the top of the stack
subu $sp, $sp, 20 # allocate 16 bytes on the stack
sw $ra, -4($fp) # store the value of the return address
sw $s0, -8($fp) # save locally used registers
sw $s1, -12($fp)
sw $s2, -16($fp)
move $s0, $a0 # $s0 = x coordinate
move $s1, $a1 # $s1 = y coordinate
move $s2, $a2 # $s2 = width for calculations
sll $t3, $s1, 5 # shift y left by 5 which is equal to multiplication of 32
add $t4, $t3, $s0 # (y * 32) + x = index of pixel
sll $t5, $t4, 2 # shift index left by 2 which is equal to multiplication of 4
add $t6, $gp, $t5 # memory address = gp + offset
move $v0, $t6 # place result in return value location
lw $s2, -16($fp) # reset saved register $s2
lw $s1, -12($fp) # reset saved register $s1
lw $s0, -8($fp) # reset saved register $s0
lw $ra, -4($fp) # get return address from frame
move $sp, $fp # get old frame pointer from current fra
lw $fp, ($sp) # restore old frame pointer
jr $ra
###################################################################################
main:
li $v0, 4 # print string
la $a0, promptRows # message to ask the user for the row number
syscall
li $v0, 5 # read integer
syscall # ask the user for a row number
move $t0, $v0
li $v0, 4 # print string
la $a0, promptCols # message to ask the user for the column number
syscall
li $v0, 5 # read integer
syscall # ask the user for a column number
move $t1, $v0
lw $t2, amountOfColumns #load amountOfColumns into $t2
move $a0, $t0 # Put procedure arguments
move $a1, $t1 # Put procedure arguments
move $a2, $t2
jal translate_coordinates # Call procedure
move $t6, $v0 # Get procedure result
move $a0, $t6
li $v0, 1 # syscall code 1 is for print_int
syscall
exit:
li $v0, 10 # syscall to end the program
syscall
I wrote this code to calculate the memory address of a pixel but whenever I run it I get this error:
Error in : invalid program counter value: 0x00000000
We had to use a stackframe for this and I'm quite new to that.
Because I'm quite new to it, it might be that I made some mistakes when it comes to that.
By default, MARS starts running the code at the start of .text, and since in your code the function comes before main, it is running the function without calling it properly.
There are three options:
add j main immediately after .text
use MARS option Settings -> Initialize Program Counter to global main if defined (off by default)
change the order so that main comes immediately after .text
I used 'compiler explorer' to convert c++ to MIPS
but it doesn't work well in the MARS because of %hi and %lo
I know I should change the part, but I don't know how to change...
Please help
$L5:
lui $2,%hi($LC1)
lwc1 $f0,%lo($LC1+4)($2)
lwc1 $f1,%lo($LC1)($2)
b $L3
$LC1:
.word 1100470148
.word 0
$L17:
lw $2,16($fp)
addiu $3,$2,1
sw $3,16($fp)
lui $4,%hi(savepath)
sll $3,$2,2
addiu $2,$4,%lo(savepath)
addu $2,$3,$2
li $3,1 # 0x1
sw $3,0($2)
move $sp,$fp
lw $fp,36($sp)
addiu $sp,$sp,40
j $31
AFAIK, there is no way in Mars to have something like the gas %lo(label) or %hi(label) feature.
A simple workaround is to use the standard macro la that loads a label in a register with a pair or lui/ori instructions.
The first part of your code can be rewritten like that:
$L5:
la $2, $LC1
lwc1 $f0,4($2)
lwc1 $f1,0($2)
b $L3
$LC1:
.word 1100470148
.word 0
As the la macro is expanded to two instructions,that is an extra instruction compared to the use of %hi/%lo but it works.
I am reading in two integers, the first must be between 1 and 7. The second must be between 1 and 7, and not less than the first. To check these number I am using a function and then returning either 1 or 0, which will repeat the input in a loop until a valid input is given.
Here is my problem: The first number seems to go in well, and it loops until a valid input is given. However for my second function, it's pretty much the same but I am using two arguments ($a0 for the first number and $a1 for the second). Whenever I run the program on QTSpim, it freezes immediately after entering the second integer. Can anyone help me?
Here is my code:
main:
li $v0,5
syscall
move $a0,$v0
jal checkdiv
move $s0,$a0
slt $t0,$zero,$v1
beq $t0,$zero,NE
j main
NE:
li $v0,5
syscall
move $a0,$v0
move $a1,$s0
jal checknum
#These are the two check functions
checkdiv:
addiu $sp,$sp,-8
sw $ra,4($sp)
sw $a0,0($sp)
li $t0,1
slt $v1,$a0,$t0
beq $v1,$t0,D1
li $t0,7
slt $v1,$t0,$a0
D1:
lw $ra,4($sp)
lw $a0,0($sp)
addiu $sp,$sp,8
jr $ra
#Second check function
checknum:
addiu $sp,$sp,-16
sw $ra,8($sp)
sw $a0,4($sp)
sw $a1,0($sp)
slt $v1,$a0,$a1
li $t0,1
beq $v1,$t0,N1
li $t0,7
slt $v1,$t0,$a0
N1: lw $ra,8($sp)
lw $a0,4($sp)
lw $a1,0($sp)
addiu $sp,$sp,16
jr $ra
Please refers to the edit portion for my explanation.
This is a bit long and difficult to illustrate. But I appreciate taking your time to read this. Please bear with me.
Suppose I have this:
.data
str1: .asciiz "A"
str2: .asciiz "1"
myInt:
.word 42 # allocate an integer word: 42
myChar:
.word 'Q' # allocate a char word
.text
.align 2
.globl main
main:
lw $t0, myInt # load myInt into register $t0
lw $t3, str1 # load str1 into register $t3
lw $t4, str2 #load str2 into register $t4
la $a0, str1 # load address str1
la $a1, str2 # load address str2
Then in SPIM, the user text segment is
User Text Segment [00400000]..[00440000]
[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] 3c011001 lui $1, 4097 ; 23: lw $t0, myInt # load myInt into register $t0
[00400028] 8c280004 lw $8, 4($1)
[0040002c] 3c011001 lui $1, 4097 ; 25: lw $t3, str1 # load str1 into register $t3
[00400030] 8c2b0000 lw $11, 0($1)
[00400034] 3c011001 lui $1, 4097 ; 27: lw $t4, str2 #load str2 into register $t4
[00400038] 8c2c0002 lw $12, 2($1)
[0040003c] 3c041001 lui $4, 4097 [str1] ; 29: la $a0, str1 # load address str1
[00400040] 3c011001 lui $1, 4097 [str2] ; 31: la $a1, str2 # load address str2
[00400044] 34250002 ori $5, $1, 2 [str2]
I understand that lw is a pseudocode so it needs to be broken down into two instructions. I understand this part. We use the entry address of data segment as a "base pointer" and relatively accessing other data (including the first data).
I also observed that loading address of str1 and str2 used two different registers: $4 and $1. $4 is $a0.
Why is that?
If I swap the last two instructions, on SPIM I see
...
[0040003c] 3c011001 lui $1, 4097 [str2] ; 31: la $a1, str2 # load address str2
[00400040] 34250002 ori $5, $1, 2 [str2]
[00400044] 3c041001 lui $4, 4097 [str1] ; 32: la $a0, str1 # load address str1
So why is load address so strange? Why did str2 use $1 ???
How can I go about explaining how lui $1, 4097 [str2] and lui $4, 4097 [str1] are different?
PS: Can someone also explain to me why we need the bracket [str2] ?
lui, $1, 4097, [str2] only pushes the entry address of data segment to register $1. That is, 0x10010000 .
Thank you very much!
EDIT
I rewrote the entire script to simplify the situation.
Script: http://pastebin.com/BHh89iqt
Text Segment: http://pastebin.com/t2eDEs1f
Let me remind you that we write in pseudo instructions, rather than true MIPS machine code. That is, "lw", "jal", "addi", etc are all pseudo instructions.
For example, lw (load word) is broken down into two machine instructions (look at the text segement):
lui $1, 4097 ; 23: lw $t0, myInt # load myInt into register $t0
lw $8, 4($1)
MIPS is 32-bit, we therefore break it down into two instructions. The total of addressing a 32-bit address will result in 43 bits instruction set.. this is why we break down into 2 parts.
A label is a memory address pointing at the thing we assigned to.
MIPS can only read instructions of the form lw $rt, offset($rs). So most of the load instructions follow this approach and use $at to convert pseudoinstructions that involve labels to MIPS machine instructions.
For lw it's pretty easy. For la load address it's a bit tricky.
Pay attention to the last four load address instructions. MIPS translates them into this:
[0040003c] 3c041001 lui $4, 4097 [str1] ; 27: la $a0, str1 # load address str2
[00400040] 3c011001 lui $1, 4097 [str2] ; 28: la $a0, str2 # load address str1
[00400044] 34240002 ori $4, $1, 2 [str2]
[00400048] 3c011001 lui $1, 4097 [str2] ; 30: la $a0, str2 # load address str2
[0040004c] 34240002 ori $4, $1, 2 [str2]
[00400050] 3c041001 lui $4, 4097 [str1] ; 31: la $a0, str1 # load address str1
$4 refers to $a0. If you look at the instructions, I swapped the first two load instructions and the result is the last two instructions.
I purposely did this to illustrate the strange behavior: before swapping, lui uses $4 to store the address of str1, but if I want to load the address of str2, I will use $at and then apply offset.
I couldn't figure out why last night, and just now, I realized that this is done because the compiler is smart enough to know that str1 is the first data in the data segement, so there is no need to convert anything.
Yet this is also strange because how does the compiler know at what byte to stop printing the string? (if we want to print a string...)
My guess: Null character to terminate print.
Anyhow. I guess this is just a convention that the MIPS uses.
Second Edit
In fact if you just add a new data on top of str1, you will see that
my explanation is correct.
New script: http://pastebin.com/8DuzFrk0
New Text Segment: http://pastebin.com/YXbvzc4z
I only added myCharB to the top of the data segment.
[0040003c] 3c011001 lui $1, 4097 [str1] ; 29: la $a0, str1 #
load address str2
[00400040] 34240004 ori $4, $1, 4 [str1]
[00400044] 3c011001 lui $1, 4097 [str2] ; 30: la $a0, str2 #
load address str1
[00400048] 34240006 ori $4, $1, 6 [str2]
I also observed that loading address of str1 and str2 used two
different registers: $4 and $1. $4 is $a0. Why is that?
Well, who cares? xD It's internal SPIM implementation and it's free to use any register as long as it does not break MIPS ABI. I just suggest you not relying too much on pseudo-instructions to make sure what registers have changed/what values they hold. Also usually LW is not a pseudo-instruction, but in the way you're using it is.
Can someone also explain to me why we need the bracket [str2] ?
You don't need any brackets. That's just a SPIM information to the programmer to show this instruction is loading the str2 address. It's not part of the assembly.
lui, $1, 4097, [str2] only pushes the entry address of data segment to
register $1. That is, 0x10010000
Well actually it only load upper half-word of $1. It just happens that the lower half-word is plain zeroes. Keep in mind LUI does not modify lower half-word, so you have to make sure it holds the value you want (reseting register or using LI).
Yet this is also strange because how does the compiler know at what
byte to stop printing the string? (if we want to print a string...)
Null-terminated, as you guessed right.
I guess this is just a convention that the MIPS uses.
This is way older than MIPS. And MIPS doesn't define anything about this, either does any other architecture. This is data handling and it's defined on a upper layer like OS. In this case it is SPIM convention on its own syscalls. Anyway null-terminated strings are pretty common. C programming language uses so for strings.