So i have an array, that is filled previously with 1's or 0's, whenever i try to compile this code MIPS gives me a syntax error, could someone explain what this syntax error is? I'm having trouble understanding why you can't access the array like that, of course $t1 is a counter for the index, which increments up through 100
slti $t7, prim_flag($t1), 1 # checks if prim_flag ($t1) < 1 stores 1 if so stores 0 if not
beq $t7, 0, print_numbers # checks if the value in $t7 is 0, if so jump to end_game
and the array:
.data
test: .asciiz "Printing numbers:"
test_2: .asciiz "Before loop"
space: .asciiz " "
done: .asciiz "\n Done printing the array"
numbers:
.word 0:210
numbers_size:
.word 210
prim_flag:
.word 1:210
The only valid operand combination for slti is register,register,immediate. You're trying to use register,memory,immediate, and there's simply no such version of slti in the MIPS instruction set.
Practically every time you need to perform an operation on some data in memory in MIPS assembly, you first have to load that data into a register using lb/lh/lw; then you can perform the operation you need on that register; and finally write some result back to memory if necessary.
Also note that the constant to the left of the parentheses in prim_flag($t1) is an offset, not the base address. The base address is the part that's inside the parentheses, and has to be a register. And since the offset has to fit in 16 bits due to how MIPS instructions are encoded, it's possible that prim_flag won't fit. So you might have to load the address of prim_flag into some register, then add that register plus $t1 and store the sum in a third register, and then read from memory using that last register as the base address.
Related
I'm learning assembly code, and given this code, I need to find what this code is about. However I am trying to debug using qtspim. I know what the value inside each register, but I still don't get what is this code about.
If you find the pattern and what this code about, can you tell me how can you do it, and in what line you know the pattern? thanks!
.text
.globl main
.text
main:
li $s0, 0x00BEEF00 ##given $s0= 0x00BEEF00
Init:
li $t0, 0x55555555
li $t1,0x33333333
li $t2,0x0f0f0f0f
li $t3,0x00ff00ff
li $t4,0x0000ffff
Step1: and $s1, $s0, $t0
srl $s0,$s0,1
and $s2,$s0,$t0
add $s0,$s1,$s2
Step2: and $s1,$s0,$t1
srl $s0,$s0,2
and $s2,$s0,$t1
add $s0,$s1,$s2
Step3: and $s1,$s0,$t2
srl $s0,$s0,4
and $s2,$s0,$t2
add $s0,$s1,$s2
Step4: and $s1,$s0,$t3
srl $s0,$s0,8
and $s2,$s0,$t3
add $s0,$s1,$s2
Step5:
and $s1,$s0,$t4
srl $s0,$s0,16
and $s2,$s0,$t4
add $s0,$s1,$s2
End:
andi $s0,$s0,0x003f
enter image description here
enter image description here
mips explain
This is a population count, aka popcount, aka Hamming Weight. The final result in $s0 is the number of 1 bits in the input. This is an optimized implementation that gives the same result as shifting each bit separately to the bottom of a register and adding it to a total. See https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
This implementation works by building up from 2-bit accumulators to 4-bit, 8-bit, and 16-bit using SWAR to do multiple narrow adds that don't carry into each other with one add instruction.
Notice how it masks every other bit, then every pair of bits, then every group of 4 bits. And uses a shift to bring the other pair down to line up for an add. Like C
(x & mask) + ((x>>1) & mask)
Repeating this with a larger shift and a different mask eventually gives you the sum of all the bits (treating them all as having place-value of 1), i.e. the number of set bits in the input.
So the GNU C representation of this is __builtin_popcnt(x).
(Except that compilers will actually use a more efficient popcnt: either a byte lookup table for each byte separately, or a bithack that starts this way, but uses a multiply by a number like 0x01010101 to horizontal sum 4 bytes into the high byte of the result. Because multiply is a shift-and-add instruction. How to count the number of set bits in a 32-bit integer?)
But this is broken: it needs to use addu to avoid faulting; if you try to popcnt 0x80000000, the first add will have both inputs = 0x40000000, thus producing signed overflow and faulting.
IDK why anyone uses the add instruction on MIPS. The normal binary add instruction is called addu.
The add-with-trapping-on-signed-overflow instruction is add, which is rarely what you want even if your numbers are signed. You might as well just forget it exists and use addu / addui
For this assignment i need to be able to make an array of size n based on a user inputed value from zero to fifty. So far this is what ive done below. If you have any advice for the question overall that would be very helpful too.
a) Prompt the user for an integer in the range of 0 to 50. If the user inputs 0 the program stops.
b) Otherwise, the program stores the numbers from 0 up to the input value into an array of words in memory, i.e. initializes the array with values from 0 up to N where N is the value that user has inputted.
c) The program then adds the value of all items of the array together (up to N) by loading them from the main memory then add them up, then prints out the sum with the message "The sum of integers from 0 to N is:". For example, if the user gave 5 as the input the program prints out "The sum of integers from 0 to 5 is 15".
Submit your work as a zip file as specified in the syllabus to eLearning by the due date.
.data
userPrompt : .asciiz "enter in an integer from zero to fifty "
zeroMessage : .asciiz " you have entered a zero , the program will close "
incorrectEntry : .asciiz " you have entered in a value greater than 50 ,
this is an incorrect value"
InputVal : .word
upperLim : .word 50
Array : .space InputVal
.text
main:
addi $t7 , $zero , 50
li $v0, 4 # load for printing of strings
la $a0, userPrompt
syscall
# take in user input and move the read in number to a temp
li $v0, 5
la $t0 , InputVal
syscall
# Store int A into memory
move $t0 , $v0
beq $t0 , $0 , numbersEqual
la $t1 , upperLim
li $v0 , 1
move $a0 , $t1
syscall
slt $t3 ,$t0 , $t1
sw $t0 , InputVal
#beq $t3 , $0 , ELSE
ELSE :
li $v0 , 4
la $a0 , incorrectEntry
syscall
li $v0 , 10
syscall
numbersEqual:
li $v0 , 4
la $a0 , zeroMessage
syscall
li $v0 , 10
syscall
The assembly language is symbolic language for machine code, and machine code is what your CPU can execute.
After you run assembler to compile your source, you get machine code, which is sort of final. Then you execute that machine code.
The .word 0x12345678 is not instruction of CPU, but directive of your assembler, it tells it to reserve whole word of memory at that place of machine code, and store value of 0x12345678 there. I'm not sure what .word without value does, whether it will reserve at least one word, you should rather do InputVal: .word 0 to be sure.
In the final machine code there is no ".word", that's not CPU instruction, there will be just those 4 bytes with their respective values forming word value, at some address, which was known to the assembler as symbol InputVal (that's also not part of machine code any more in this textual form, any instruction using this memory address has only the proper address encoded in it as numeric value, and the executable binary may contain some sort of relocation table for OS to patch addresses properly after loading the machine code to target memory before execution).
Now this may sounds like stating the obvious, but it's important for you to understand the difference, what is available when the CPU is already executing your machine code, and what is available during compilation by assembler (code not running yet).
Array : .space InputVal will not work as you wish, because InputVal is symbol of memory address. So the directive .space will either reserve bazillion bytes (value of memory address of InputVal), or more likely the compilation will fail. What you want is content of memory at InputVal, but that's not known yet, because the code didn't run, user didn't enter anything, it's still just assembly step. So the value is not know, you may just as write Array: .space 0. But that will reserve no space.
Unless you want to delve into dynamic memory allocation, there's simple trick to resolve such situation, which will work in your particular case. If you will read the task, the N is valid only when inputted value is from 0 to 50 (anything else is user error and you can exit). So for maximum N=50 you will need array of 51 values, and you will never need more.
So you can avoid all the dynamic memory allocation (at runtime) by simply doing:
.align 4 # make sure the reserved space is word-aligned
Array: .space (51*4)
This will reserve 204 bytes (51 words) of memory in the data area for your machine code, with symbol Array pointing at the first byte of it.
Now you have memory reserved, and you can store values into it, and use it. If you would want during runtime to change your mind, and use 52 words of memory, you are out of luck with such code. Then you need either to code dynamic allocation, or increment the hard-sized fixed buffer during compilation time.
Also your code has always 51 words available in that Array, so it's up to your code to use only the inputted N+1 values out of them. If user enters N=5, then you should work only over 6 words (24 bytes), ignoring the remaining reserved words).
So each loop in your code will be like for (i = 0; i <= N; ++i) Array[i] = i;, where N is the value entered by user during runtime (store it to InputVal reserved memory, so you can access it whenever you need it), not known during compilation.
Okay so I have an issue. I want to get an integer and turn it into an array of single-digit integers in MIPS but I'm not sure how to go about that.
Can you guys help me? I know how to do this in every other language except this one...
Example:
I want to the integer 32325
to be an array where A[0] = 3, A[1] = 2, A[2] = 3, ...
Can you please help me? I've been stumped for a while!
This is what I have so far...
.data
prompt: .asciiz
msg: .asciiz
array: .space 24 #6 digit number
.text
li $v0, 4 #print out
la $a0, prompt1
syscall
li $v0, 5 #take in int
syscall
la $a0, array# Set address t0 to be the array
I have no idea about MIPS, but the algorithm is quite simple
Divide the number by 10, as long as it is != 0 ... the reminders (in reverse order) are the digits. easiest way to store them would be the stack, since pop'ing them will bring them into correct order again:
counter=0
while (number !=0) {
push number%10
number /= 10
counter++
}
while (counter>0) {
pop number
store/display it
counter--
}
I am looking for help on how to take a string from the user and then output the number of times each letter was used in the string.
Pseudo code
string "Please enter a string:"
take string and save into an array,
check for ascii duplicates of character values and then output when corresponding letter is output.
example: Hello World
A:
B:
C:
D: 1
E: 1
...
H: 1
...
W: 1
code
.data
intro: .asciiz "Letter Checker Program"
question: .asciiz "\nPlease enter a string for evaluation: "
string: .space 1024
alphabet: .space 26
.text
main:
jal setup
#jal analyze
#jal results
li $v0, 10
syscall
setup:
li $v0, 4 # outputing name and program information
la $a0, intro
syscall
li $v0, 4 # asksing for string input
la $a0, question
syscall
li $v0, 8
la $a0, string
li $a1, 1024
syscall
jr $ra # return
analyze:
loop:
loop:
results:
What you want to do is:
Create some space (26 * 4 bytes) to store the results and fill with 0
Loop over every letter in the string and load with lb
Determine the numerical value of the letter, and thus the memory location (of step 1). Don't forget about lower and upper case letters.
Load that memory location (4 bytes, use lw), increase the value with 1, and store again with sw
Stop when you encounter 0 (not the letter '0')
In analyze, loop over every letter in the alphabet, load the corresponding memory location from step 1, and print results
I am trying copy some words from memory and saving it to another memory address using assembly.
I am trying to write the code for it but I am not sure about some of the parts. I will briefly describe what I want to do.
The source address, destination address and the number of words to copy are input arguments of the function.
From your description it sounds like a regular memcpy, except that you specify the number of words to copy rather than the number of bytes. Not sure where the whole stack buffer idea comes from(?).
Something like this would copy the words from the source to the destination address:
sll $a2,$a2,2
addu $a2,$a1,$a2 ; $a2 = address of first byte past the dest buffer
Loop:
lw $t0,0($a0)
sw $t0,0($a1)
addiu $a0,$a0,4
addiu $a1,$a1,4
bne $a1,$a2,Loop
nop
EDIT: If your source and destination buffers are not aligned on word boundaries you need to use lb/sb instead to avoid data alignment exceptions.
EDIT: added nops after branches
So think about how you would do this in C...At a low level.
unsigned int *src,*dst;
unsigned int len;
unsigned int temp;
...
//assume *src, and *dst and len are filled in by this point
top:
temp=*src;
*dst=temp;
src++;
dst++;
len--;
if(len) goto top;
you are mixing too many things, focus on one plan. First off you said you had a source and destination address in two registers, why is the stack involved? you are not copying or using the stack, you are using the two addresses.
it is correct to multiply by 4 to get the number of bytes, but if you copy one word at a time you dont need to count bytes, just words. This is assuming the source and destination addresses are aligned and or you dont have to be aligned. (if unaligned then do everything a byte at a time).
so what does this look like in assembly, you can convert to mips, this is pseudocode:
rs is the source register $a0, rd is the destination register $a1 and rx is the length register $a2, rt the temp register. Now if you want to load a word from memory use the load word (lw) instruction, if you want to load a byte do an lb (load byte).
top:
branch_if_equal rx,0,done
nop
load_word rt,(rs)
store_word rt,(rd)
add rs,rs,4
add rd,rd,4
subtract rx,rx,1
branch top
nop
done:
Now if you copy bytes at a time instead of words then
shift_left rx,2
top:
branch_if_equal rx,0,done
nop
load_byte rt,(rs)
store_byte rt,(rd)
add rs,rs,1
add rd,rd,1
subtract rx,rx,1
branch top
nop
done: