jehanne/sys/src/cmd/hmi/realemu/xec.c

1555 lines
24 KiB
C

#include <u.h>
#include <lib9.h>
#include "dat.h"
#include "fns.h"
#define sign(s) (1UL<<((s)-1))
#define mask(s) (sign(s)|(sign(s)-1))
static void
push(Iarg *sp, Iarg *a)
{
print_func_entry();
Iarg *p;
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);
print_func_exit();
}
static void
pop(Iarg *sp, Iarg *a)
{
print_func_entry();
Iarg *p;
p = amem(sp->cpu, a->len, RSS, ar(sp));
aw(a, ar(p));
aw(sp, p->off + a->len);
print_func_exit();
}
static void
jump(Iarg *to)
{
print_func_entry();
Cpu *cpu;
cpu = to->cpu;
switch(to->atype){
default:
abort();
case AMp:
to = afar(to, 1, to->len);
case AAp:
cpu->reg[RCS] = to->seg;
case AJb:
case AJv:
cpu->reg[RIP] = to->off;
break;
case AEv:
cpu->reg[RIP] = ar(to);
break;
}
print_func_exit();
}
static void
opcall(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
sp = areg(cpu, cpu->slen, RSP);
switch(i->a1->atype){
default:
abort();
case AAp:
case AMp:
push(sp, areg(cpu, i->olen, RCS));
case AJv:
case AEv:
push(sp, areg(cpu, i->olen, RIP));
break;
}
jump(i->a1);
print_func_exit();
}
static void
opint(Cpu *cpu, Inst *i)
{
print_func_entry();
cpu->trap = ar(i->a1);
longjmp(cpu->jmp, 1);
print_func_exit();
}
static void
opiret(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
if(i->olen != 2)
trap(cpu, EBADOP);
sp = areg(cpu, cpu->slen, RSP);
pop(sp, areg(cpu, 2, RIP));
pop(sp, areg(cpu, 2, RCS));
pop(sp, areg(cpu, 2, RFL));
print_func_exit();
}
static void
opret(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
unsigned long c;
sp = areg(cpu, cpu->slen, RSP);
pop(sp, areg(cpu, i->olen, RIP));
if(c = ar(i->a1))
aw(sp, ar(sp) + c);
print_func_exit();
}
static void
opretf(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
unsigned long c;
sp = areg(cpu, cpu->slen, RSP);
pop(sp, areg(cpu, i->olen, RIP));
pop(sp, areg(cpu, i->olen, RCS));
if(c = ar(i->a1))
aw(sp, ar(sp) + c);
print_func_exit();
}
static void
openter(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp, *bp;
unsigned long oframe, nframe;
int j, n;
sp = areg(cpu, cpu->slen, RSP);
bp = areg(cpu, cpu->slen, RBP);
push(sp, bp);
oframe = ar(bp);
nframe = ar(sp);
n = ar(i->a2) % 32;
if(n > 0){
for(j=1; j<n; j++){
aw(bp, oframe - i->olen*j);
push(sp, bp);
}
push(sp, acon(cpu, i->olen, nframe));
}
aw(bp, nframe);
aw(sp, nframe - ar(i->a1));
print_func_exit();
}
static void
opleave(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
sp = areg(cpu, cpu->slen, RSP);
aw(sp, ar(areg(cpu, cpu->slen, RBP)));
pop(sp, areg(cpu, i->olen, RBP));
print_func_exit();
}
static void
oppush(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
sp = areg(cpu, cpu->slen, RSP);
if(i->a1->len == 1) /* 0x6A push imm8 */
push(sp, acon(cpu, i->olen, ar(i->a1)));
else
push(sp, i->a1);
print_func_exit();
}
static void
oppop(Cpu *cpu, Inst *i)
{
print_func_entry();
pop(areg(cpu, cpu->slen, RSP), i->a1);
print_func_exit();
}
static void
oppusha(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp, *osp;
sp = areg(cpu, cpu->slen, RSP);
osp = acon(cpu, i->olen, ar(sp));
push(sp, areg(cpu, i->olen, RAX));
push(sp, areg(cpu, i->olen, RCX));
push(sp, areg(cpu, i->olen, RDX));
push(sp, areg(cpu, i->olen, RBX));
push(sp, osp);
push(sp, areg(cpu, i->olen, RBP));
push(sp, areg(cpu, i->olen, RSI));
push(sp, areg(cpu, i->olen, RDI));
print_func_exit();
}
static void
oppopa(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *sp;
sp = areg(cpu, cpu->slen, RSP);
pop(sp, areg(cpu, i->olen, RDI));
pop(sp, areg(cpu, i->olen, RSI));
pop(sp, areg(cpu, i->olen, RBP));
pop(sp, areg(cpu, i->olen, RBX)); // RSP
pop(sp, areg(cpu, i->olen, RBX));
pop(sp, areg(cpu, i->olen, RDX));
pop(sp, areg(cpu, i->olen, RCX));
pop(sp, areg(cpu, i->olen, RAX));
print_func_exit();
}
static void
oppushf(Cpu *cpu, Inst *i)
{
print_func_entry();
push(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
print_func_exit();
}
static void
oppopf(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, o;
f = cpu->reg + RFL;
o = *f;
pop(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
*f &= ~(VM|RF);
*f |= (o & (VM|RF));
print_func_exit();
}
static void
oplahf(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, cpu->reg[RFL]);
print_func_exit();
}
static void
opsahf(Cpu *cpu, Inst *i)
{
print_func_entry();
enum { MASK = SF|ZF|AF|PF|CF };
unsigned long *f;
f = cpu->reg + RFL;
*f &= ~MASK;
*f |= (ar(i->a1) & MASK);
print_func_exit();
}
static void
opcli(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] &= ~IF;
print_func_exit();
}
static void
opsti(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] |= IF;
print_func_exit();
}
static void
opcld(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] &= ~DF;
print_func_exit();
}
static void
opstd(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] |= DF;
print_func_exit();
}
static void
opclc(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] &= ~CF;
print_func_exit();
}
static void
opstc(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] |= CF;
print_func_exit();
}
static void
opcmc(Cpu *cpu, Inst *inst)
{
print_func_entry();
cpu->reg[RFL] ^= CF;
print_func_exit();
}
static void
parity(unsigned long *f, unsigned long r)
{
print_func_entry();
static unsigned long tab[8] = {
0x96696996,
0x69969669,
0x69969669,
0x96696996,
0x69969669,
0x96696996,
0x96696996,
0x69969669,
};
r &= 0xFF;
if((tab[r/32] >> (r%32)) & 1)
*f &= ~PF;
else
*f |= PF;
print_func_exit();
}
static unsigned long
test(unsigned long *f, long r, int s)
{
print_func_entry();
*f &= ~(CF|SF|ZF|OF|PF);
r &= mask(s);
if(r == 0)
*f |= ZF;
if(r & sign(s))
*f |= SF;
parity(f, r);
print_func_exit();
return r;
}
static void
opshl(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, r, a, h;
int s, n;
if((n = ar(i->a2) & 31) == 0) {
print_func_exit();
return;
}
s = i->a1->len*8;
a = ar(i->a1);
f = cpu->reg + RFL;
r = test(f, a<<n, s);
h = sign(s);
aw(i->a1, r);
if((a<<(n-1)) & h)
*f |= CF;
if(n == 1 && ((a^r) & h))
*f |= OF;
print_func_exit();
}
static void
opshr(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a;
int s, n;
if((n = ar(i->a2) & 31) == 0) {
print_func_exit();
return;
}
s = i->a1->len*8;
a = ar(i->a1);
f = cpu->reg + RFL;
aw(i->a1, test(f, a>>n, s));
if(a & sign(n))
*f |= CF;
if(n == 1 && (a & sign(s)))
*f |= OF;
print_func_exit();
}
static void
opsar(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f;
long a;
int n;
if((n = ar(i->a2) & 31) == 0) {
print_func_exit();
return;
}
a = ars(i->a1);
f = cpu->reg + RFL;
aw(i->a1, test(f, a>>n, i->a1->len*8));
if(a & sign(n))
*f |= CF;
print_func_exit();
}
static void
opshld(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a;
int s, n;
if((n = ar(i->a3) & 31) == 0) {
print_func_exit();
return;
}
s = i->a1->len*8;
a = ar(i->a1);
f = cpu->reg + RFL;
aw(i->a1, test(f, (a<<n)|(ar(i->a2)>>(s-n)), s));
if((a<<(n-1)) & sign(s))
*f |= CF;
print_func_exit();
}
static void
opshrd(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a;
int s, n;
if((n = ar(i->a3) & 31) == 0) {
print_func_exit();
return;
}
s = i->a1->len*8;
a = ar(i->a1);
f = cpu->reg + RFL;
aw(i->a1, test(f, (a>>n)|(ar(i->a2)<<(s-n)), s));
if(a & sign(n))
*f |= CF;
print_func_exit();
}
static void
oprcl(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a, r;
int s, n;
s = i->a1->len*8;
n = ar(i->a2) % (s+1);
a = ar(i->a1);
r = (a<<n) | ((a>>(s-n))>>1);
f = cpu->reg + RFL;
if(*f & CF)
r |= sign(n);
aw(i->a1, r);
*f &= ~(CF|OF);
if((a>>(s-n)) & 1)
*f |= CF;
if((a ^ r) & sign(s))
*f |= OF;
parity(f, r);
print_func_exit();
}
static void
oprcr(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a, r, h;
int s, n;
s = i->a1->len*8;
n = ar(i->a2) % (s+1);
a = ar(i->a1);
h = a<<(s-n);
r = (a>>n) | (h<<1);
f = cpu->reg + RFL;
if(*f & CF)
r |= 1<<(s-n);
aw(i->a1, r);
*f &= ~(CF|OF);
if(h & sign(s))
*f |= CF;
if((a ^ r) & sign(s))
*f |= OF;
parity(f, r);
print_func_exit();
}
static void
oprol(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a, r;
int s, n;
s = i->a1->len*8;
n = ar(i->a2) & (s-1);
a = ar(i->a1);
r = (a<<n) | (a>>(s-n));
f = cpu->reg + RFL;
aw(i->a1, r);
*f &= ~(CF|OF);
if(r & 1)
*f |= CF;
if((a ^ r) & sign(s))
*f |= OF;
parity(f, r);
print_func_exit();
}
static void
opror(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, a, r;
int s, n;
s = i->a1->len*8;
n = ar(i->a2) & (s-1);
a = ar(i->a1);
r = (a>>n) | (a<<(s-n));
aw(i->a1, r);
f = cpu->reg + RFL;
*f &= ~(CF|OF);
if(r & sign(s))
*f |= CF;
if((a ^ r) & sign(s))
*f |= OF;
parity(f, r);
print_func_exit();
}
static void
opbittest(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long a, m;
int n, s;
Iarg *x;
n = ar(i->a2);
x = i->a1;
s = x->len*8;
if(x->tag == TMEM){
x = adup(x);
x->off += (n / s) * x->len;
x->off &= mask(i->alen*8);
}
a = ar(x);
n &= s-1;
m = 1<<n;
if(a & m)
cpu->reg[RFL] |= CF;
else
cpu->reg[RFL] &= ~CF;
switch(i->op){
case OBT:
break;
case OBTS:
aw(x, a | m);
break;
case OBTR:
aw(x, a & ~m);
break;
case OBTC:
aw(x, a ^ m);
break;
}
print_func_exit();
}
static void
opbitscan(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long a;
if((a = ar(i->a2)) == 0)
cpu->reg[RFL] |= ZF;
else {
int j;
if(i->op == OBSF){
for(j = 0; (a & (1<<j)) == 0; j++)
;
} else {
for(j = i->a2->len*8-1; (a & (1<<j)) == 0; j--)
;
}
aw(i->a1, j);
cpu->reg[RFL] &= ~ZF;
}
print_func_exit();
}
static void
opand(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8));
print_func_exit();
}
static void
opor(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, test(cpu->reg + RFL, ars(i->a1) | ars(i->a2), i->a1->len*8));
print_func_exit();
}
static void
opxor(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, test(cpu->reg + RFL, ars(i->a1) ^ ars(i->a2), i->a1->len*8));
print_func_exit();
}
static void
opnot(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, ~ar(i->a1));
print_func_exit();
}
static void
optest(Cpu *cpu, Inst *i)
{
print_func_entry();
test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8);
print_func_exit();
}
static unsigned long
add(unsigned long *f, long a, long b, int c, int s)
{
print_func_entry();
unsigned long r, cc, m, n;
*f &= ~(AF|CF|SF|ZF|OF|PF);
n = sign(s);
m = mask(s);
r = a + b + c;
r &= m;
if(r == 0)
*f |= ZF;
if(r & n)
*f |= SF;
cc = (a & b) | (~r & (a | b));
if(cc & n)
*f |= CF;
if((cc ^ (cc >> 1)) & (n>>1))
*f |= OF;
parity(f, r);
print_func_exit();
return r;
}
static unsigned long
sub(unsigned long *f, long a, long b, int c, int s)
{
print_func_entry();
unsigned long r, bc, n;
*f &= ~(AF|CF|SF|ZF|OF|PF);
r = a - b - c;
n = sign(s);
r &= mask(s);
if(r == 0)
*f |= ZF;
if(r & n)
*f |= SF;
a = ~a;
bc = (a & b) | (r & (a | b));
if(bc & n)
*f |= CF;
if((bc ^ (bc >> 1)) & (n>>1))
*f |= OF;
parity(f, r);
print_func_exit();
return r;
}
static void
opadd(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, add(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
print_func_exit();
}
static void
opadc(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f = cpu->reg + RFL;
aw(i->a1, add(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
print_func_exit();
}
static void
opsub(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
print_func_exit();
}
static void
opsbb(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f = cpu->reg + RFL;
aw(i->a1, sub(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
print_func_exit();
}
static void
opneg(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, sub(cpu->reg + RFL, 0, ars(i->a1), 0, i->a1->len*8));
print_func_exit();
}
static void
opcmp(Cpu *cpu, Inst *i)
{
print_func_entry();
sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8);
print_func_exit();
}
static void
opinc(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, o;
f = cpu->reg + RFL;
o = *f;
aw(i->a1, add(f, ars(i->a1), 1, 0, i->a1->len*8));
*f = (*f & ~CF) | (o & CF);
print_func_exit();
}
static void
opdec(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long *f, o;
f = cpu->reg + RFL;
o = *f;
aw(i->a1, sub(f, ars(i->a1), 1, 0, i->a1->len*8));
*f = (*f & ~CF) | (o & CF);
print_func_exit();
}
static void
opmul(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *la, *ha;
unsigned long l, h, m;
unsigned long long r;
int s;
s = i->a2->len*8;
m = mask(s);
r = ar(i->a2) * ar(i->a3);
l = r & m;
h = (r >> s) & m;
if(i->a1->atype != AAX)
abort();
la = areg(cpu, i->a2->len, RAX);
if(s == 8){
ha = adup(la);
ha->tag |= TH;
} else
ha = areg(cpu, i->a2->len, RDX);
aw(la, l);
aw(ha, h);
if(h)
cpu->reg[RFL] |= (CF|OF);
else
cpu->reg[RFL] &= ~(CF|OF);
print_func_exit();
}
static void
opimul(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long l, h, m, n;
long long r;
int s;
s = i->a2->len*8;
m = mask(s);
n = sign(s);
r = ars(i->a2) * ars(i->a3);
h = (r >> s) & m;
l = r & m;
if(i->a1->atype == AAX){
Iarg *la, *ha;
la = areg(cpu, i->a2->len, RAX);
if(s == 8){
ha = adup(la);
ha->tag |= TH;
}else
ha = areg(cpu, i->a2->len, RDX);
aw(la, l);
aw(ha, h);
} else
aw(i->a1, l);
if((r > (long long)n-1) || (r < -(long long)n))
cpu->reg[RFL] |= (CF|OF);
else
cpu->reg[RFL] &= ~(CF|OF);
print_func_exit();
}
static void
opdiv(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *qa, *ra;
unsigned long long n, q;
unsigned long m, r, d;
int s;
s = i->a1->len*8;
m = mask(s);
d = ar(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 = (unsigned long long)ar(ra)<<s | (unsigned long long)ar(qa);
q = n/d;
if(q > m)
trap(cpu, EDIV0);
r = n%d;
aw(ra, r);
aw(qa, q);
print_func_exit();
}
static void
opidiv(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *qa, *ra;
long long 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 = (long long)ars(ra)<<s | (unsigned long long)ars(qa);
q = n/d;
r = n%d;
max = sign(s)-1;
min = ~max;
if(q > max || q < min)
trap(cpu, EDIV0);
aw(ra, r);
aw(qa, q);
print_func_exit();
}
static int
cctrue(Cpu *cpu, Inst *i)
{
print_func_entry();
enum { SO = 1<<16, /* pseudo-flag SF != OF */ };
static unsigned long test[] = {
OF, /* JO, JNO */
CF, /* JC, JNC */
ZF, /* JZ, JNZ */
CF|ZF, /* JBE,JA */
SF, /* JS, JNS */
PF, /* JP, JNP */
SO, /* JL, JGE */
SO|ZF, /* JLE,JG */
};
unsigned long f, t;
unsigned char c;
c = i->code;
switch(c){
case 0xE3: /* JCXZ */
print_func_exit();
return ar(areg(cpu, i->alen, RCX)) == 0;
case 0xEB: /* JMP */
case 0xE9:
case 0xEA:
case 0xFF:
print_func_exit();
return 1;
default:
f = cpu->reg[RFL];
if(((f&SF)!=0) ^ ((f&OF)!=0))
f |= SO;
t = test[(c>>1)&7];
print_func_exit();
return ((t&f) != 0) ^ (c&1);
}
}
static void
opjump(Cpu *cpu, Inst *i)
{
print_func_entry();
if(cctrue(cpu, i))
jump(i->a1);
print_func_exit();
}
static void
opset(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, cctrue(cpu, i));
print_func_exit();
}
static void
oploop(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx;
unsigned long c;
switch(i->op){
default:
abort();
case OLOOPNZ:
if(cpu->reg[RFL] & ZF) {
print_func_exit();
return;
}
break;
case OLOOPZ:
if((cpu->reg[RFL] & ZF) == 0) {
print_func_exit();
return;
}
break;
case OLOOP:
break;
}
cx = areg(cpu, i->alen, RCX);
c = ar(cx) - 1;
aw(cx, c);
if(c)
jump(i->a1);
print_func_exit();
}
static void
oplea(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, i->a2->off);
print_func_exit();
}
static void
opmov(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, ar(i->a2));
print_func_exit();
}
static void
opcbw(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(areg(cpu, i->olen, RAX), ars(areg(cpu, i->olen>>1, RAX)));
print_func_exit();
}
static void
opcwd(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(areg(cpu, i->olen, RDX), ars(areg(cpu, i->olen, RAX))>>(i->olen*8-1));
print_func_exit();
}
static void
opmovsx(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, ars(i->a2));
print_func_exit();
}
static void
opxchg(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long x;
x = ar(i->a1);
aw(i->a1, ar(i->a2));
aw(i->a2, x);
print_func_exit();
}
static void
oplfp(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *p;
p = afar(i->a3, i->olen, i->olen);
aw(i->a1, p->seg);
aw(i->a2, p->off);
print_func_exit();
}
static void
opbound(Cpu *cpu, Inst *i)
{
print_func_entry();
unsigned long p, s, e;
p = ar(i->a1);
s = ar(i->a2);
e = ar(i->a3);
if((p < s) || (p >= e))
trap(cpu, EBOUND);
print_func_exit();
}
static void
opxlat(Cpu *cpu, Inst *i)
{
print_func_entry();
aw(i->a1, ar(amem(cpu, i->a1->len, i->sreg, ar(areg(cpu, i->alen, i->a2->reg)) + ar(i->a1))));
print_func_exit();
}
static void
opcpuid(Cpu *cpu, Inst *inst)
{
print_func_entry();
static struct {
unsigned long level;
unsigned long ax;
unsigned long bx;
unsigned long cx;
unsigned long dx;
} tab[] = {
0,
5,
0x756e6547, /* Genu */
0x6c65746e, /* ntel */
0x49656e69, /* ineI */
1,
4<<8,
0x00000000,
0x00000000,
0x00000000,
2,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
3,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
int i;
for(i=0; i<nelem(tab); i++){
if(tab[i].level == cpu->reg[RAX]){
cpu->reg[RAX] = tab[i].ax;
cpu->reg[RBX] = tab[i].bx;
cpu->reg[RCX] = tab[i].cx;
cpu->reg[RDX] = tab[i].dx;
print_func_exit();
return;
}
}
trap(cpu, EBADOP);
print_func_exit();
}
static void
opmovs(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx, *d, *s;
unsigned long c, m;
int n;
m = mask(i->alen*8);
d = adup(i->a1);
s = adup(i->a2);
n = s->len;
if(cpu->reg[RFL] & DF)
n = -n;
if(i->rep){
cx = areg(cpu, i->alen, RCX);
c = ar(cx);
} else {
cx = nil;
c = 1;
}
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);
aw(areg(cpu, i->alen, RSI), s->off);
if(cx)
aw(cx, 0);
print_func_exit();
}
static void
oplods(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx, *s;
unsigned long c, m;
int n;
m = mask(i->alen*8);
s = adup(i->a2);
n = s->len;
if(cpu->reg[RFL] & DF)
n = -n;
if(i->rep){
cx = areg(cpu, i->alen, RCX);
c = ar(cx);
} else {
cx = nil;
c = 1;
}
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)
aw(cx, 0);
print_func_exit();
}
static void
opstos(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx, *d;
unsigned long c, a, m;
int n;
m = mask(i->alen*8);
d = adup(i->a1);
n = d->len;
if(cpu->reg[RFL] & DF)
n = -n;
if(i->rep){
cx = areg(cpu, i->alen, RCX);
c = ar(cx);
} else {
cx = nil;
c = 1;
}
a = ar(i->a2);
while(c){
aw(d, a);
d->off += n;
d->off &= m;
c--;
}
aw(areg(cpu, i->alen, RDI), d->off);
if(cx)
aw(cx, c);
print_func_exit();
}
static int
repcond(unsigned long *f, int rep)
{
print_func_entry();
if(rep == OREPNE) {
print_func_exit();
return (*f & ZF) == 0;
}
print_func_exit();
return (*f & ZF) != 0;
}
static void
opscas(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx, *d;
unsigned long *f, c, m;
long a;
int n, z;
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);
c = ar(cx);
} else {
cx = nil;
c = 1;
}
a = ars(i->a2);
while(c){
sub(f, a, ars(d), 0, z);
d->off += n;
d->off &= m;
c--;
if(!repcond(f, i->rep))
break;
}
aw(areg(cpu, i->alen, RDI), d->off);
if(cx)
aw(cx, c);
print_func_exit();
}
static void
opcmps(Cpu *cpu, Inst *i)
{
print_func_entry();
Iarg *cx, *s, *d;
unsigned long *f, c, m;
int n, z;
m = mask(i->alen*8);
d = adup(i->a1);
s = adup(i->a2);
n = s->len;
z = n*8;
f = cpu->reg + RFL;
if(*f & DF)
n = -n;
if(i->rep){
cx = areg(cpu, i->alen, RCX);
c = ar(cx);
} else {
cx = nil;
c = 1;
}
while(c){
sub(f, ars(s), ars(d), 0, z);
s->off += n;
s->off &= m;
d->off += n;
d->off &= m;
c--;
if(!repcond(f, i->rep))
break;
}
aw(areg(cpu, i->alen, RDI), d->off);
aw(areg(cpu, i->alen, RSI), s->off);
if(cx)
aw(cx, c);
print_func_exit();
}
static void
opin(Cpu *cpu, Inst *i)
{
print_func_entry();
Bus *io;
io = cpu->port;
aw(i->a1, io->r(io->aux, ar(i->a2) & 0xFFFF, i->a1->len));
print_func_exit();
}
static void
opout(Cpu *cpu, Inst *i)
{
print_func_entry();
Bus *io;
io = cpu->port;
io->w(io->aux, ar(i->a1) & 0xFFFF, ar(i->a2), i->a2->len);
print_func_exit();
}
static void
opnop(Cpu *cpu, Inst *inst)
{
print_func_entry();
print_func_exit();
}
static void
ophlt(Cpu *cpu, Inst *inst)
{
print_func_entry();
trap(cpu, EHALT);
print_func_exit();
}
static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
[OINT] = opint,
[OIRET] = opiret,
[OCALL] = opcall,
[OJUMP] = opjump,
[OSET] = opset,
[OLOOP] = oploop,
[OLOOPZ] = oploop,
[OLOOPNZ] = oploop,
[ORET] = opret,
[ORETF] = opretf,
[OENTER] = openter,
[OLEAVE] = opleave,
[OPUSH] = oppush,
[OPOP] = oppop,
[OPUSHF] = oppushf,
[OPOPF] = oppopf,
[OLAHF] = oplahf,
[OSAHF] = opsahf,
[OPUSHA] = oppusha,
[OPOPA] = oppopa,
[OCLI] = opcli,
[OSTI] = opsti,
[OCLC] = opclc,
[OSTC] = opstc,
[OCMC] = opcmc,
[OCLD] = opcld,
[OSTD] = opstd,
[OSHL] = opshl,
[OSHR] = opshr,
[OSAR] = opsar,
[OSHLD] = opshld,
[OSHRD] = opshrd,
[ORCL] = oprcl,
[ORCR] = oprcr,
[OROL] = oprol,
[OROR] = opror,
[OBT] = opbittest,
[OBTS] = opbittest,
[OBTR] = opbittest,
[OBTC] = opbittest,
[OBSF] = opbitscan,
[OBSR] = opbitscan,
[OAND] = opand,
[OOR] = opor,
[OXOR] = opxor,
[ONOT] = opnot,
[OTEST] = optest,
[OADD] = opadd,
[OADC] = opadc,
[OSUB] = opsub,
[OSBB] = opsbb,
[ONEG] = opneg,
[OCMP] = opcmp,
[OINC] = opinc,
[ODEC] = opdec,
[OMUL] = opmul,
[OIMUL] = opimul,
[ODIV] = opdiv,
[OIDIV] = opidiv,
[OLEA] = oplea,
[OMOV] = opmov,
[OCBW] = opcbw,
[OCWD] = opcwd,
[OMOVZX] = opmov,
[OMOVSX] = opmovsx,
[OXCHG] = opxchg,
[OLFP] = oplfp,
[OBOUND] = opbound,
[OXLAT] = opxlat,
[OCPUID] = opcpuid,
[OMOVS] = opmovs,
[OLODS] = oplods,
[OSTOS] = opstos,
[OSCAS] = opscas,
[OCMPS] = opcmps,
[OIN] = opin,
[OOUT] = opout,
[ONOP] = opnop,
[OHLT] = ophlt,
};
void
trap(Cpu *cpu, int e)
{
print_func_entry();
cpu->reg[RIP] = cpu->oldip;
cpu->trap = e;
longjmp(cpu->jmp, 1);
print_func_exit();
}
int
intr(Cpu *cpu, int v)
{
print_func_entry();
Iarg *sp, *ip, *cs, *iv;
if(v < 0 || v > 0xff || cpu->olen != 2) {
print_func_exit();
return -1;
}
sp = areg(cpu, cpu->slen, RSP);
cs = areg(cpu, 2, RCS);
ip = areg(cpu, 2, RIP);
iv = amem(cpu, 2, R0S, v * 4);
push(sp, areg(cpu, 2, RFL));
push(sp, cs);
push(sp, ip);
cpu->reg[RIP] = ar(iv);
iv->off += 2;
cpu->reg[RCS] = ar(iv);
print_func_exit();
return 0;
}
int
xec(Cpu *cpu, int n)
{
print_func_entry();
if(setjmp(cpu->jmp)) {
print_func_exit();
return cpu->trap;
}
while(n--){
void (*f)(Cpu *, Inst *);
Iarg *ip;
Inst i;
cpu->ic++;
ip = amem(cpu, 1, RCS, cpu->oldip = cpu->reg[RIP]);
decode(ip, &i);
cpu->reg[RIP] = ip->off;
if((f = exctab[i.op]) == nil)
trap(cpu, EBADOP);
f(cpu, &i);
}
print_func_exit();
return n;
}