diff options
author | mischief <mischief@offblast.org> | 2014-02-01 12:27:07 -0800 |
---|---|---|
committer | mischief <mischief@offblast.org> | 2014-02-01 12:27:07 -0800 |
commit | 1fe36bf84947198199b0dcf895aedfd584521e84 (patch) | |
tree | 8d3430fb23f0f1d6e4d46c7cfc7fb5a44bce6dc6 /sys/src/cmd/aux/realemu | |
parent | 08bb4afb528e91b46ae8eb13277ad51cf8d724ba (diff) |
realemu: implement IDIV, mark 0xE0000 writeable, fix DIV overfow trap
Diffstat (limited to 'sys/src/cmd/aux/realemu')
-rw-r--r-- | sys/src/cmd/aux/realemu/xec.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/sys/src/cmd/aux/realemu/xec.c b/sys/src/cmd/aux/realemu/xec.c index 5a5f8a8cf..90c8bc1ec 100644 --- a/sys/src/cmd/aux/realemu/xec.c +++ b/sys/src/cmd/aux/realemu/xec.c @@ -769,12 +769,58 @@ opdiv(Cpu *cpu, Inst *i) n = (uvlong)ar(ra)<<s | (uvlong)ar(qa); q = n/d; if(q > m) - trap(cpu, EGPF); + trap(cpu, EDIV0); r = n%d; aw(ra, r); aw(qa, q); } - + +static void +opidiv(Cpu *cpu, Inst *i) +{ + Iarg *qa, *ra; + vlong n, q, min, max; + long r, d; + int s; + + s = i->a1->len*8; + d = ars(i->a1); + if(d == 0) + trap(cpu, EDIV0); + if(s == 8){ + qa = areg(cpu, 1, RAX); + ra = adup(qa); + ra->tag |= TH; + } else { + qa = areg(cpu, i->olen, RAX); + ra = areg(cpu, i->olen, RDX); + } + n = (vlong)ars(ra)<<s | (uvlong)ars(qa); + q = n/d; + r = n%d; + + /* check for overflow based on operand size */ + switch(s) { + case 8: + min = (char)0x80; + max = 0x7F; + break; + case 16: + min = (short)0x8000; + max = 0x7FFF; + break; + case 32: + min = (long)0x80000000; + max = 0x7FFFFFFF; + break; + } + + if(q > max || q < min) + trap(cpu, EDIV0); + + aw(ra, r); + aw(qa, q); +} static int cctrue(Cpu *cpu, Inst *i) @@ -1249,6 +1295,7 @@ static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = { [OMUL] = opmul, [OIMUL] = opimul, [ODIV] = opdiv, + [OIDIV] = opidiv, [OLEA] = oplea, [OMOV] = opmov, |