Mips assembly language isolating bits - hex

I have 16 hexadecimal values that I'm trying to loop through and isolate the bits at b6,b2,b1,b0 thats where i got the the 0x47 from.
.data
#dellares all 16 test cases hexadecimal values
testCases: .byte 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
#set size of array to 16
size: .word 16
NL: .asciiz "\n"
.text
main:
lw $s7, size
move $s1, $zero
move $s2, $zero
loop:
bge $s1, $s7, loop_end
lb $s0, testCases($s2)
andi $a0, $s0, 0x47
li $v0, 1
syscall
la $a0, NL
li $v0, 4
syscall
addi $s1, $s1, 1
addi $s2, $s2, 4
j loop
loop_end:
However this does not print out the desired result, it prints out these results
Than you for any help

You're going through an array of bytes, so you should just add 1 to $s2, not 4.
In case you were hoping to print the results in hexadecimal form, then you're going to have to write you own routine for converting the numbers to strings because SPIM doesn't have a system call for that. MARS does, but it will add leading zeroes so that every number is printed with 8 hexadecimal digits.
Also, I didn't really find it clear if you just wanted to get those 4 bits, or if you also wanted to group them together (e.g. 0x43 -> 0xB). If you want to group them together it's going to take a little more than just an AND (and additional AND, a right shift, and an OR, to be precise).

Related

Arithmetic between double and integer in MIPS assembly

Below is a MIPS program that converts from Fahrenheit to Celsius.
I've defined 3 variables, one of which is a double and the rest are all integer. In order to perform division or multiplication between the variables, however, I had to convert the int variables to double later in the code.
The whole reason I declared the variables as int not float or double is because I'm literally storing one-digit decimal constants, and I wouldn't need to use two registers for that, asdouble requires. However, now I realise I'm facing two new problems:
1) I now need to do two extra steps for each variable (moving to cp1 and converting to double)
2) After the line mtc1.d $t1, $f6, the values become double and they get stored in two registers like normal doubles instead of one register like integers, hence missing my intention completely.
My question is, which way is better for memory and program efficiency? Declaring the variables as all of the same data type and shortening the number of instructions but taking up more memory space than I need?
Or giving the variables more suitable data types but costing myself 3 steps instead of just one?
Isn't there an efficient way to do arithmetic between two different data types in MIPS by using as few registers as possible?
.data
input: .double
cons1: .double 32
cons2: .word 5
cons3: .word 9
.text
#take double input from user
li $v0, 7
syscall #value is stored in f0 (and f1 probably)
#subtract first constant
ldc1 $f2, cons1 #load the value 32 into f2 and f3
sub.d $f12, $f0, $f2
#multiply by 5
lw $t1, cons2 #load 5 into t1
mtc1.d $t1, $f4 #move the value in t1 to f4
cvt.d.w $f4, $f4 #convert value to single precision to be able to do
#multiplication
mul.d $f12, $f12, $f4
#divide by 9
lw $t2, cons3 #load 9 into t2
mtc1.d $t2, $f6 #move the value in t2 to f5
cvt.d.w $f6, $f6 #convert value to single precision to be able to do
#division
div.d $f12, $f12, $f6
#show result
li $v0, 3
syscall

Intel 8086 Division. Need AX to be denominator not numerator

Need to divide CL by 10. I understand that in division AX will always be the numerator, but I need it to be the denominator.
In the code below I attempt to move the value I need as the numerator into AL and then put 10 into CL and divide.
Any help would be appreciated.
Mov Al, Cl
Mov Cl, 10
Div Cl
Need to divide Cl by 10
So you'll want the quotient back in the CL register then.
Your corrected solution (10 bytes):
mov al, cl
xor ah, ah ;Clear high byte because DIV will use the entire AX
mov cl, 10
div cl ;Divides AX by 10, leaves quotient in AL
mov cl,al
Shorter solution (6 bytes):
mov al, cl
aam ;Divides AL by 10, leaves quotient in AH
mov cl, ah
On 8086 the AAM instruction exclusively divides by 10.
On x86 the AAM instruction can divide by any byte-sized number.
So this AAM instruction is in effect an 8 bit by 8 bit division!
Is there a way then to divide a register by 10?
All divisions implicitly use the accumulator (AL, AX, DX:AX). Just copy your register to the accumulator first.

How to simply convert MIPS instruction to 32bits hex number

I'm working with ASM/MIPS technology and I want to train myself to conversion.
I wanna convert MIPS instructions to a 32bits hexadecimal number.
For example, I want to change sub$t0,$zero,$t1 to a hexa number.
I've find a lot of solutions, but everything is different.
Any idea ?
The MIPS sub instruction subtracts two registers and stores the result in a register.sub $d,$s,$t means $d = $s - $t
sub = function code 34 (see manual), 22 in hex, 100010 in bin (6 bits)
$t0 = 8 in decimal, 8 in hex, 01000 in bin (5 bits)
$zero = 0 in decimal, 0 in hex, 00000 in bin (5 bits)
$t1 = 9 in decimal, 9 in hex, 01001 in bin (5 bits)
So the machine code for your instruction is 01001 01000 00000 100010
For R-format instructions, the opcode, or "operation code" is always zero. rs, rt, and rd correspond to the two source and one destination registers.
The source sub$t0,$zero,$t1 therefore translates to 0x00094022 in hexadecimal notation.
Explanation
Every MIPS instruction is 32bits and translates to a 32bits number that can be written as machine code in hexadecimal format.
The instruction sub (subtract) has opcode 0x22. Therefore the rightmost digits has to be 22 (see above that they are).
sub is an instruction type R. This means the R instructions are used when all the data values used by the instruction are located in registers.
All R-type instructions have the following format:
OP rd, rs, rt
Where "OP" is the mnemonic for the particular instruction (in this case sub). rs, and rt are the source registers, and rd is the destination register. In this case, the sub instruction is used as:
sub $t0, $zero, $t1
In other words, your instruction means "subtract t1 from 0 and put the result in t0".
If you want to swap the values of two registers you can do it as follows:
.text
.globl __start
__start:
sw $t0, x
sw $t1, y
lw $t0, y
lw $t1, x
.data
x:
.word 0x000000FF
y:
.word 0xABCDE080
If you want to put the content in $t0 also in $t1, you can use the or instruction:
lui $t0, 0x0123
or $t1, $zero, $t0

Multi-Precision Arithmetic on MIPS

I am just trying to implement multi-precision arithmetic on native MIPS. Assume that
one 64-bit integer is in register $12 and $13 and another is in registers $14 and $15.
The sum is to be placed in registers $10 and $11. The most significant word of the 64-bit integer is found in the even-numbered registers, and the least significant word is found in the odd-numbered registers. On the internet, it said, this is the shortest possible implementation.
addu $11, $13, $15 # add least significant word
sltu $10, $11, $15 # set carry-in bit
addu $10, $10, $12 # add in first most significant word
addu $10, $10, $14 # add in second most significant word
I just wanna double check that I understand correctly. The sltu checks if
the sum of the two least significant words is smaller or equal than one of
the operands. If this is the case, than did a carry occur, is this right?
To check if there occured a carry when adding the two most significant
words and store the result in $9 I have to do:
sltu $9, $10, $12 # set carry-in bit
Does this make any sense?
The sltu checks if the sum of the two least significant words is smaller or equal than one of the operands.
Not quite: it sets $10 to 1 if the sum of the two least significant words is strictly less than one of the operands (considered as 32-bit unsigned values); and 0 if the sum is equal to, or greater than, that operand.
If this is the case, than did a carry occur, is this right?
Yes.
Consider what can happen when adding various possible values of b to some particular value a (where everything is an unsigned 32-bit value):
If overflow has not occurred, we must have a <= sum <= 0xFFFFFFFF, so 0 <= b <= (0xFFFFFFFF - a).
The remaining cases for b cause an overflow; the actual sum in these cases must be 0x100000000 <= sum <= a + 0xFFFFFFFF, which when truncated to 32 bits gives 0 <= sum <= a - 1.
To check if there occured a carry when adding the two most significant words and store the result in $9
I have to do:
sltu $9, $10, $12 # set carry-in bit
Not quite.
The problem here is that you're adding two 32-bit values and possibly a carry from the sum of the least significant words. For example, consider the case where there is a carry and both most significant words are 0xFFFFFFFF: the sum will be 1+ 0xFFFFFFFF + 0xFFFFFFFF = 0xFFFFFFFF, and so the carry will not be set (but it should be).
One way to deal with this would be to check for carry after adding $12 to $10, and check again after adding $11 to that sum. Only one of those sums can produce a carry ($12 + $10 only overflows when $12 is 0xFFFFFFFF, because $10 is either 0 or 1; and in that case the sum is 0, so the second sum can't overflow as well).
So this might (disclaimer: it's late, and this is untested) do the trick:
addu $11, $13, $15
sltu $10, $11, $15 # carry from low word
addu $10, $10, $12
sltu $9, $10, $12 # possible carry from high word (1)
addu $10, $10, $14
sltu $8, $10, $14 # possible carry from high word (2)
or $9, $8, $9 # carry in result if either (1) or (2) were true (can't both be true at once)

MIPS program to determine pass/fail for test grades

I'm writing a MiPS program that will examine a list of 15 test scores. And it is going to input from the terminal. The passing criterion is the score of 50. The outputs to the terminal will include the scores in each category and the number of students passing and failing. I should use input prompts and output statement. Please I need some help, just need some advice how to do it.
main:
li $t1,15 #load 15 into $t1
la $a1,array #load a pointer to array into $a1
I have a loop:
addi $t1,$t1,-1
li $v0,4
la $a0,prompt
syscall
I don´t want to give it away, so i´ll throw some guidelines.
You should read Assemblers, linkers and the Spim simulator. It´s a lot of help.
So here it goes.
Create two 15- word arrays.
.data
fail_vector: .word -1,-1,-1 ... #15 invalid words
passed_vector: .word -1,-1,-1 ... #15 invalid words
Load on some register the loop control variable.
li $t1,15
beq $t1,$zero,END
addiu $t1,$t1,-1
Now inside this loop read values
syscall... #SYS_READ
Then read this value (suppose you have it in register t4) and decide whether to store it in fail vector, or pass vector.
addiu t4,t4,-50 #subtract 50 from input value.
blez t4,FAILED #If its lower than 0, then read value is lower than 50 ->FAIL
PASSED:
#STORE VALUE INTO passed_vector
FAILED:
#STORE VALUE INTO failed_vector
When you are done with all the 15 values, print out the vectors. This is kind of tricky.
Before using your program, you should fill both vectors with some invalid value, like -1.
So when you are printing vector to screen, you should stop when you find one of this invalid values. And while you are at it, keep a counter to show how many passed / failed.
In pseudo-code
for both arrays
for (i in (0,15) and array[i] not -1)
print array[i]
add 1 to scores count //to count passed - failed test scores.
assembly (fill in the blanks)
END:
li $t4,15
li $t1,0
beq $t1,$t4,EXIT #condition. While ( i < 15) kind of thing.
addiu $t1,$t1,-1
#print out vectors and keep count on other registers
#then print them out.
syscall... #SYS_WRITE
EXIT: #exit syscall here.
Another tricky issue is the indexing of these vectors. Since they are arrays of words, then you should multiply by 4 (assuming 32 bit words) the loop control variable (classical i variable in C) to index the vector. If they were byte arrays, then no multiplication would be needed. And if they were short arrays...(well, you get my point)
For example:
passed_vector[i] #(C style sintax)
and let variable i be stored in register $t1
would turn out as:
sll $t2,$t1,2 #i * sizeof(word)
la $a0,passed_vector #$a0 points to passed_vector
add $a0,$a0,$t2 #$a0 now points to passed_vector + i
So now you could load/store to passed_vector[i]
sw $t3,0($a0) #0($a0) is passed_vector[0]
lw $t3,0($a0)
One way of solving these kind of things (that is, writing in assembly) is to write the program in C ( or some other language that you know ), and then translating it to assembly, instruction by instruction.
Ok, here's how to load both integer arrays (and only that)
.data
#These are two integer arrays. Each position is 32 bits long.
passed_vector: .word -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
failed_vector: .word -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
.text
#
# Previous code here.
#
li $t5,50 #For comparing test_scores against.
li $t0,0 # for (0..15)
li $t6,15 #
LOOP: beq $t0,$t6,CONTINUE # loops while i<15
li $v0,5
syscall
move $t1,$v0 #read test score and move it to register $t1
bge $t1,$t5,PASSED #if score >=50, load into passed_vector
FAILED: # else: test score lower than 50. Loads into failed vector
#dont forget to increment the failed counter here
sll $t2,$t0,2
sw $t1,failed_vector($t2)
addiu $t0,$t0,1 #i++
b LOOP
PASSED:
#dont forget to increment the passed counter here.
sll $t2,$t0,2
sw $t1,passed_vector($t2)
addiu $t0,$t0,1 #i++
b LOOP
CONTINUE: #other code

Resources