MIPS instruction modulo - mips

b = a % 16
a --> $s0
b --> $s1
Answer: $s1, $s0, 0xF
#0xF= 0000 0000 0000 0000 0000 0000 0000 1111
When I convert it to decimal, it is 15.
I am not too sure why it is 15?

The remainder when dividing any number by b is in the range [0, b-1]. So modulo 16 returns a maximum value of 15
To get modulo 2N of any number we take the last N bits of it, because any higher bit at position M with M > N represents a value 2M which is divisible by 2N. The mask to get N bits is 2N - 1. That means a % 16 = a & 0xF = a & 15

When using the MIPS command div for division, the result is stored in the register lo while the modolo is stored in the register hi.
So if a=$s0, b=$s1 and $t0 = 16 you could use
div $s0,$t0
mfhi $s1
for b=a%16

Related

How translate MIPS I-format to binary?

I don't know how to translating mips I-format instruction to binary.
For example,
$t0 is base of an int array A[].
And the way to get value of A[1] is
lw $t0, 4($t0) // 4 means 4bytes
35(6bits) | 8(5bits) | 8(5bits) | 4(16bits)
10011 / 00101 / 01000 / 0000 0000 0000 0100
Is it correct?
and
bne $t0, $s0, Exit <- 80000
// other instruction1 <- 80004
// other instruction2 <- 80008
Exit: <- 80012
5(6bits) | 8(5bits) | 16(5bits) | 2(16bits)
00101 / 01000 / 10000 / 0000 0000 0000 0010
Pointer counter points instruction1(80004).
And address is byte address.
Is correct?
I know address in BNE is instruction distance between Program Counter.
I am confused why address in BNE is 2, not 8.
lw $t0, 4($t0) // 4 means 4bytes
35(6bits) | 8(5bits) | 8(5bits) | 4(16bits)
Yes
10011 / 00101 / 01000 / 0000 0000 0000 0100
No
100011 / 01000 / 01000 / 0000 0000 0000 0100
bne $t0, $s0, Exit <- 80000
5(6bits) | 8(5bits) | 16(5bits) | 2(16bits)
Yes
00101 / 01000 / 10000 / 0000 0000 0000 0010
Close
000101 / 01000 / 10000 / 0000 0000 0000 0010
(Make sure there's actually 6 digits in your 6-bit fields.)
With MIPS, all instructions are 32 bits wide, or 4 bytes long, and each instruction starts at an even 4 byte boundary (4 byte or word aligned, even multiple of 4).  Thus, for a branch, it is going from a 4 byte aligned address to another 4 byte aligned address.
A 4-byte aligned address has 2 low bits of zero.  The branch offset is the difference between 2 4-byte aligned addresses, and therefore such an offset also has 2 low bits that are zero.  There's no point in encoding those two zero bits in the instruction because it is known they're zeros.  So, the immediate encoded in the branch instruction is the branch offset divided by 4, which removes those zero bits, and also increases the branch offset's range by 2 bits.  (The assembler divides the offset by 4 to encode it and the hardware effectively multiplies the immediate by 4 in usage.)

Possible to move Program Counter to a far-off memory address immediately?

I'm trying to adapt a program that counts the occurrences of a char in a file to store a list of the hex addresses where the matches occurred in a far-off memory location. Code:
011 0000 0000 0000 ;Codes x3000 as Load-address of program
0101 010 010 1 00000 ;R2 <- 0
0010 011 000010000 ;R3 <- M[x3012]
1111 0000 0010 0011 ;TRAP x23 (Loads INPUT into R0)
0110 001 011 000000 ;R1 <- M[R3]
;LOOP BEGINS HERE
0001 100 001 1 11100 ;R4 <- R1 - EOT
0000 010 000001000 ;If above = 0, exit loop
1001 001 001 111111 ;R1 <- NOT R1
0001 001 001 1 00001 ;R1 <- R1 + 1
0001 001 001 0 00 000 ;R1 <- R1 + R0
0000 101 000000001 ;If above != 0, do NOT increment counter
0001 010 010 1 00001 ;R2 <- R2 + 1 (increment counter)
0001 011 011 1 00001 ;R3 <- R3 + 1 (increments pointer to next char in file)
0110 001 011 000000 ;R1 <- M[R3] (loads next char into R1)
0000 111 111110110 ;BRnzp x3004 (unconditionally RETURN to loop start)
;LOOP ENDS HERE
0010 000 000000100 ;R0 <- M[x3013]
0001 000 000 0 00 010 ;R0 <- R0 + R2
1111 0000 0010 0001 ;TRAP x21 (OUTPUT)
1111 0000 0010 0101 ;TRAP x25 (HALT)
0011 0001 0000 0000 ;Codes x3100 for the starting address of the file
0000 000 000110000 ;ASCII template
So my program starts at memory address x3000. I want to begin the set of instructions that will handle the list at x300B (below the "increment R2" instruction). Trouble is, I want to start the list at x3500, and I don't know of an "efficient" way to get there.
My original plan was to use a Load Indirect (LDI) instruction, but because of sign-extension, the 9-bit offset only allows an offset of at most x00FF = 0000 0000 1111 1111, which only takes me from x300C (x300B with program counter incremented) to x310B.
The only real "workaround" I've come up with is to use a Load Effective Address (LEA) instructions to store the address x310B in a register (say R5), then store the value x00FF in R6, and repeatedly add R6 to R5 until I get to x3408 (that would take 3 ADD instructions), at which point I'd store the value x0092 in R6, add that to R5, and I'd FINALLY have x3500 in R5.
At that point, the rest is trivial (store R3 in (R5 + counter), which would put the address of the current match into the appropriate "spot" on the list)
I haven't actually done this yet because the whole method of getting to x3500 I described above seems really cumbersome and clumsy. I can't shake the feeling that there has to be a better, faster way to move that many memory addresses at the same time.
Is it possible to move from x300C to x3500 in a single instruction? Even two would be better than what I've currently got.
You wouldn't want to do that, it is possible but a simpler method would be to use LD (opcode 0010) and LDR (opcode 0110) to do this. No need to have the PC jump to x3500 (which would start executing the data in your array which is bad)
Have an address contain the bits 0011 0101 0000 0000
Opcode 0010 will allow you to pull the x3500 into a register. Opcode 0110 will then allow you to load values from your array.

Counting the number of 1's on the left side of a binary representation

Im trying to get the number of 1's on the left side (bits 16-31) This code seems to work but im getting 1 extra count on my 1's from certain integers.
For example:
1536 in binary is 0000 0000 0000 0000 | 0000 0110 0000 0000
and im getting 0 1's on the left side which is correct.
Also:
100000 left side binary is 0000 0000 0000 0001
and my result is 1. which is also correct.
However:
1000000000 in binary is 0011 1011 1001 1010 | 1100 1010 0000 0000
and im getting 10 1's on the left side instead of 9.
Ive tested other numbers as well but they also have an extra count.
#Displays number of 1's on left half
li $v0, 4
la $a0, left
syscall
li $t2, 0 #i = 0
srl $t3, $s0, 16 #shifts users number to the right by 16 bits
Counter:
and $t4, $t3, 1 #Mask off bit
beq $t4, 1, Count #if mask = 1 go to count
srl $t3, $t3, 1 #if mask != 1 (aka 0) shifts right by 1
beq $t3, 0, Exit #once the shifted bits = 0 go to exit
Count:
add $t2, $t2, 1 #increment i++
srl $t3, $t3, 1 #shifts right by 1
j Counter
Exit:
li $v0, 1 #Displays number of 1's
move $a0, $t2
syscall
Not sure if the code is even correct since im new to mips. Could be possible that the whole thing is wrong.
You may use clz/clo to count the number of leading zeros and ones, and use that to count the number of ones. The idea is to consume the leading zeroes, then count the leading ones (shifting those bits out of the register) until the input data is zero.
i.e.:
li $t1, 0x4F044321 % $t1 Input number
srl $t1, $t1, 16
sll $t1, $t1, 16 % Discard least significant bits
li $t2, 0 % $t2 will hold number of 1s
count:
beqz $t1, done
clz $t3, $t1
sllv $t1, $t1, $t3
clo $t3, $t1
addu $t2, $t2, $t3
sllv $t1, $t1, $t3
b count
done:

Mips instructions mthi and mtlo into hex?

I am in the process of writing a utility to convert a mips instruction into its hex (4 bytes) format. Everything was going ok with instructions such as ADD, etc. But with mthi and mtlo, there is a different in the output I am getting compare to what is expected. I am not sure what exact version of mips this is.
Here is what I am getting:
mthi $t2 = 01400011
mthi $s0 = 02000011
mtlo $t8 = 03000013
mtlo $a3 = 00e00013
Here is what I am getting:
mthi $t2
1010 00000 00000 00000 010001
Does anyone know how the inner bits are being calculated and what version of mips that is? Thanks.
Information from "See MIPS Run", for all MIPS ISA it covers (up through MIPS IV) there is no difference in the MIPS32 instruction.
This is the format for mfhi, mtlo, mfhi, mtlo (mfhi/mflo included for comparison and completeness)
bit: 31-26 25-21 20-16 15-11 10-6 5-0
mfhi rd 0 0 0 rd 0 16
mthi rs 0 rs 0 0 0 17
mflo rd 0 0 0 rd 0 18
mtlo rs 0 rs 0 0 0 19
So mthi $t2 (register #10)
mthi $t2 000000 01010 00000 00000 00000 01001
The MIPS 32R2 encoding of MTHI rs is binary 000000 sssss 000 0000 0000 0000 010001.
So MTHI $t2 is binary 000000 01010 000 0000 0000 0000 010001

How does the sll instruction in MIPS work?

The following assembly code is given in my text book.
Loop:
sll $t1, $t0, 2
add $t2, $a0, $t1
sw $zero, 0($t2)
addi $t0, $t0, 1
slt $t3, $t0, $a1
bne $t3, $zero, Loop
# return where we were
jr $ra
From this code I have two question to ask.
The first question is about the second line from the top. I get that the instruction sll is shift left logical which shifts bit to the left. Since the shift amount is 2, it will make 0000 -> 0100 = 4 in decimal. But I don't get it after the first loop. If we shift this to the left by 2, isn't it multiplied by more than 4??
And the second question is if it is possible to optimize this code?? In my opinion, I can modify sll and add parts in the code but I am not sure.
Any comment??
Shifting left will insert 0's, not 1's. So 0000 would still be 0000, 0001 will become 0100 after the shift
[is it] possible to optimize this code?
A more compact way of doing the same thing would be:
sll $a1, $a1, 2
addu $a1, $a1, $a0 # $a1 = $a1 * 4 + $a0
Loop:
sw $zero, ($a0)
addiu $a0, $a0, 4
bne $a0, $a1, Loop
I'm making these assumptions:
The original values of $a0 and $a1 are not needed anymore after the loop ends. If they are needed, save the original values somewhere (in other registers or on the stack) before entering the loop, and restore them afterwards.
$t0 starts out at zero. If not, you'll have to add $t0 * 4 to $a0 before the loop. I'm also assuming that the value of $t0 after exiting the loop is irrelevant.
Consider the following binary:
0000 0001
If you shift the bits left by 1 digit you get:
0000 0010
If you shift again to the left by 1 digit:
0000 0100
And again:
0000 1000
The binary values above are equivalent to 1; 1x2=2; 2x2=4; 4x2=8.
Shifting bits to the left is multiplying the value by 2^N if N is the number of bits you are shifting.
Another example of shifting:
Assume $t1 contains 0000 1111
sll $t0, $t1, 3 # $t0 = $t1 * 2^3
Now $t0 contains 0111 1000
You can verify this by performing decimal multiplication. 15 * 8 = 120.