Overview of program: Input of a number 1-26, give the corresponding Capital letter too the number
My logic: Set up an Array type "structure" using .byte with chars. have a counter going through the array. once the counter is equivenlt to the input number print out the current point at the array.
This is a homework assignment so I'm not trying to "nudge" out the answer but guidance would be very helpful.
This is why where I think its going wrong. When I add 1 to the address it for some reason gives me a error. But when i add 4 it works fine? A char is supposed to take only 1 bit correct? I understand that when indexing address's of ints in an array it should be by 4.
.data
prompt: .asciiz "Enter the value of n here: "
larray: .byte 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
.globl main
.text
main:
la $t1, larray # Loads Array addresss into $t1
li $v0, 4 # System call for Print String
la $a0, prompt # Load address of prompt into $a0
syscall # Print the prompt message
li $v0, 5 # System call code for Read Integer
syscall # Read N into $v0
move $t3, $v0
li $t0, 0 # Loads int 0 into $t0
loop:
beq $t0, $t3, end # Break
lw $a0, ($t1) # Loads current pointer
addi $t0, $t0, 1 # Adds one to $t0 (Counting up +1)
addi $t1, $t1, 1 # Advances to next address in the array
j loop
end:
li $v0, 11 # Print at current index
syscall
li $v0, 10 # return control to system
syscall
I did do research on how to access the char a different way, but I don't think I can implement this way because you would need it hard coded?
Link:
This is the Stack Link that I found
There's no need for the array or the loop. If all you want to do is find the corresponding capital letter for a single number in the range 1-26, this would suffice:
li $v0, 5 # System call code for Read Integer
syscall # Read N into $v0
addiu $v0,$v0,'A'-1 # Convert the number 1-26 to the character 'A'-'Z'
A char is supposed to take only 1 bit correct?
One byte.
When I add 1 to the address it for some reason gives me a error. But when i add 4 it works fine?
You're using the lw instruction, which loads one word (4 bytes). To load a single byte, use the lb or lbu instruction (lb is for signed bytes, lbu for unsigned).
Related
.data
spaceChar: .asciiz " "
#array of 26 elements 1,0,0,0,0 elements = 5*5
array: .word 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
size: .word 25
endl: .asciiz "\n"
.text
main:
lw $t3, size
la $t1, array # get array address
li $t2, 0 # set loop counter
print_loop:
beq $t2, $t3, print_loop_end # check for array end
li $t5,4 #at 4th element I want next line
beq $t5,$t2,newline #checking..
lw $a0, ($t1) # print value at the array pointer
li $v0, 1
syscall
la $a0, spaceChar # Display a space character between elements
li $v0, 4
syscall
addi $t2, $t2, 1 # advance loop counter
addi $t1, $t1, 4 # advance array pointer
j print_loop # repeat the loop
print_loop_end:
li $v0,10
syscall
newline:
la $a0,endl
li $v0,4
syscall
j print_loop
Im trying to print a 5*5 matrix in MIPS This is a 1 dimensional array in mips of 25 elements, Im traversing through the elements in print_loop and when it hits the 4th element I want to do next line but when I run this (MARS 4.5) is freezing I dont know what Im doing please help
Short answer:
You're infinitely looping on newline.
Long answer:
The problem is
beq $t5, $t2, newline #checking
Once your counter gets 4, it keeps going to newline
newline:
la $a0, endl
li $v0, 4
syscall
j print_loop
Then it goes back to print_loop
print_loop:
beq $t2, $t3, print_loop_end #check for array end
li $t5, 4 #at 4th element I want next line
beq $t5, $t2, newline #checking
Uh-oh. We're back to our beq again! If you use the step-by-step debugger (the green arrow with a 1 next to the green arrow that runs), you'll see that you print the first row and then infinitely print newlines. Looks to me like you could just add another label in there after that beq.
In the future, I'd suggest commenting every single line and dividing code into chunks that complete objectives. For example:
# print value at the array pointer
lw $a0, ($t1) # print array[index]
li $v0, 1 # syscall: print integer
syscall
# print space
la $a0, spaceChar # print character " "
li $v0, 4 # syscall: print string
syscall
It's tedious, but it'll helps you sniff out bugs when everything is written in pseudocode. (plus, when someone asks a MIPS question on stackoverflow that you want to answer in a couple years, it helps you remember what the commands do! :P)
Oh, and you can just do
beq $t2, 4, newline
instead of
li $t5, 4
beq $t5, $t2
MIPS can be tricky. Just take it slow and document EVERYTHING. Good luck!
First of all, I have already checked related questions to this one, yet I am still not able to overcome the problem I have with this program.
What I am trying to do is, basically, take a byte[] input and duplicate it to another byte[], and print the duplicate array. My code is as above:
.data
hello: .asciiz "hello"
inp: .byte 5
dup: .byte 5
.text
main:
la $a0, inp #get input
li $v0, 8
syscall
la $s0, dup #load arrays on s0 and s1
la $s1, inp
li $t0, 0 #instantiate offsets as 0
li $t2, 0
Load:
lb $t1, 0($s1) #load first byte
sub $t1, $t1, 48 #test if it is <0
bltz, $t1, exit #if so go to exit
add $t1, $t1, 48
sb $t1, 0($s0) #else save the byte
add $s1, $s1, 1 #increment offsets
add $s0, $s0, 1
j Load
la $a0, hello
li $v0, 4
syscall
exit:
li $t1, 0
add $s0, $s0, 1
sb $t1, 0($s0) #add null to the end of dup
la $a0, dup
li $v0, 4
syscall
jr $ra
I am new to MIPS and, I am not able to recognize what the problem is.
By the way, I am passing 123 as an input and I am getting countless of 1s as output, which tells me that I am stuck in the loop and never getting any further in $s1 (inp).
There are a couple of problems with your code:
First, .byte 5 doesn't reserve space for 5 bytes, it declares a single byte with the value 5. If you want 5 bytes you should say .space 5 (the bytes will be initialized with the value 0 IIRC).
Second, syscall 8 takes one more argument; $a1 = maximum number of characters to read, which you haven't specified. If you have room for 5 bytes in your buffer you should set $a1 to 5. Note that "maximum number of characters to read" actually means "maximum number of characters to read including the terminating null-character".
For my assignment we are given an array of names and an array of integers which represent the ages of the corresponding names (this is basically a dictionary or a map). We are supposed to read in a string from the user, and if that name is in the array, then we print that persons age. Heres what I have so far:
.data
names: .asciiz "steve","john","chelsea","julia","ryan"
ages: .byte 20,25,22,21,23
out1: .asciiz "Please enter a name:"
out2: .asciiz "Age is: "
notfound: .asciiz "Not found!"
input: .asciiz
.text
li $v0, 4
la $a0, out1
syscall #prompts user for name
li $v0, 8
la $a0, input
li $a1, 20
syscall #Reads a name into address "input"
CheckNames: #needs to compare the input string with each element of "names" array and return 1 if they match
la $t0, (names)
la $t1, (input)
beq $t1, $t0, printAge
printAge:
I realize that my CheckNames function is wrong, but I don't know how to iterate through the array of names when each name differs in size (since I can't use an offset to get to the next name)
I faced this problem today. If it still helps you (or anybody else), I overcame this issue using the fact that .asciiz data in Assembly are an especial string of characteres that terminate themselves always with a special signal: NUL. The ASCII's table below could help ilustrate this:
ASCII Table
Keeping in mind that every character fills 8 bits (1 byte) of information, you can use these knowledge to go through all the bytes in the string's array and identify the end of each world by comparing the load byte with the $0 register (or a register with data equivalent with zero).
A pseudo-code is presented below to help you construct your own code:
move $a1, $s0 # $s0 register store the normal index of the string names(1), for example
li $t0, 0
li $t2, 0 # cont to know how many word did you pass
li $t1, maxSpace # maxSpace is that maximum space in the array
while ($t2<$t1) {
branch to "final", if $t1 == $a1
lb $t3, names($t0)
branch to "isnotNUL", if $t3 != $0
$t2 = $t2 + 1
$t0 = $t0 + 1
isnotNUL:
$t0 = $t0 + 1
}
# normal part of code to print a string .asciiz passing the start adress to $a0
final:
li $v0, 4
la $a0, names($t0)
syscall
jr $ra
There is just one problem with this method: the iteration could be very slow - specially if the array is big and the strings are also big. If this is your case and you don't want that, you could modify the code to save the numbers of bytes each string of the array has and construct a LUT (Look up table) with this information. So, you would run this function on the start of the program and when the time to print the information has come, you already know the adress you shuold start by loading the initial adress of the array and adding to it the number saved on the LUT.
.data
array: .word 0:5
prompt1: .asciiz "enter number: "
newline: .asciiz "\n"
.text
add $t2,$zero,$zero # initializes counter to 0
la $s0, array # stores the beginning of array into $s0
secretcode:
li $v0, 4 # prints "enter number: "
la $a0, prompt1
syscall
li $v0, 5 # reads in user input
syscall
sw $v0, ($s0) # saves user input into address at $s0
addi $s0, $s0, 4 # increments address at $s0 by 4 bytes
addi $t2, $t2, 1 # increments counter by 1
bne $t2, 5, secretcode # stops loop when loop executes 5 times
printsecretcode:
lw $a0, ($s0) # print first element
li $v0, 1
syscall
li $v0, 10 # system code halt
syscall
The program is supposed to store 5 user inputted numbers into an array. I tried to print the first value but it comes up as a large number which I assume is an address. How would I print the actual value of the number so that I know it saved correctly?
By the time you reach your printing code $s0 contains the address array + 4*5, so what you end up printing is the 32-bit number formed by the first four characters of the "enter number: " string.
To fix this, add an la $s0, array before you try to print the first element.
.text
main: la $a0, A #loads address of A into $a0
li $t0, 1 #loads 1 into $t0
sw $t0, ($a0) #stores word from $a0 into $t0
li $t0, 2 #loads 2 into $t0
sw $t0, 4($a0)
li $t0, 3
sw $t0, 8($a0)
li $t0, 4
sw $t0, 12($a0)
la $a1, A
li $v0, 1
lw $a0, ($a1)
syscall
lw $a0, 4($a1)
syscall
lw $a0, 8($a1)
syscall
lw $a0, 12($a1)
syscall
la $a0, tab
li $v0, 4
syscall
li $v0, 10
syscall
.data
A: .space 16 #array size 16
tab: .asciiz "\t" #makes line indentation
#stores 1 - 4 into $t0
From what I can see, it loads the address of A into a0, then it loads '1' into $t0, then it overrides?!? $t0, by storing the array into it., then loads 2 into $t0, then I'm unsure what the 4 is supposed to do(doesn't do anything as far as I can see, then loads $t0 into 3, then same as '4' don't don't see what 8 does, then loads 4 into $t0, then does something with 12, and then it loads address of A, into $a1, and prints it?!? I'm completely lost about the rest of the program. The program is correct,(loads "1234"), but I am supposed to learn MIPS, by understanding what each program the class lecturer gives. This isn't homework or anything, just learning how MIPS programs work.
The program first stores the constants 1, 2, 3, 4 starting at the address of A, and then it just prints the contents of those four words.
Instruction sw reg1, offset(reg2) stores the contents of the register reg1 into the address pointed by reg2 plus the optional offset specified.
So, in your first example sw $t0, ($a0) will store the contents of $t0 in the address pointed by $a0, which in your case is the address of label A.
It then uses multiples of 4 as the offset because you are storing words and each word occupies exactly 4 bytes, therefore to store the numbers 1, 2, 3, 4 at consecutive words you have to add 4 to each previous address.
It appears to be an unrolled loop. The first loop sets the content of the array and the second loop prints out the contents of the array followed by a tab. Here's what I would assume the pseudo code would look like:
function main()
{
i = 1
while( i <= 4 )
{
A[i-1] = i
i = i + 1
}
i = 1
while( i <= 4 )
{
printToConsole( A[i-1] )
i = i + 1
}
printToConsole( tab )
}
When the code was assembled, the assembler possibly unrolled the loop as a performance improvement.