im a newbie in MIPS and still scratching some basic commands, currently i bumped into a very strange situation, where i have 2 identical code but one runs, and the other doesnt.
This is the code that throw an exception when running at line sw $v0, input:
.data
Text_output1: .asciiz "Input number 1: "
input: .word
.text
main:
li $v0, 4
la $a0, Text_output1
syscall
li $v0, 5
syscall
sw $v0, input
li $v0, 1
lw $a0, input
add $a0, $a0, 1
syscall
This is the normal functioning one:
# Program: Hello, World!
.data
# data declaration section; specifies values to be stored
# in memory and labels whereby the values are accessed
Greeting: .asciiz "\nghfhgfhgf\n"
Text_output1: .asciiz "Number 1 : "
input: .word
.text # Start of code section
main: # Execution begins at label "main"
li $v0, 4 #in ra number 1 :
la $a0, Text_output1
syscall
li $v0, 5
syscall
sw $v0, input
li $v0, 1
lw $a0, input
add $a0, $a0, 1
syscall
I cannot see any difference between the twos, or is there something i dont know about this language?
Btw im using MARS 4.5 with JDK 13. Thank you so much.
If you're writing any MIPS assembly, you should get the official instruction set reference (MIPS32™ Architecture For Programmers
Volume II: The MIPS32™ Instruction Set).
For the sw instruction it states the following:
Restrictions:
The effective address must be naturally-aligned. If either of the 2 least-significant bits of the address is non-zero, an
Address Error exception occurs.
As the simulator clearly states, you have an sw instruction at address 0x0040001c that tries to write to address 0x10010011, which is not a word-aligned address.
Your second example happens to work out of pure luck, because your two strings occupy 24 bytes of memory, so the input label ends up 24 bytes from the start of the .data section, which is a word-aligned address.
To ensure proper alignment, use the .align directive, e.g.:
.align 2
input: .word 0
Also note the 0 after .word. If you leave out the initial value and just write .word you will run into problems if you add more variables (they will all get the same address).
Related
For a project, I need to allocate space for an array of half-words which is supplied by the user. Thus far, I have:
.data
get_size: .asciiz "Enter array size: "
myArray: .space $s0
.text
li $v0, 4
la $a0, get_size
syscall # Print get size message
li $v0, 5
syscall # Put array size into $v0
mul $s0, $v0, 2 # Multiply $v0 by element size to reserve memory space
However, this throws an error at the myArray .space $s0 line. Whenever I hardcode in a value after .space the program works fine, but I specially need to calculate the space to allocate based on whatever the user give me.
i am currently learning MIPS and i have a question about MIPS. As the question title, is it possible to print a value that is inside a storage that declared with ".word"
EX:
.data
var1: .word 3
.text
.globl main
main:
li $v0, 4
la $a0, var1
syscall
So is it possible for it to printed about the value 3 from var1?
Sure, just load the word from that address:
la $a0, var1
lw $a0, ($a0)
Or, if you wanted to, you could replace those two instructions with a single lw:
lw $a0, var1
Note that this is a pseudo-instruction, which the assembler will translate into 1 or more actual instructions. So you're not gaining anything at the machine code level, but your assembly code will be more compact.
This code is part of a much bigger program that worked just fine. Then I realized the assignment would be tested in -bare mode. As soon as I tried running it in -bare mode my print_string syscalls went from working fine to not printing anything and I have no idea why.
Running this gives me no errors it just doesn't print anything
(also are the 2 or $0,$0,$0 necessary at the end?)
.globl main
.data
v: .space 2
w: .space 2
x: .space 2
y: .space 2
z: .space 2
inputPrompt: .asciiz "Input mathmatical expression: "
.text
main: #main block used to read in all the necessary data
lui $a0, 0x1001
#prompt for expression
addi $v0, $0, 4
addi $a0, $a0, 10
syscall
or $0,$0,$0
jr $ra
or $0,$0,$0
This is the problem:
lui $a0, 0x1001
If you look at the addresses in the DATA/STACK viewer in SPIM, you'll see that when you're in bare mode the DATA section starts at 0x10000000 instead of 0x10010000. So you should change that lui to lui $a0, 0x1000.
are the 2 or $0,$0,$0 necessary
Bare mode implies that branch delay slots are simulated. So you should fill any branch delay slots with instructions that are safe to execute there. That could be NOPs, or more meaningful instructions if you manage to reorganize your code. For example, if you had:
ori $a0,$0,1
jal foo
you could've changed that into:
jal foo
ori $a0,$0,1 # will be executed in the delay slot
Note that syscall doesn't have any delay slot. From MIPS32™ Architecture For Programmers
Volume II: The MIPS32™ Instruction Set:
Format: SYSCALL
Description:
A system call exception occurs, immediately and unconditionally transferring control to the exception handler
I am trying to compute the length of a string given by a user. Every time I try to run the code, I get the message "Exception occurred at PC=(a certain address) followed by the message :"Bad address in Data/stack read: (another address). I know that it has something to do with the stack but I can't figure out the problem. The code in MIPS is bello and I am using QtSpim. Your help will be very appreciated.
sentence: .space 6
Prompt: .asciiz "Enter the sentence. Max 6 characters, plus a terminator .\n"
.text # Start of code section
main: # The prompt is displayed.
li $v0, 4 # system call code for printing string = 4
la $a0, Prompt # load address of string to be printed into $a0
syscall # call operating system to perform operation;
# $v0 specifies the system function called;
# syscall takes $v0 (and opt arguments)
##read the string, plus a terminator, into the sentence
la $t0, sentence
li $t0, 6
li $v0, 8
add $v0, $zero, $zero #initialize length to zero
loop:
lbu $s0, 0($t0) #load one character of string
addi $t0,$t0,1 #point to next character
addi $v0,$v0,1 #increment length by 1
bne $s0,$zero, loop #repeat if not null yet
end_loop:
addi $v0, $v0, -1 #don't count the null terminator
li $v0, 4 #display the actual length
syscall
exit: #exit the program
li $v0, 10
syscall
##read the string, plus a terminator, into the sentence
la $t0, sentence
li $t0, 6
Here you're loading the address of sentence into $t0, and then immediately overwrite $t0 with the value 6. This is probably the root cause of the exception, since the following lbu will attempt to read from address 0x00000006. I suggest that you remove the li.
li $v0, 8
add $v0, $zero, $zero #initialize length to zero
This li is pointless since you're setting $v0 to zero on the very next line, so this li can also be removed.
sentence: .space 6
Prompt: .asciiz "Enter the sentence. Max 6 characters, plus a terminator .\n"
You say that the user is allowed to enter up to 6 characters. But you only allocate space for 6 bytes, meaning that the NULL terminator wouldn't fit if the user actually enters 6 characters.
I'm working on a mips program that will run on pcspim and i need a little help. The description of the program is: Write a program that reads a string (from a keyboard), stores it in the memory, and computes and prints the frequency of each character; and then it reverses the string and prints the reversed string.
so far i have is...
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newLine: .asciiz "\n"
.text
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
li $v0, 8
la $a0, userString
li $a1, 256
syscall
jr $ra
la $a0, userString
move $t0, $a0
lb $t1, 0($t0)
li $v0, 4
move $a0, $t1
syscall # prints first letter of word
Right now i just wanted to see if i've actually stored the input into the userString array. So at the end i tried to print out the first letter. but it doesnt seem to be printing anything.
Any suggestion?
thank.
I've broken your code down into three parts: prompting, input, display. I assume the first two parts were given to you and the third is what you are focusing on right now. I'll explain what the first to parts are doing then explain what the third is doing right now and what you probably want it to do at this point.
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newLine: .asciiz "\n"
.text
# Part I
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
# Part II
li $v0, 8
la $a0, userString
li $a1, 256
syscall
jr $ra
# Part III
la $a0, userString
move $t0, $a0
lb $t1, 0($t0)
li $v0, 4
move $a0, $t1
syscall # prints first letter of word
Part I
This is pretty straightforward, when we start executing the program counter will be set to the address of the main label. It loads the value 4 into $v0 (that seems to be the print string system call number), and then loads the address of the Prompt string into the first argument register $a0. The last bit just performs the system call that puts the string on the screen.
Part II
Now that the "Enter a word: " string has been printed on screen, we want to actually read what the user is typing. It looks like here we're using system call #8 (probably read string), so we load that value into $v0 in preparation for the syscall. Then, since we want to read the user string into userString, we load the address of that label into $a0 (the first argument for the read string function) then, since we are savvy programmers, we give the upper bound of how many bytes userString can hold (256) in $a1. Then we perform the system call, you type in a string at the keyboard and hit enter and we return to the next line of code.
That line is jr $ra, which means "jump to the location stored in register $ra (return address)". You probably don't want this, because it marks the end of the main function and likely you program exits back to the command line at this point, probably best to remove it.
Part III
Again, you're loading the address of userString into $a0 (and also moving it into $t0 in the next line). Now it gets weird, you load the first byte 0($t0) of userString into $t1. This is a ASCII character value (like 72 or something). Then you start up the system call stuff again with the print string system call (#4) and the argument of $t1. Which you think will print the first letter of the word, which I disagree with. Here's why. If the user types the string, "Hello, world!" this is what it looks like in memory:
userString: H e l l o , w o r l d !
offset: 0 1 2 3 4 5 6 7 8 9 10 11 12
So, loading 0($t0) moves the letter H into register $t1, then when you perform the system call it tries to print the string starting at H to the screen. However, there is not a string starting at letter H, it starts at the address of userString. So if you just move the address of userString into register $a0, then do system call #4 it should print userString to the screen.
#mjshultz
i've changed it up a little. Didnt think i needed 2 loops. Also i've increment it by four because i thought each character is 4 bytes so to go to the next letter i need to increment the offset by four.
.data # Data declaration section
userString: .space 256
Prompt: .asciiz "\nEnter a word: "
newSpace: .asciiz " "
newLine: .asciiz "\n"
.text
main: # Start of code section
li $v0, 4
la $a0, Prompt
syscall
la $a0, userString
li $a1, 256
li $v0, 8
syscall
la $a0, userString
move $s0, $a0
loop:
lb $t1, 0($s0)
li $v0, 1
move $a0, $t1
syscall
li $v0, 4
la $a0, newSpace
syscall
addi $s0, $s0, 4
blt $s0, 256, loop