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
Related
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
I want to check if the value of the register ax is divisible by 7, with remainder = 0. How can I do it?
You can use the same way as shown in this answer, with different constants of course.
The modular multiplicative inverse of 7 mod 216 is 0x6db7, which (by definition) means that numbers of the form x = n * 7 will obey x * 0x6db7 = n, where n will be less than or equal to 0xffff / 7. So if you get something bigger out of x * 0x6db7, you know it's not a multiple of 7. Also, non-multiples of 7 cannot also map to low results, because multiplication by an odd number modulo a power of two is bijective.
So you can use (not tested)
imul ax, ax, 0x6db7
cmp ax, 0x2492
ja not_multiple_of_7
This is for unsigned numbers of course.
As a bonus, ax will be the original value divided by 7 iff it was a multiple of 7.
org 100h
mov ax,14
mov cl,7
div cl
cmp ah,0
je positive
PRINTN "The number has a remainder"
jmp finish
positive:
PRINTN "The number has no remainder"
finish:
PRINTN "After comparison"
mov ah, 0
int 16h
ret
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).
I have to write a program in 8086 assembly that calculates this:
(a+b*c+2/c)/(2+a)+e
where
a,b - byte
c - word
e - doubleword,
in unsigned interpretation.
So far I have this:
assume cs:code,ds:data
data segment
a db 4
b db 2
c dw 16
e dd 126
data ends
code segment
start:
mov ax,data
mov ds,ax
and here is my program
mov al,b ; al=b
mov ah,0 ; ax=b;
mul c; dx:ax=b*c; b*c=doubleword
mov bx,ax; we save b*c in bx to use ax in the division 2/c
mov al,2; al=2
mov ah,0; al=ax=0
div c; ax=dx:ax/c ; dx=dx:ax%c;
I don't know how to continue.
When you write
mov bx,ax; we save b*c in bx to use ax in the division 2/c
you're actually only saving the low word of the product between B and C. It works with the numbers provided but it's not a general solution.
In stead of writing
mov al,2; al=2
mov ah,0; al=ax=0
use mov ax,2 and remember to explicitely clear the DX register because the division needs it.
To continue I would suggest you create a result variable of doubleword size because in the end the size of your largest expression participant defines the size of the result. Then on the way move or add your partial results to this variable.
If you are allowed to use 32 bit registers a suitable approach might be to promote all values to 32 bit and continue from there.
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