Arithmetic, logic and bits
Multiplication and division answer into hi and lo, two registers outside the 32, and division by zero says nothing unless you used the pseudo-instruction. Then the masks, the shifts and the fields you pull out of a word with them.
add and sub behave exactly as they look, with the trapping and wrapping pairs from "Words, halves
and bytes". Multiplication and division are the two with rules of their own, because a product can
need 64 bits and a division has two answers.
hi and lo
mult $t0, $t1 multiplies the two registers and writes the 64 bit product into hi and lo,
two registers that sit outside the 32 and that no other instruction reads. The top half goes in hi,
the bottom half in lo, and mfhi and mflo (move from hi, move from lo) copy them into a register
you name.
div $t0, $t1 divides and writes both answers the same way: the quotient in lo and the
remainder in hi.
$t2 comes out at 2 and $t3 at 540BE400, which together are 10000000000. $t6 is 142 and $t7
is 6, because 7 times 142 is 994.
hi and lo are at the bottom of the registers panel with pc, and they hold whatever the last
mult or div left there. So read them before the next one: a mult between your div and your
mflo throws the quotient away.
mul $t2, $t0, $t1 is the three operand form and it is a real instruction: it writes the low 32
bits of the product straight into a register, and updates hi and lo as well. When the answer
fits in a word, which is nearly always, it is the one to write.
Division by zero says nothing
div $t0, $t1 with a zero in $t1 does not stop the program, does not raise an exception and does
not even change hi and lo. The answer you then read with mflo is whatever was there before.
The three operand div $t2, $t0, $t1 and rem $t2, $t0, $t1 are pseudo-instructions, and they build
the check in: each becomes a bne that tests the divisor, a break for when it is zero, then the
real div and an mflo or mfhi.
$t2 is 142, $t3 is 6 and $t4 is 7000. Click on the div line after building and the four
instructions it became are printed underneath.
Change li $t1, 7 to li $t1, 0 and press Run: the program stops on the div line with
break instruction executed; no code given. Write the two operand div $t0, $t1 instead and the
same zero goes by in silence. So either use the pseudo-instructions and let them stop you, or test
the divisor yourself before the real one.
madd and msub write hi and lo too: they multiply and then add to or subtract from
what is already in the pair, which is how a sum of products is computed without a move between every
step. mthi and mtlo write them from a register you name.
Logic and masks
and, or, xor and nor are one bit position at a time with no carrying between them, and the
i forms take a constant: andi, ori, xori. There is no not instruction, because
nor $t1, $t0, $zero is one, and the assembler accepts not as a name for it.
A mask is a number written for the pattern of its bits, and each of the operations does one of the things you can want with one:
andwith a mask keeps the bits the mask has set and clears the rest.orwith a mask sets those bits.xorwith a mask flips them.- clearing a bit takes
andwith the mask's complement, which MIPS makes you build:northe mask with$zeroand thenand, or write the complement out withli.
The constant of andi, ori and xori is 16 bits zero extended, so it can only reach the low
half of a register. A mask that touches the top half has to go into a register first with li.
$t1 comes out at 00000056 and $t2 at 00000034, the second and third bytes of 12345678
pulled out one at a time. $t5 is 0000ABCD, two bytes packed into one half. $t6 is 123456FF,
$t7 is 12345687 and $t9 is 12345600.
Mask and shift down to read a field, shift up and or to write one. That pair is how every packed
value on this machine is taken apart, including the colour of a pixel on the bitmap display, which
is red, green and blue in three bytes of one word.
Shifts
Three shifts, each with a form that takes the amount from a register:
sll,sllv, shift left, zeroes coming in at the bottom. Shifting left bynmultiplies by 2 to then.srl,srlv, shift right logical, zeroes coming in at the top, which divides an unsigned number.sra,srav, shift right arithmetic, copies of the sign bit coming in at the top, which divides a signed number.
The constant amount is five bits, so 0 to 31, and the register forms use the low five bits of the register and ignore the rest.
$t2 is 00100000, $t4 is 0000FF00, $t6 is FFFFFFFB, which is -5, and $t7 is 3FFFFFFB,
which is 1073741819. $t9 is C0000000: the bit at the bottom came round to the top and joined the
one already there.
rol and ror are pseudo-instructions. MIPS has no rotate, so each becomes a shift each way and an
or, through $at.
One bit at a time
There is no bit test instruction. Testing bit n is andi with 1 << n and a branch on whether the
answer is zero; setting it is ori, clearing it is and with the complement, flipping it is xori.
When n is in a register, srlv brings the bit down to the bottom and andi $t1, $t1, 1 keeps it.
Counting the set bits of a word is that idea in a loop:
$t1 comes out at 16 and $t0 at 0, shifted away entirely. add $t1, $t1, $t3 with a bit that is 0
or 1 is the whole of "count it if it is set", which needs no branch.
Two instructions count bits for you at one end of a word. clz $t1, $t0 counts the leading zeroes
of $t0, the run of 0 bits from the top down, and clo counts the leading ones. clz is how a
program finds the position of the highest set bit, which is the integer logarithm of a number.
Your turn
The test starts $t0 at 1000. Divide it by 7 and leave the quotient in $t1, which is 142, and the
remainder in $t2, which is 6.
Show solution
The second one starts $t0 at 0xF0F0F0F0 and wants the number of bits set in it left in $t1,
which is 16. $t0 may be destroyed on the way.