There appears to be a problem with the way the DCPU rc1 does DIV. The current DCPU RC1 implementation does the following for DIV:
long val = (b << 16) / a;
b = (char)(int)(val >> 16);
this.ex = (char)(int)val;
Given b = 0xFFFF, a = 0x2 the result will be a = 0xFFFF and ex = 0x8000. This is wrong. (0xFFFF << 16) / 0x2 should = 0x7FFF8000. The problem is that given "(b << 16) / a", Java will sign extend it. So, what Java ends up doing is (0xFFFFFFFFFFFF0000 / 0x2) which produces 0xFFFFFFFFFFFF8000 and that's not what is described in the spec. In order for the DCPU to meet the spec it would need to do:
long val = b;
val <<= 16;
val /= a;
b = (char)(int)(val >> 16);
this.ex = (char)(int)val;
Now, in order to divide a 32 bit value by a 16 bit value, a different spec for DIV would be useful. On the x86 DIV does the following AX = DX:AX / divisor DX = DX:AX % divisor If the DCPU DIV instruction did:
int long = (ex << 16) | b;
b = (char)(tmp / a);
ex = (char)(tmp % b);
Then a 32 bit unsigned value could be divided using:
SET A, 0xFFFF ; Low Word
SET B, 0x000F ; High Word
SET EX, 0 ; Zero extend the value into EX
DIV B, 0x3
DIV A, 0x3
This will produce the result: A = 0x5555 B = 0x0005 Giving the correct result of 0x00055555. For signed division DVI should:
int tmp = (ex << 16) | b;
b = (char)(tmp / (short)a);
ex = (char)(tmp % (short)b);
Then a 32 bit value could be divided using:
SET A, 0x0001 ; Low Word
SET B, 0xFFF0 ; High Word
SET EX, 0xFFFF ; Zero extend the value into EX (only if dividend is signed)
DIV B, 0x3
DIV A, 0x3
This should produce the result: A = 0xAAAB B = 0xFFFB Giving the correct result of 0xFFFBAAAB.
Finally, let me say I haven't had this much fun in a long time. Thank's Notch!