]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/aux/realemu/xec.c
realemu: implement IDIV, mark 0xE0000 writeable, fix DIV overfow trap
[plan9front.git] / sys / src / cmd / aux / realemu / xec.c
index c39ad27b5295e94cdf7a2d19cad27f298b0afadd..90c8bc1ec36b8c3a5c38efbf67e67f6a89d12c0e 100644 (file)
@@ -15,6 +15,7 @@ push(Iarg *sp, Iarg *a)
 
        p = amem(sp->cpu, a->len, RSS, ar(sp));
        p->off -= a->len;
+       p->off &= mask(sp->len*8);
        aw(p, ar(a));
        aw(sp, p->off);
 }
@@ -485,7 +486,7 @@ opror(Cpu *cpu, Inst *i)
 }
 
 static void
-opbt(Cpu *cpu, Inst *i)
+opbittest(Cpu *cpu, Inst *i)
 {
        ulong a, m;
        int n, s;
@@ -496,7 +497,7 @@ opbt(Cpu *cpu, Inst *i)
        s = x->len*8;
        if(x->tag == TMEM){
                x = adup(x);
-               x->off += n / s;
+               x->off += (n / s) * x->len;
                x->off &= mask(i->alen*8);
        }
        a = ar(x);
@@ -768,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)
@@ -931,9 +978,9 @@ opcpuid(Cpu *cpu, Inst *)
        } tab[] = {
                0,
                        5,
-                       0x756e6547,
-                       0x49656e69,
-                       0x6c65746e,
+                       0x756e6547, /* Genu */
+                       0x6c65746e, /* ntel */
+                       0x49656e69, /* ineI */
                1,
                        4<<8,
                        0x00000000,
@@ -969,9 +1016,10 @@ static void
 opmovs(Cpu *cpu, Inst *i)
 {
        Iarg *cx, *d, *s;
-       ulong c;
+       ulong c, m;
        int n;
 
+       m = mask(i->alen*8);
        d = adup(i->a1);
        s = adup(i->a2);
        n = s->len;
@@ -987,7 +1035,9 @@ opmovs(Cpu *cpu, Inst *i)
        while(c){
                aw(d, ar(s));
                d->off += n;
+               d->off &= m;
                s->off += n;
+               s->off &= m;
                c--;
        }
        aw(areg(cpu, i->alen, RDI), d->off);
@@ -1000,9 +1050,10 @@ static void
 oplods(Cpu *cpu, Inst *i)
 {
        Iarg *cx, *s;
-       ulong c;
+       ulong c, m;
        int n;
 
+       m = mask(i->alen*8);
        s = adup(i->a2);
        n = s->len;
        if(cpu->reg[RFL] & DF)
@@ -1016,8 +1067,10 @@ oplods(Cpu *cpu, Inst *i)
        }
        if(c){
                s->off += n*(c-1);
+               s->off &= m;
                aw(i->a1, ar(s));
                s->off += n;
+               s->off &= m;
        }
        aw(areg(cpu, i->alen, RSI), s->off);
        if(cx)
@@ -1028,9 +1081,10 @@ static void
 opstos(Cpu *cpu, Inst *i)
 {
        Iarg *cx, *d;
-       ulong c, a;
+       ulong c, a, m;
        int n;
 
+       m = mask(i->alen*8);
        d = adup(i->a1);
        n = d->len;
        if(cpu->reg[RFL] & DF)
@@ -1046,6 +1100,7 @@ opstos(Cpu *cpu, Inst *i)
        while(c){
                aw(d, a);
                d->off += n;
+               d->off &= m;
                c--;
        }
        aw(areg(cpu, i->alen, RDI), d->off);
@@ -1054,28 +1109,27 @@ opstos(Cpu *cpu, Inst *i)
 }
 
 static int
-repcond(Cpu *cpu, int rep)
+repcond(ulong *f, int rep)
 {
-       switch(rep){
-       case OREPNE:
-               return (cpu->reg[RFL] & ZF) == 0;
-       case OREPE:
-       default:
-               return !rep || (cpu->reg[RFL] & ZF) != 0;
-       }
+       if(rep == OREPNE)
+               return (*f & ZF) == 0;
+       return (*f & ZF) != 0;
 }
 
 static void
 opscas(Cpu *cpu, Inst *i)
 {
-       Iarg *cx, *s;
-       ulong c;
+       Iarg *cx, *d;
+       ulong *f, c, m;
        long a;
-       int n;
+       int n, z;
 
-       s = adup(i->a1);
-       n = s->len;
-       if(cpu->reg[RFL] & DF)
+       m = mask(i->alen*8);
+       d = adup(i->a1);
+       n = d->len;
+       z = n*8;
+       f = cpu->reg + RFL;
+       if(*f & DF)
                n = -n;
        if(i->rep){
                cx = areg(cpu, i->alen, RCX);
@@ -1086,13 +1140,14 @@ opscas(Cpu *cpu, Inst *i)
        }
        a = ars(i->a2);
        while(c){
-               sub(cpu->reg + RFL, a, ars(s), 0, s->len*8);
-               s->off += n;
+               sub(f, a, ars(d), 0, z);
+               d->off += n;
+               d->off &= m;
                c--;
-               if(repcond(cpu, i->rep))
+               if(!repcond(f, i->rep))
                        break;
        }
-       aw(areg(cpu, i->alen, RDI), s->off);
+       aw(areg(cpu, i->alen, RDI), d->off);
        if(cx)
                aw(cx, c);
 }
@@ -1101,13 +1156,16 @@ static void
 opcmps(Cpu *cpu, Inst *i)
 {
        Iarg *cx, *s, *d;
-       ulong c;
-       int n;
+       ulong *f, c, m;
+       int n, z;
 
+       m = mask(i->alen*8);
        d = adup(i->a1);
        s = adup(i->a2);
        n = s->len;
-       if(cpu->reg[RFL] & DF)
+       z = n*8;
+       f = cpu->reg + RFL;
+       if(*f & DF)
                n = -n;
        if(i->rep){
                cx = areg(cpu, i->alen, RCX);
@@ -1117,11 +1175,13 @@ opcmps(Cpu *cpu, Inst *i)
                c = 1;
        }
        while(c){
-               sub(cpu->reg + RFL, ars(s), ars(d), 0, s->len*8);
+               sub(f, ars(s), ars(d), 0, z);
                s->off += n;
+               s->off &= m;
                d->off += n;
+               d->off &= m;
                c--;
-               if(repcond(cpu, i->rep))
+               if(!repcond(f, i->rep))
                        break;
        }
        aw(areg(cpu, i->alen, RDI), d->off);
@@ -1208,10 +1268,10 @@ static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
        [OROL] = oprol,
        [OROR] = opror,
 
-       [OBT] = opbt,
-       [OBTS] = opbt,
-       [OBTR] = opbt,
-       [OBTC] = opbt,
+       [OBT] = opbittest,
+       [OBTS] = opbittest,
+       [OBTR] = opbittest,
+       [OBTC] = opbittest,
 
        [OBSF] = opbitscan,
        [OBSR] = opbitscan,
@@ -1235,6 +1295,7 @@ static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
        [OMUL] = opmul,
        [OIMUL] = opimul,
        [ODIV] = opdiv,
+       [OIDIV] = opidiv,
 
        [OLEA] = oplea,
        [OMOV] = opmov,