How to convert / encode a negative number as an immediate in MIPS machine code - binary

I want to change this instruction to binary or machine code:
addi $s3, $s1, -1000.
I know how to encode the opcode, rs, and rt, but I have no idea how to convert -1000 to binary.
I know how to get 1's complement and 2's complement. But i don't know how to express it in this I type instruction.
I just don't know how to express -1000 into last 16 digits as binary number.
since 1000(decimal) is 0000001111101000 in 16 digit.
1's complement is 1111110000010111
+1
= 1111110000011000 2's complement
so the answer for the whole instruction is
001000 10001 10011 1111110000011000
addi rs rt immediate
Is this right?

Yes, MIPS addi / addiu use a 16-bit signed 2's complement immediate as the low 16 bits of the instruction word. The CPU will sign-extend it to 32 (or 64) bits when decoding.
But note that ori / xori / andi logical instruction use unsigned 16-bit immediates that are zero-extended to 32-bit (or 64-bit), so -1000 is not encodable.
To implement xori $t0, $t1, -1000, you'd need to create a 32-bit -1000 in a register with something like addiu $at, $zero, -1000, then you could xori $t0, $t1, $at. ($at is the "assembler temporary" register that pseudo-instructions like bgt use.)

Related

MIPS multu overflow

As part of a hex to decimal program I'm writing in MIPS using QT spim I load the value of 16^7 (268435456) into a generic register. I then multiply this number by 1-15 depending on the character, add the result to a running total, and divide 16^7 by 16.
However, I encounter what I assume to be overflow issues when multiplying 268435456. For instance, the code
li $t0, 10
li $t1, 268435456
multu $t0, $t1
mflo $t2
li $v0, 10
syscall
Which is intended to multiply 268435456 by 10 and store the result in $t2 stores -1610612736 instead of 2684354560. Any ideas on how to fix this code to store the correct value?
multu is the unsigned version of mult, which means that it is not going to generate an overflow because the result is taken as an unsigned number. When you show the value through a syscall it is taken as a signed number, so the signed value is shown (which in this case is negative).
You didn't give much info regarding what you are trying to achieve, but if you mean to perform a signed multiplication (meaning you want to keep the sign of the result) and store the result in a 32 bit register then you are going to run into limitations. If this is the case you will need to check whether the operation is possible within these bounds before printing the results, meaning you have to check whether the overflow happened:
li $t0, 10
li $t1, 268435456
multu $t0, $t1
mflo $t2
li $t3, 31
srl $t0, $t0, $t3
srl $t1, $t1, $t3
srl $t2, $t2, $t3
xor $t0, $t0, $t1
xor $t0, $t0, $t2
bgtz $t0, noOperationRoutine
li $v0, 10
syscall
noOperationRoutine:
....
The above solution performs a check on the leftmost bit (obtained by shifting right by 31 bits), which is indicative of the sign (1 for negative and 0 for positive). If one and only one of the operands is negative, then the result should be negative. If both are negative or positive, then the result should be positive. I think you can see how the two xors perform this check.
If you want to work with results that are bigger than the maximum size of a signed number then you have to keep in mind that mult stores the low part of the result in LO and the high part in HI. At this point you are going to deal with 64 bits numbers, which occupy two words/registers each.

Trouble sign extending a register in MIPS

Currently I have
lh $t1, 0($t1)
for sign extending $t1 from 16 bit to 32 bits, but this doesn't work. Is there a simple way to sign extend registers in MIPS?
The way I understand your question, even though you had attempted to use lh you actually wanted to sign-extend the halfword value of $t1 rather than the halfword $t1 is pointing to.
You can accomplish this with two shifts:
sll $t1, $t1, 16
sra $t1, $t1, 16
If you started out with 0x8000, you'd get 0x80000000 after the first shift, and 0xffff8000 after the second.
If you started out with 0x7fff, you'd get 0x7fff0000 after the first shift, and 0x7fff after the second.
lh does work but you need to be sure what you're loading from is defined by .half and not .word because of width and little-endian considerations:
main:
la $t5,myhalf
lh $t1,0($t5)
nop
.data
myhalf: .half 0x8000 # this works
# these do _not_
myword: .word 0x80000000
myword2: .word 0x8000

MIPS: Integer Multiplication and Division

So I'm building a calculator program in MIPS and I'm trying to write the multiply and divide functions.
Currently I read in the integers in a loop like so:
li $v0, 5
syscall
and then eventually call my functions multi and dividepending on which action the user wants to do.
So assuming I have the integers in $a0 and $a1, what would be a clean way to multiply $a0 by $a1 and/or divide $a0 by $a1? I've been looking around online but I can't find a clean and easy way to do this, because I have to send the resulting answer back in $v0
To multiply, use mult for signed multiplication and multu for unsigned multiplication. Note that the result of the multiplication of two 32-bit numbers yields a 64-number. If you want the result back in $v0 that means that you assume the result will fit in 32 bits.
The 32 most significant bits will be held in the HI special register (accessible by mfhi instruction) and the 32 least significant bits will be held in the LO special register (accessible by the mflo instruction):
E.g.:
li $a0, 5
li $a1, 3
mult $a0, $a1
mfhi $a2 # 32 most significant bits of multiplication to $a2
mflo $v0 # 32 least significant bits of multiplication to $v0
To divide, use div for signed division and divu for unsigned division. In this case, the HI special register will hold the remainder and the LO special register will hold the quotient of the division.
E.g.:
div $a0, $a1
mfhi $a2 # remainder to $a2
mflo $v0 # quotient to $v0

MIPS How to branch to a 32-bit address?

I am trying to branch to an address:
bne $t0, $0, 0x7813a21c
However, this is incorrect because bne only allocates 16-bits to the immediate
How can I branch to a direct 32-bit address? Is there a way to branch from a value in a register?
You have to use JR to jump to an address stored in a register.
To preform this type of operation you will need a jump statement. You have to tell the code to jump control context to the exact line you wish to specify. This is example syntax: j offset Where in your address is the offset.
Here is a link that better reviews what you have to do. Check out the section on jump. These are the types of jump available. One of them is what you need: j offset, jal offset, jr $rs, jalr $rs
Here is the link:
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/jump.html
Good luck
We can load 32-bit addresss to the register (e.g. $t1) in 2 steps:
Load the upper 16 bits by lui (Load Upper Immediate).
Load the lower 16 bits by ori (Or Immediate).
NOTE: It is work because lui fills the lower 16 bits with 0s, so bitwise OR load the lower 16 bits (n | 0 = n);
In code below if $t0 is equal to 0 we do skip jr instruction.
Or if $t0 is not equal to 0 we do not skip jr instruction (or we do jump).
beq $t0, $0, SKIP
# load 0x7813a21c to $t0
lui $t1, 0x7813 # load the upper 16 bits
# Now $t1 = 0x78130000
ori $t1, $1, 0xa21c # load the lower 16 bits
# Now $t1 = 0x7813A21C
jr $t1 # as #Matt Eckert said
SKIP:

Finding offset from a code snippet

I am a bit stuck up with the following question,
Consider the following MIPS code and answer the questions that follow.
addi $t1, $s0, 400
loop: lw $s1, 0($s0)
add $s2, $s2, $s1
lw $s1, 4($s0)
add $s2, $s2, $s1
addi $s0, $s0, 8
bne $t1, $s0, loop
What value is the label loop translated to in the conditional branch
instruction?
Now I know the mathematical formula for Branch Target Address. But here as memory addressing is not done so I found out the offset by counting the lines between the target address and PC. This gives the answer to be 7 (word offset). Am I right with this approach?
A quick experiment with MARS simulator http://courses.missouristate.edu/KenVollmar/MARS/download.htm gave me the answer-6, -5 for number of lines difference and another -1 because PC is increased by 1 after the instruction.
AFAIK, I'm afraid not.
As MIPS instruction reference says:
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following the branch (not
the branch itself), in the branch delay slot, to form a PC-relative
effective target address.
So as I understand, the distance from the branch instruction to the loop label is negative (because the label is before the branch, thus the address is lower). The distance is calculated in number of words (hence the 2 bits left shift). As all MIPS instructions are 4 bytes, this would be 6 instructions before, hence -6 is the value that should appear in the branch instruction offset (lower half-word). In binary: 1111 1111 1111 1010 (two's complement). In hexadecimal: FFFA.
Checked with simulator and seems that my reasoning is correct since the instruction is coded as 0x1530FFFA.