4

What is the difference between div and divu in MIPS.

I have seen difference between add and addu (link for same). My understanding of add and addu : both operate on 2's complement signed numbers, the only difference that add generates traps on overflow whilst addu does not

But what is difference between div and divu, I mean we wont really get overflows here right.

I tried following cases but got pretty weird results with divu. I only loaded the quotients (with mflo) and here are the outputs:

num1 |  num2  | div num1 num2 (qoutient) | divu num1 num2 (qoutient) | 

5    |   2    |            2             |            2              |

-5   |   2    |           -2             |            2147483645     |

5    |  -2    |           -2             |            0              |

-5   |  -2    |            2             |            0              |

Can Someone please explain logic of what is happening!!??

Naman
  • 372
  • 4
  • 20

2 Answers2

4

In general, the u suffix means "unsigned". The overflow trap is a side-effect of signed arithmetic which is not supposed to overflow, whereas unsigned arithmetic is allowed to overflow or wrap around without triggering any exceptions.

What this means is that you should consider the signed vs unsigned differences before looking at the traps. A regular div instruction will treat its operands as two's-complement encoded whereas a divu operation will treat the operands as unsigned integers.

All this means that using the same operands can result in different answers depending on whether div or divu is used.

When dividing -5 by 2 with div, you get the answer you expect: a quotient of -2 and a remainder of -1, which makes sense since -2 * 2 + -1 = -5. But when using divu which takes unsigned integers, the -5 isn't seen as "negative five" but rather 11111111111111111111111111111011 (which is the two's complement representation of -5) but it's read as "plain" bytes in which it comes out to 4294967291, which when divided by 2 correctly yields 2147483645.

In short: the purpose of the u version of a command is to treat the input as unsigned integers even if that can't result in an overflow. Why does this exist? Well let's say you DID want to find out the result of 4294967291/2 - how would you do that with a signed divide? Trying to store 4294967291 in a 32-bit register will result in a value that is interpreted as -5 rather than 4294967291. divu takes care of that by letting you use all 32 bits of the register as "data" rather than setting aside one bit for the sign.

jcomeau_ictx
  • 37,688
  • 6
  • 92
  • 107
Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • But then for addu why doesn't it treat numbers as unsigned. As per the answers mentioned in link (mentioned in my problem), addu aslo operates on 2's complement numbers. For Example how does -5 and 2 on addu gives -3 ?? (isn't it unsigned addition? – Naman Aug 16 '18 at 18:11
  • Or does the -5 gets converted to that big binary string, then after addition of 2 gives another binary string. And then unsigned numbers are converted back to 2's complement form..) – Naman Aug 16 '18 at 18:15
  • You're getting the hang of it now. Do the math by hand, converting each operand to the two's complement, then add them. The result overflows but the carry bit is dropped in the unsigned case, resulting in wraparound. If the result register were 33 digits wide, `addu` would give you a big number as the result. – Mahmoud Al-Qudsi Aug 16 '18 at 18:18
  • Ohh yeah I get it know, so actually in background it does convert to unsigned numbers but due to dropping of carry bit and due to magic of 2's complement it wraps around the the same answer with adding corresponding signed numbers right? [Though most answers online ignore this and say addu performs signed operations only which is confusing!] – Naman Aug 16 '18 at 18:24
  • Also last clarification why does addiu does signed extension of the immediate field (padding with all ones before the immediate value if most significant bit is 1)? It's pretty un-intuitive to me because the instruction is for unsigned addition! – Naman Aug 16 '18 at 18:30
  • 3
    it does not convert in background to unsigned, the bits in register are set as they are.. it's 32 bits (0 or 1). The "unsigned/signed integer" is your *interpretation* of those bit patterns, CPU does not care while storing the bit pattern, and often it does not care while doing arithmetic, although in case of `div/divu` it actually does interpret those bit patterns as signed/unsigned integers (in two's complement). But the bit patterns is processed as is, there's no additional converting needed. Whether you see it in debugger as signed int instead of unsigned is not an issue for CPU. – Ped7g Aug 16 '18 at 20:33
  • Yeah I should have said (was trying to say) interpretation instead of conversion. Thanks for correcting – Naman Aug 16 '18 at 20:37
  • 2
    I guess the `addiu` does sign-extend to make it viable also in case where `subiu` would be needed without that, i.e. `addiu $1, $1, -4` is possible. Creating also `subiu` would be less practical, because the sign-extension eats only one bit of the immediate which is already large enough (for larger values you can use memory or load them by parts, but 16 bit immediate will cover many use-cases) - while adding another instruction blocks one more opcode. But generally these questions are difficult to answer without consulting the author of the ISA, maybe they had completely different reasons. – Ped7g Aug 16 '18 at 20:38
  • Although `addiu $1, $1, -4` would actually 'interpret' -4 as an unsigned number and uses hardware logic for unsigned numbers for producing the result (which due to wrapping around gives the expected answer), right?? – Naman Aug 16 '18 at 20:43
  • @Naman: There is no "interpretation". Unsigned and 2's complement addition are the same binary operation, given full-width inputs. The only reason MIPS has `add` vs. `addu` is to give you the option of trapping on signed overflow, not because the numeric result would ever be different. (Unlike some other ISAs, MIPS doesn't have a FLAGS register. On x86 or ARM, there's only one `add` instruction, but you can detect signed or unsigned overflow by checking OF or CF (overflow or carry). See http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt.) – Peter Cordes Aug 17 '18 at 00:11
  • @PeterCordes thanks. But then why does div and divu work differently. It must mean that div interprets (uses hardware logic for) the numbers in 2's complement form whilst div does not. And while for add vs addu hardware logic for both (treating as signed vs treating as unsigned) would probably be the same, but overflow may occur (unlike div or mult), so for overflows people decided to use add and addu for distinguishing. – Naman Aug 17 '18 at 04:41
  • @PeterCordes Also for addu even assuming or thinking that it treats the numbers (uses hardware logic for) unsigned numbers it doesn't matter because of 'magic of 2's complement'. So it does makes things somewhat intuitive to think about even if it's kinda wrong language I guess! – Naman Aug 17 '18 at 04:44
  • 2
    @Naman: because unlike addition, signed 2's complement division is different from unsigned division. It's not the same binary operation; the interpretation of the bits *does* matter. (Same for full multiplication (N x N => 2N bits): the low half is the same whether the MSB has place value `-2^(N-1)` or `+2^(N-1)`, but the high half of the result depends on the signedness.) – Peter Cordes Aug 17 '18 at 05:00
  • Yeah that's what I wanted to hear. Thank you everyone for this awesome comment thread. Nobody explicitly mentions and it becomes somewhat confusing (atleast for beginners). Thanks alot! – Naman Aug 17 '18 at 05:08
  • 1
    @Naman btw, MUL and DIV are sort of exceptions, most of the CPU operations are based on individual bit manipulation, as that is what is convenient to design in HW. The early CPUs started with instructions like "add, shift-by-one, and, xor, or, mov", all of them trivial on bit-level, and there's no need to interpret the whole bit patterns as integers. Multiplication and division were added later for performance, when adding many more transistors (to have the "integer" logic) on the CPU die become feasible and the benefit outweighed the costs. This relation to HW should be IMO shown to beginner. – Ped7g Aug 17 '18 at 05:25
0
                           num=lo*divisor+hi

div   5, 2  => lo= 2; hi=  1   num= 2* 2+  1  = 5

div  -5, 2  => lo=-2; hi= -1   num=-2* 2+(-1) = -5

div   5, -2 => lo=-2; hi=  1   num=-2*-2+  1  = 5

div  -5, -2 => lo= 2; hi= -1   num= 2*-2+(-1) = -5

======================================================

divu  5, 2  => lo=2;          hi= 1 
   
divu -5, 2  => lo=2147483645; hi= 1 

exec as: divu 4294967291, 2  => lo=2147483645; hi= 1
  
 
divu  5, -2 => lo=0;          hi= 5;  

exec as: divu  5, 4294967294 => hi= 5;  lo=0 

 
divu -5, -2 => lo=0;          hi= 4294967291 (=-5 if you see in c'2);

exec as: divu 4294967291, 4294967294 => lo=0; hi=4294967291

tomerpacific
  • 4,704
  • 13
  • 34
  • 52
  • 2
    It would help a lot if you add some text explaining what you intend to show, and why/how your overview answers the question. Simply providing some - basically correct - calculations is not an answer unless you already understand both problem and answer. – Johan Bezem Apr 02 '21 at 10:58