§ portable86.cpp
Портативный код для запуска X86 везде.
#define AX_ regs[0]
#define CX_ regs[1]
#define DX_ regs[2]
#define BX_ regs[3]
#define SP_ regs[4]
#define BP_ regs[5]
#define SI_ regs[6]
#define DI_ regs[7]
#define AL_ (regs[0]&255)
#define CL_ (regs[1]&255)
#define DL_ (regs[2]&255)
#define BL_ (regs[3]&255)
#define AH_ (regs[0]>>8)
#define CH_ (regs[1]>>8)
#define DH_ (regs[2]>>8)
#define BH_ (regs[3]>>8)
#define REPINC(a,b) { if (flags & D_FLAG) a-=b; else a+=b; }
#define REPINIT { if (rep && CX_ == 0) break; }
uint16_t flags;
uint32_t rdtsc;
enum FlagBit
{
C_FLAG = 0x0001,
P_FLAG = 0x0004,
A_FLAG = 0x0010,
Z_FLAG = 0x0040,
N_FLAG = 0x0080,
T_FLAG = 0x0100,
I_FLAG = 0x0200,
D_FLAG = 0x0400,
V_FLAG = 0x0800
};
enum RegsALL {
REG_AX = 0, REG_AL = 0,
REG_CX = 1, REG_CL = 1,
REG_DX = 2, REG_DL = 2,
REG_BX = 3, REG_BL = 3,
REG_SP = 4, REG_AH = 4,
REG_BP = 5, REG_CH = 5,
REG_SI = 6, REG_DH = 6,
REG_DI = 7, REG_BH = 7,
};
enum SegID {
SEG_ES = 0,
SEG_CS = 1,
SEG_SS = 2,
SEG_DS = 3,
SEG_FS = 4,
SEG_GS = 5
};
enum Prefixes {
REPNZ = 1,
REPZ = 2
};
class portable86
{
protected:
uint8_t opcode, rmdat, cpu_reg, cpu_mod, cpu_rm, inhlt;
uint8_t sel_seg, rep;
uint16_t eaaddr;
uint32_t segment;
uint8_t znptable8[256];
public:
uint16_t regs[8];
uint16_t segs[6];
uint32_t seg_cs, seg_ss, seg_es, seg_ds, seg_fs, seg_gs;
uint16_t ip, ip_start;
uint32_t tstates;
virtual uint8_t ioread(uint16_t a) { return 0; };
virtual void iowrite(uint16_t a, uint8_t b) { };
virtual uint8_t readmemb(uint32_t a) { return 0; };
virtual void writememb(uint32_t a, uint8_t b) { };
portable86()
{
initcpu();
}
void initcpu()
{
unsigned char d, c = 0;
do
{
d = (c>>4) ^ c;
d = (d>>2) ^ d;
d = (d>>1) ^ d;
znptable8[c] = (d&1) ? 0 : P_FLAG;
if (c == 0) znptable8[c] |= Z_FLAG;
if (c&0x80) znptable8[c] |= N_FLAG;
c++;
}
while (c != 0);
loadcs(0xf000);
loadds(0x0000);
loades(0x0000);
loadss(0x0000);
ip = 0x0000;
SP_ = 0x0000;
AX_ = 0x0000;
inhlt = 0;
tstates = 0;
}
void setznp8(uint8_t val)
{
flags &= ~0xC4;
flags |= znptable8[val];
}
void setznp16(uint16_t val)
{
flags &= ~0xC4;
if (val & 0x8000) flags |= N_FLAG;
if (val == 0) flags |= Z_FLAG;
flags |= (znptable8[val&0xff] & P_FLAG);
}
uint8_t setadd8(uint8_t a, uint8_t b)
{
uint16_t c = (uint16_t)a + (uint16_t)b;
flags &= ~0x8D5;
flags |= znptable8[c & 0xFF];
if (c & 0x100) flags |= C_FLAG;
if (!((a^b)&0x80)&&((a^c)&0x80)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint8_t setadd8nc(uint8_t a, uint8_t b)
{
uint16_t c = (uint16_t)a + (uint16_t)b;
flags &= ~0x8D4;
flags |= znptable8[c&0xFF];
if (!((a^b)&0x80)&&((a^c)&0x80)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint8_t setadc8(uint8_t a, uint8_t b, uint8_t tempc)
{
uint16_t c = (uint16_t)a + (uint16_t)b + tempc;
flags &= ~0x8D5;
flags |= znptable8[c&0xFF];
if (c & 0x100) flags |= C_FLAG;
if (!((a^b)&0x80)&&((a^c)&0x80)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setadd16(uint16_t a, uint16_t b)
{
uint32_t c = (uint32_t)a + (uint32_t)b;
flags &= ~0x8D5;
setznp16(c & 0xffff);
if (c & 0x10000) flags |= C_FLAG;
if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setadd16nc(uint16_t a, uint16_t b)
{
uint32_t c = (uint32_t)a + (uint32_t)b;
flags &= ~0x8D4;
setznp16(c & 0xffff);
if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setadc16(uint16_t a, uint16_t b, uint8_t tempc)
{
uint32_t c = (uint32_t)a + (uint32_t)b + tempc;
flags &= ~0x8D5;
setznp16(c & 0xffff);
if (c & 0x10000) flags |= C_FLAG;
if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags |= V_FLAG;
if (((a&0xF)+(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint8_t setsub8(uint8_t a, uint8_t b)
{
uint16_t c = (uint16_t)a - (uint16_t)b;
flags &= ~0x8D5;
flags |= znptable8[c&0xFF];
if (c&0x100) flags|=C_FLAG;
if ((a^b)&(a^c)&0x80) flags|=V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG;
return c;
}
uint8_t setsub8nc(uint8_t a, uint8_t b)
{
uint16_t c=(uint16_t)a - (uint16_t)b;
flags &= ~0x8D4;
flags |= znptable8[c&0xFF];
if ((a^b)&(a^c)&0x80) flags |= V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint8_t setsbc8(uint8_t a, uint8_t b, uint8_t tempc)
{
uint16_t c = (uint16_t)a - (((uint16_t)b) + tempc);
flags &= ~0x8D5;
flags |= znptable8[c&0xFF];
if (c&0x100) flags |= C_FLAG;
if ((a^b)&(a^c)&0x80) flags |= V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setsub16(uint16_t a, uint16_t b)
{
uint32_t c = (uint32_t)a - (uint32_t)b;
flags &= ~0x8D5;
setznp16(c & 0xffff);
if (c&0x10000) flags |= C_FLAG;
if ((a^b)&(a^c)&0x8000) flags |= V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setsub16nc(uint16_t a, uint16_t b)
{
uint32_t c = (uint32_t)a - (uint32_t)b;
flags &= ~0x8D4;
setznp16(c & 0xffff);
flags &= ~0x4;
flags |= (znptable8[c&0xFF]&4);
if ((a^b)&(a^c)&0x8000) flags |= V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint16_t setsbc16(uint16_t a, uint16_t b, uint8_t tempc)
{
uint32_t c = (uint32_t)a - (((uint32_t)b) + tempc);
flags &= ~0x8D5;
setznp16(c & 0xffff);
flags &= ~0x4;
flags |= (znptable8[c&0xFF]&4);
if (c&0x10000) flags |= C_FLAG;
if ((a^b)&(a^c)&0x8000) flags |= V_FLAG;
if (((a&0xF)-(b&0xF))&0x10) flags |= A_FLAG;
return c;
}
uint8_t setor8(uint8_t a, uint8_t b)
{
uint8_t c = a | b;
setznp8(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint16_t setor16(uint16_t a, uint16_t b)
{
uint16_t c = a | b;
setznp16(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint8_t setand8(uint8_t a, uint8_t b)
{
uint8_t c = a & b;
setznp8(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint16_t setand16(uint16_t a, uint16_t b)
{
uint16_t c = a & b;
setznp16(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint8_t setxor8(uint8_t a, uint8_t b)
{
uint8_t c = a ^ b;
setznp8(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint16_t setxor16(uint16_t a, uint16_t b)
{
uint16_t c = a ^ b;
setznp16(c);
flags &=~ (C_FLAG | V_FLAG | A_FLAG);
return c;
}
uint16_t readmemw(uint32_t s, uint16_t a)
{
uint8_t l = readmemb(s + a);
uint8_t h = readmemb(s + ((a+1) & 0xffff));
return (h<<8) | l;
}
void writememw(uint32_t s, uint16_t a, uint16_t v)
{
writememb(s + a, v);
writememb(s + ((a+1) & 0xffff), v >> 8);
}
void loadcs(uint16_t s) { segs[SEG_CS] = s; seg_cs = (uint32_t)s << 4; }
void loadss(uint16_t s) { segs[SEG_SS] = s; seg_ss = (uint32_t)s << 4; }
void loades(uint16_t s) { segs[SEG_ES] = s; seg_es = (uint32_t)s << 4; }
void loadds(uint16_t s) { segs[SEG_DS] = s; seg_ds = (uint32_t)s << 4; }
void loadfs(uint16_t s) { segs[SEG_FS] = s; seg_fs = (uint32_t)s << 4; }
void loadgs(uint16_t s) { segs[SEG_GS] = s; seg_gs = (uint32_t)s << 4; }
inline uint8_t getbyte() { return readmemb(seg_cs + (ip++)); }
uint16_t getword()
{
uint8_t l = getbyte();
return ((uint16_t)getbyte() << 8) | l;
}
void fetchea()
{
rmdat = getbyte();
cpu_mod = (rmdat >> 6) & 3;
cpu_reg = (rmdat >> 3) & 7;
cpu_rm = rmdat & 7;
eaaddr = 0;
switch (cpu_rm) {
case 0: eaaddr = (BX_ + SI_); break;
case 1: eaaddr = (BX_ + DI_); break;
case 2: eaaddr = (BP_ + SI_); break;
case 3: eaaddr = (BP_ + DI_); break;
case 4: eaaddr = SI_; break;
case 5: eaaddr = DI_; break;
case 6: eaaddr = BP_; break;
case 7: eaaddr = BX_; break;
}
if (sel_seg == 0 && ((cpu_rm == 6 && cpu_mod) || (cpu_rm == 2) || (cpu_rm == 3)))
segment = seg_ss;
switch (cpu_mod) {
case 0: if (cpu_rm == 6) eaaddr = getword(); break;
case 1: eaaddr += (signed char) getbyte(); break;
case 2: eaaddr += getword(); break;
case 3: eaaddr = 0; break;
}
}
uint8_t getr8(uint8_t id) { return id & 4 ? regs[id&3] >> 8 : regs[id&3]; }
void setr8(uint8_t id, uint8_t v)
{
if (id & 4) {
regs[id&3] = (regs[id&3] & 0x00ff) | ((uint16_t)v << 8);
} else {
regs[id&3] = (regs[id&3] & 0xff00) | v;
}
}
inline uint16_t getr16(uint8_t id) { return regs[id]; }
inline void setr16(uint8_t id, uint16_t v) { regs[id] = v; }
uint8_t geteab()
{
if (cpu_mod == 3)
return getr8(cpu_rm);
else
return readmemb(segment + eaaddr);
}
uint16_t geteaw()
{
if (cpu_mod == 3) return getr16(cpu_rm);
return readmemw(segment, eaaddr);
}
void seteab(uint8_t v)
{
if (cpu_mod == 3) {
setr8(cpu_rm, v);
} else {
writememb(segment + eaaddr, v);
}
}
void seteaw(uint16_t v)
{
if (cpu_mod == 3) {
regs[cpu_rm] = v;
} else {
writememw(segment, eaaddr, v);
}
}
void push(uint16_t v)
{
writememw(seg_ss, ((SP_ - 2) & 0xffff), v);
SP_ -= 2;
}
uint16_t pop()
{
uint16_t r = readmemw(seg_ss, SP_);
SP_ += 2;
return r;
}
void interrupt(uint8_t int_id)
{
uint16_t a = (int_id<<2);
uint16_t l = readmemw(0, a);
uint16_t h = readmemw(0, a+2);
push(flags | 0xF000);
push(segs[SEG_CS]);
push(ip);
flags &= ~(I_FLAG | T_FLAG);
loadcs(h); ip = l;
}
void daa()
{
uint8_t AL = AL_;
uint16_t tempi;
if ((flags & A_FLAG) || ((AL & 0xF) > 9))
{
tempi = ((uint16_t) AL) + 6;
AL += 6;
flags |= A_FLAG;
if (tempi & 0x100) flags |= C_FLAG;
}
if ((flags & C_FLAG) || (AL > 0x9F))
{
AL += 0x60;
flags |= C_FLAG;
}
setznp8(AL);
setr8(REG_AL, AL);
}
void das()
{
uint8_t AL = regs[REG_AL];
uint16_t tempi;
if ((flags & A_FLAG) || ((AL & 0xF)>9))
{
tempi = ((uint16_t)AL) - 6;
AL -= 6;
flags |= A_FLAG;
if (tempi & 0x100) flags |= C_FLAG;
}
if ((flags & C_FLAG) || (AL>0x9F))
{
AL -= 0x60;
flags |= C_FLAG;
}
setznp8(AL);
setr8(REG_AL, AL);
}
void aaa()
{
uint8_t AL = regs[REG_AL];
uint8_t AH = regs[REG_AX] >> 8;
if ((flags & A_FLAG) || ((AL & 0xF) > 9))
{
AL+=6;
AH++;
flags |= (A_FLAG|C_FLAG);
}
else {
flags &= ~(A_FLAG|C_FLAG);
}
setr16(REG_AX, (AL&15) + ((uint16_t)AH << 8));
}
void aas()
{
uint8_t AL = regs[REG_AL];
uint8_t AH = regs[REG_AX] >> 8;
if ((flags & A_FLAG) || ((AL & 0xF) > 9))
{
AL-=6;
AH--;
flags |= (A_FLAG|C_FLAG);
}
else
flags &= ~(A_FLAG|C_FLAG);
setr16(REG_AX, (AL&15) + ((uint16_t)AH<<8));
}
inline void aam()
{
uint8_t tb = getbyte();
setr8(REG_AH, AL_ / tb);
setr8(REG_AL, AL_ % tb);
setznp16(AX_);
}
inline void aad()
{
uint8_t tb = getbyte();
AX_ = (AH_*tb + AL_) & 0x00FF;
setznp16(AX_);
}
void callfar(uint16_t _cs, uint16_t _ip)
{
uint16_t cs_ = segs[SEG_CS], ip_ = ip;
ip = _ip;
loadcs(_cs);
push(cs_);
push(ip_);
}
uint8_t groupalu8(uint8_t mode, uint8_t a, uint8_t b)
{
switch (mode) {
case 0: return setadd8(a, b);
case 1: return setor8 (a, b);
case 2: return setadc8(a, b, flags & C_FLAG);
case 3: return setsbc8(a, b, flags & C_FLAG);
case 4: return setand8(a, b);
case 5:
case 7: return setsub8(a, b);
case 6: return setxor8(a, b);
}
return 0;
}
uint16_t groupalu16(uint8_t mode, uint16_t a, uint16_t b)
{
switch (mode) {
case 0: return setadd16(a, b);
case 1: return setor16 (a, b);
case 2: return setadc16(a, b, flags & C_FLAG);
case 3: return setsbc16(a, b, flags & C_FLAG);
case 4: return setand16(a, b);
case 5:
case 7: return setsub16(a, b);
case 6: return setxor16(a, b);
}
return 0;
}
uint16_t groupshift(uint8_t mode, uint8_t bit, uint16_t temp, uint8_t n) {
uint8_t tmpc = 0;
uint16_t temp2;
uint16_t sign_bit = bit ? 0x8000 : 0x80;
uint16_t prev_bit = sign_bit >> 1;
if (n == 0) return temp;
switch (mode)
{
case 0: {
flags &= ~(C_FLAG | V_FLAG);
while (n > 0) {
tmpc = !!(temp & sign_bit);
temp = (temp << 1) | tmpc;
n--;
}
if (tmpc) flags |= C_FLAG;
if (!!(flags & C_FLAG) != !!(temp & sign_bit)) flags |= V_FLAG;
break;
}
case 1: {
flags &= ~(C_FLAG | V_FLAG);
while (n > 0) {
tmpc = temp & 1;
temp >>= 1;
if (tmpc) temp |= sign_bit;
n--;
}
if (tmpc) flags |= C_FLAG;
if ((temp ^ (temp >> 1)) & prev_bit) flags |= V_FLAG;
break;
}
case 2: {
flags &= ~(V_FLAG);
while (n > 0) {
tmpc = flags & C_FLAG;
if (temp & sign_bit) flags |= C_FLAG; else flags &= ~C_FLAG;
temp = (temp << 1) | tmpc;
n--;
}
if (!!(flags & C_FLAG) != !!(temp & sign_bit)) flags |= V_FLAG;
break;
}
case 3: {
flags &= ~(V_FLAG);
while (n > 0) {
tmpc = flags&C_FLAG;
temp2 = temp&1;
temp >>= 1;
if (temp2) flags |= C_FLAG; else flags &= ~C_FLAG;
if (tmpc) temp |= sign_bit;
n--;
}
if ((temp ^ (temp >> 1)) & prev_bit) flags |= V_FLAG;
break;
}
case 4:
case 6: {
flags &= ~(C_FLAG);
if (n > (bit ? 16 : 8)) {
temp = 0;
} else {
if ((temp << (n-1)) & sign_bit) flags |= C_FLAG;
temp <<= n;
}
if (bit) setznp16(temp); else setznp8(temp);
flags |= A_FLAG;
break;
}
case 5: {
flags &= ~(C_FLAG);
if (n > (bit ? 16 : 8)) {
temp = 0;
} else {
if ((temp >> (n-1)) & 1) flags |= C_FLAG;
temp >>= n;
}
if (bit) setznp16(temp); else setznp8(temp);
flags |= A_FLAG;
break;
}
case 7: {
flags &= ~(C_FLAG);
if ((temp >> (n-1)) & 1) flags |= C_FLAG;
while (n > 0) {
temp >>= 1;
if (temp & prev_bit) temp |= sign_bit;
n--;
}
if (bit) setznp16(temp); else setznp8(temp);
flags |= A_FLAG;
break;
}
}
return temp;
}
void autorep(uint8_t flag_test) {
if (rep) {
CX_--;
if (flag_test) {
if ((rep == REPZ) && !(flags & Z_FLAG))
return;
if ((rep == REPNZ) && (flags & Z_FLAG))
return;
}
if (CX_) ip = ip_start;
}
}
void ud(int type)
{
ip--;
}
void extended()
{
opcode = getbyte();
int16_t offset;
switch (opcode) {
case 0x31: AX_ = rdtsc&0xffff; DX_ = 0; break;
case 0x80: offset = (int16_t)getword(); if (flags&V_FLAG) ip += offset; break;
case 0x81: offset = (int16_t)getword(); if (!(flags&V_FLAG)) ip += offset; break;
case 0x82: offset = (int16_t)getword(); if (flags&C_FLAG) ip += offset; break;
case 0x83: offset = (int16_t)getword(); if (!(flags&C_FLAG)) ip += offset; break;
case 0x84: offset = (int16_t)getword(); if (flags&Z_FLAG) ip += offset; break;
case 0x85: offset = (int16_t)getword(); if (!(flags&Z_FLAG)) ip += offset; break;
case 0x86: offset = (int16_t)getword(); if (flags&(C_FLAG|Z_FLAG)) ip += offset; break;
case 0x87: offset = (int16_t)getword(); if (!(flags&(C_FLAG|Z_FLAG))) ip += offset; break;
case 0x88: offset = (int16_t)getword(); if (flags&N_FLAG) ip += offset; break;
case 0x89: offset = (int16_t)getword(); if (!(flags&N_FLAG)) ip += offset; break;
case 0x8A: offset = (int16_t)getword(); if (flags&P_FLAG) ip += offset; break;
case 0x8B: offset = (int16_t)getword(); if (!(flags&P_FLAG)) ip += offset; break;
case 0x8C: offset = (int16_t)getword(); if (!!(flags&N_FLAG) != !!(flags&V_FLAG)) ip += offset; break;
case 0x8D: offset = (int16_t)getword(); if (!!(flags&N_FLAG) == !!(flags&V_FLAG)) ip += offset; break;
case 0x8E: offset = (int16_t)getword(); if ( (flags&Z_FLAG) || !!(flags&N_FLAG) != !!(flags&V_FLAG)) ip += offset; break;
case 0x8F: offset = (int16_t)getword(); if (!(flags&Z_FLAG) && (!!(flags&N_FLAG) == !!(flags&V_FLAG))) ip += offset; break;
case 0xB6: fetchea(); setr16(cpu_reg, geteab()); break;
case 0xB7: fetchea(); setr16(cpu_reg, geteaw()); break;
default:
ud(7);
break;
}
}
int x86run(int32_t instr_cnt)
{
int8_t offset;
int16_t tempws;
uint8_t cont, tempc, noint;
uint8_t tempb, tempb2;
uint16_t tempw, tempw2;
uint32_t templ;
int32_t templs;
int8_t trap;
int8_t p66, p67;
while (instr_cnt-- >= 0)
{
if (inhlt) return 1;
rep = 0;
trap = flags & T_FLAG;
sel_seg = 0;
noint = 0;
p66 = 0;
p67 = 0;
segment = seg_ds;
tempc = flags & C_FLAG;
tstates++;
ip_start = ip;
do {
rdtsc++;
cont = 0;
opcode = getbyte();
switch (opcode)
{
case 0x00: fetchea(); seteab(setadd8 (geteab(), getr8 (cpu_reg))); break;
case 0x01: fetchea(); seteaw(setadd16(geteaw(), getr16(cpu_reg))); break;
case 0x02: fetchea(); setr8 (cpu_reg, setadd8 (getr8 (cpu_reg), geteab())); break;
case 0x03: fetchea(); setr16(cpu_reg, setadd16(getr16(cpu_reg), geteaw())); break;
case 0x04: setr8 (REG_AL, setadd8 (regs[REG_AL], getbyte())); break;
case 0x05: setr16(REG_AX, setadd16(regs[REG_AX], getword())); break;
case 0x06: push(segs[SEG_ES]); break;
case 0x07: loades(pop()); break;
case 0x08: fetchea(); seteab(setor8 (geteab(), getr8 (cpu_reg))); break;
case 0x09: fetchea(); seteaw(setor16(geteaw(), getr16(cpu_reg))); break;
case 0x0A: fetchea(); setr8 (cpu_reg, setor8 (getr8 (cpu_reg), geteab())); break;
case 0x0B: fetchea(); setr16(cpu_reg, setor16(getr16(cpu_reg), geteaw())); break;
case 0x0C: setr8 (REG_AL, setor8 (regs[REG_AL], getbyte())); break;
case 0x0D: setr16(REG_AX, setor16(regs[REG_AX], getword())); break;
case 0x0E: push(segs[SEG_CS]); break;
case 0x0F: extended(); break;
case 0x10: fetchea(); seteab(setadc8 (geteab(), getr8 (cpu_reg), tempc)); break;
case 0x11: fetchea(); seteaw(setadc16(geteaw(), getr16(cpu_reg), tempc)); break;
case 0x12: fetchea(); setr8 (cpu_reg, setadc8 (getr8 (cpu_reg), geteab(), tempc)); break;
case 0x13: fetchea(); setr16(cpu_reg, setadc16(getr16(cpu_reg), geteaw(), tempc)); break;
case 0x14: setr8 (REG_AL, setadc8 (regs[REG_AL], getbyte(), tempc)); break;
case 0x15: setr16(REG_AX, setadc16(regs[REG_AX], getword(), tempc)); break;
case 0x16: push(segs[SEG_SS]); break;
case 0x17: loadss(pop()); noint = 1; break;
case 0x18: fetchea(); seteab(setsbc8 (geteab(), getr8 (cpu_reg), tempc)); break;
case 0x19: fetchea(); seteaw(setsbc16(geteaw(), getr16(cpu_reg), tempc)); break;
case 0x1A: fetchea(); setr8 (cpu_reg, setsbc8 (getr8 (cpu_reg), geteab(), tempc)); break;
case 0x1B: fetchea(); setr16(cpu_reg, setsbc16(getr16(cpu_reg), geteaw(), tempc)); break;
case 0x1C: setr8 (REG_AL, setsbc8 (regs[REG_AL], getbyte(), tempc)); break;
case 0x1D: setr16(REG_AX, setsbc16(regs[REG_AX], getword(), tempc)); break;
case 0x1E: push(segs[SEG_DS]); break;
case 0x1F: loadds(pop()); break;
case 0x20: fetchea(); seteab(setand8 (geteab(), getr8 (cpu_reg))); break;
case 0x21: fetchea(); seteaw(setand16(geteaw(), getr16(cpu_reg))); break;
case 0x22: fetchea(); setr8 (cpu_reg, setand8 (getr8 (cpu_reg), geteab())); break;
case 0x23: fetchea(); setr16(cpu_reg, setand16(getr16(cpu_reg), geteaw())); break;
case 0x24: setr8 (REG_AL, setand8 (regs[REG_AL], getbyte())); break;
case 0x25: setr16(REG_AX, setand16(regs[REG_AX], getword())); break;
case 0x26: sel_seg = 1; segment = seg_es; cont = 1; break;
case 0x27: daa(); break;
case 0x28: fetchea(); seteab(setsub8 (geteab(), getr8 (cpu_reg))); break;
case 0x29: fetchea(); seteaw(setsub16(geteaw(), getr16(cpu_reg))); break;
case 0x2A: fetchea(); setr8 (cpu_reg, setsub8 (getr8 (cpu_reg), geteab())); break;
case 0x2B: fetchea(); setr16(cpu_reg, setsub16(getr16(cpu_reg), geteaw())); break;
case 0x2C: setr8 (REG_AL, setsub8 (regs[REG_AL], getbyte())); break;
case 0x2D: setr16(REG_AX, setsub16(regs[REG_AX], getword())); break;
case 0x2E: sel_seg = 1; segment = seg_cs; cont = 1; break;
case 0x2F: das(); break;
case 0x30: fetchea(); seteab(setxor8 (geteab(), getr8 (cpu_reg))); break;
case 0x31: fetchea(); seteaw(setxor16(geteaw(), getr16(cpu_reg))); break;
case 0x32: fetchea(); setr8 (cpu_reg, setxor8 (getr8 (cpu_reg), geteab())); break;
case 0x33: fetchea(); setr16(cpu_reg, setxor16(getr16(cpu_reg), geteaw())); break;
case 0x34: setr8 (REG_AL, setxor8 (regs[REG_AL], getbyte())); break;
case 0x35: setr16(REG_AX, setxor16(regs[REG_AX], getword())); break;
case 0x36: sel_seg = 1; segment = seg_ss; cont = 1; break;
case 0x37: aaa(); break;
case 0x38: fetchea(); setsub8 (geteab(), getr8 (cpu_reg)); break;
case 0x39: fetchea(); setsub16(geteaw(), getr16(cpu_reg)); break;
case 0x3A: fetchea(); setsub8 (getr8 (cpu_reg), geteab()); break;
case 0x3B: fetchea(); setsub16(getr16(cpu_reg), geteaw()); break;
case 0x3C: setsub8 (regs[REG_AL], getbyte()); break;
case 0x3D: setsub16(regs[REG_AX], getword()); break;
case 0x3E: sel_seg = 1; segment = seg_ds; cont = 1; break;
case 0x3F: aas(); break;
case 0x40: case 0x41: case 0x42: case 0x43:
case 0x44: case 0x45: case 0x46: case 0x47: {
regs[opcode&7] = setadd16nc(regs[opcode&7], 1);
break;
}
case 0x48: case 0x49: case 0x4A: case 0x4B:
case 0x4C: case 0x4D: case 0x4E: case 0x4F: {
regs[opcode&7] = setsub16nc(regs[opcode&7], 1);
break;
}
case 0x50: case 0x51: case 0x52: case 0x53:
case 0x54: case 0x55: case 0x56: case 0x57: {
push(regs[opcode&7]);
break;
}
case 0x58: case 0x59: case 0x5A: case 0x5B:
case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
regs[opcode&7] = pop();
break;
}
case 0x60: {
tempw = regs[REG_SP];
for (int i = 0; i < 8; i++)
push(i == REG_SP ? tempw : regs[i]);
break;
}
case 0x61: {
tempw = 0;
for (int i = 7; i >= 0; i--) {
if (i == REG_SP) tempw = pop();
else regs[i] = pop();
}
regs[REG_SP] = tempw;
break;
}
case 0x64: sel_seg = 1; segment = seg_fs; cont = 1; break;
case 0x65: sel_seg = 1; segment = seg_gs; cont = 1; break;
case 0x66: p66 = ~p66; cont = 1; break;
case 0x67: p67 = ~p67; cont = 1; break;
case 0x68: push(getword()); break;
case 0x6a: tempw = getbyte(); tempw = (tempw & 0x80 ? 0xff00 : 0) | tempw; push(tempw); break;
case 0x69: {
fetchea();
tempw = getword();
templ = (long)((int16_t)geteaw()) * (long)((int16_t)tempw);
setr16(cpu_reg, templ);
if (templ & 0xffff0000)
flags |= (C_FLAG | V_FLAG);
else flags &= ~(C_FLAG | V_FLAG);
break;
}
case 0x6B: {
fetchea();
tempw = getbyte();
tempw = tempw & 0x80 ? (0xff00 | tempw) : tempw;
templ = (long)((int16_t)geteaw()) * (long)((int16_t)tempw);
setr16(cpu_reg, templ);
if (templ & 0xffff0000)
flags |= (C_FLAG | V_FLAG);
else flags &= ~(C_FLAG | V_FLAG);
break;
}
case 0x70: offset = (int8_t)getbyte(); if (flags&V_FLAG) ip += offset; break;
case 0x71: offset = (int8_t)getbyte(); if (!(flags&V_FLAG)) ip += offset; break;
case 0x72: offset = (int8_t)getbyte(); if (flags&C_FLAG) ip += offset; break;
case 0x73: offset = (int8_t)getbyte(); if (!(flags&C_FLAG)) ip += offset; break;
case 0x74: offset = (int8_t)getbyte(); if (flags&Z_FLAG) ip += offset; break;
case 0x75: offset = (int8_t)getbyte(); if (!(flags&Z_FLAG)) ip += offset; break;
case 0x76: offset = (int8_t)getbyte(); if (flags&(C_FLAG|Z_FLAG)) ip += offset; break;
case 0x77: offset = (int8_t)getbyte(); if (!(flags&(C_FLAG|Z_FLAG))) ip += offset; break;
case 0x78: offset = (int8_t)getbyte(); if (flags&N_FLAG) ip += offset; break;
case 0x79: offset = (int8_t)getbyte(); if (!(flags&N_FLAG)) ip += offset; break;
case 0x7A: offset = (int8_t)getbyte(); if (flags&P_FLAG) ip += offset; break;
case 0x7B: offset = (int8_t)getbyte(); if (!(flags&P_FLAG)) ip += offset; break;
case 0x7C: offset = (int8_t)getbyte(); if (!!(flags&N_FLAG) != !!(flags&V_FLAG)) ip += offset; break;
case 0x7D: offset = (int8_t)getbyte(); if (!!(flags&N_FLAG) == !!(flags&V_FLAG)) ip += offset; break;
case 0x7E: offset = (int8_t)getbyte(); if ( (flags&Z_FLAG) || !!(flags&N_FLAG) != !!(flags&V_FLAG)) ip += offset; break;
case 0x7F: offset = (int8_t)getbyte(); if (!(flags&Z_FLAG) && (!!(flags&N_FLAG) == !!(flags&V_FLAG))) ip += offset; break;
case 0x80:
case 0x82: {
fetchea();
tempb = geteab();
tempb2 = getbyte();
tempb = groupalu8(cpu_reg, tempb, tempb2);
if (cpu_reg < 7) seteab(tempb);
break;
}
case 0x81: {
fetchea();
tempw = geteaw();
tempw2 = getword();
tempw = groupalu16(cpu_reg, tempw, tempw2);
if (cpu_reg < 7) seteaw(tempw);
break;
}
case 0x83: {
fetchea();
tempw = geteaw();
tempb = getbyte();
tempw = groupalu16(cpu_reg, tempw, tempb | (tempb&0x80 ? 0xFF00 : 0));
if (cpu_reg < 7) seteaw(tempw);
break;
}
case 0x84: fetchea(); setand8 (geteab(), getr8 (cpu_reg)); break;
case 0x85: fetchea(); setand16(geteaw(), getr16(cpu_reg)); break;
case 0x86: fetchea(); tempb = geteab(); seteab(getr8 (cpu_reg)); setr8 (cpu_reg, tempb); break;
case 0x87: fetchea(); tempw = geteaw(); seteaw(getr16(cpu_reg)); setr16(cpu_reg, tempw); break;
case 0x88: fetchea(); seteab(getr8 (cpu_reg)); break;
case 0x89: fetchea(); seteaw(getr16(cpu_reg)); break;
case 0x8A: fetchea(); setr8 (cpu_reg, geteab()); break;
case 0x8B: fetchea(); setr16(cpu_reg, geteaw()); break;
case 0x8C: {
fetchea();
switch (rmdat & 0x38) {
case 0x00: seteaw(segs[SEG_ES]); break;
case 0x08: seteaw(segs[SEG_CS]); break;
case 0x10: seteaw(segs[SEG_SS]); break;
case 0x18: seteaw(segs[SEG_DS]); break;
case 0x20: seteaw(segs[SEG_FS]); break;
case 0x28: seteaw(segs[SEG_GS]); break;
}
break;
}
case 0x8D: fetchea(); regs[cpu_reg] = eaaddr; break;
case 0x8E: {
fetchea();
noint = 1;
switch (rmdat & 0x38) {
case 0x00: loades(geteaw()); break;
case 0x08: ud(6); break;
case 0x10: loadss(geteaw()); break;
case 0x18: loadds(geteaw()); break;
case 0x20: loadfs(geteaw()); break;
case 0x28: loadgs(geteaw()); break;
}
break;
}
case 0x8F: fetchea(); seteaw(pop()); break;
case 0x90: case 0x91: case 0x92: case 0x93:
case 0x94: case 0x95: case 0x96: case 0x97: {
tempw = regs[opcode&7];
regs[opcode&7] = regs[REG_AX];
regs[REG_AX] = tempw;
break;
}
case 0x98: AX_ = (AX_ & 0x0080 ? 0xff00 : 0) | (AX_ & 0xff); break;
case 0x99: DX_ = (AX_ & 0x8000) ? 0xffff : 0; break;
case 0x9A: tempw = getword(); callfar(getword(), tempw); break;
case 0x9B: break;
case 0x9C: push((flags & ~0x2A) | 2); break;
case 0x9D: flags = pop() & 0xfff; break;
case 0x9E: flags = (flags & 0xFF00) | (AX_ >> 8); break;
case 0x9F: setr8(REG_AH, flags); break;
case 0xA0: tempw = getword(); setr8(REG_AX, readmemb(segment + tempw)); break;
case 0xA1: tempw = getword(); AX_ = readmemw(segment, tempw); break;
case 0xA2: tempw = getword(); writememb(segment + tempw, AX_); break;
case 0xA3: tempw = getword(); writememw(segment, tempw, AX_); break;
case 0xA4: {
REPINIT;
writememb(seg_es + DI_, readmemb(segment + SI_));
REPINC(SI_,1);
REPINC(DI_,1);
autorep(0);
break;
}
case 0xA5: {
REPINIT;
writememw(seg_es, DI_, readmemw(segment, SI_));
REPINC(SI_, p66 ? 4 : 2);
REPINC(DI_, p66 ? 4 : 2);
autorep(0);
break;
}
case 0xA6: {
REPINIT;
setsub8(readmemb(segment + SI_), readmemb(seg_es + DI_));
REPINC(SI_,1);
REPINC(DI_,1);
autorep(0);
break;
}
case 0xA7: {
REPINIT;
setsub16(readmemw(segment, SI_), readmemw(seg_es, DI_));
REPINC(SI_, p66 ? 4 : 2);
REPINC(DI_, p66 ? 4 : 2);
autorep(0);
break;
}
case 0xA8: setand8 (AX_, getbyte()); break;
case 0xA9: setand16(AX_, getword()); break;
case 0xAA: {
REPINIT;
writememb(seg_es + DI_, AL_);
REPINC(DI_, 1);
autorep(0);
break;
}
case 0xAB: {
REPINIT;
writememw(seg_es, DI_, AX_);
REPINC(DI_, p66 ? 4 : 2);
autorep(0);
break;
}
case 0xAC: {
REPINIT;
setr8(REG_AL, readmemb(segment + SI_));
REPINC(SI_, 1);
autorep(0);
break;
}
case 0xAD: {
REPINIT;
AX_ = readmemw(segment, SI_);
REPINC(SI_, p66 ? 4 : 2);
autorep(0);
break;
}
case 0xAE: {
REPINIT;
setsub8(AL_, readmemb(seg_es + DI_));
REPINC(DI_, 1);
autorep(1);
break;
}
case 0xAF: {
REPINIT;
setsub16(AX_, readmemw(seg_es, DI_));
REPINC(DI_, p66 ? 4 : 2);
autorep(1);
break;
}
case 0xB0: case 0xB1: case 0xB2: case 0xB3:
case 0xB4: case 0xB5: case 0xB6: case 0xB7: {
setr8(opcode&7, getbyte());
break;
}
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
case 0xBC: case 0xBD: case 0xBE: case 0xBF: {
regs[opcode&7] = getword();
break;
}
case 0xC0: fetchea(); tempb = getbyte(); seteab(groupshift(cpu_reg, 0, geteab(), tempb & 7)); break;
case 0xC1: fetchea(); tempb = getbyte(); seteaw(groupshift(cpu_reg, 1, geteaw(), tempb & 31)); break;
case 0xC2: tempw = getword(); ip = pop(); SP_ += tempw; break;
case 0xC3: ip = pop(); break;
case 0xC4: fetchea(); setr16(cpu_reg, readmemw(segment, eaaddr)); loades(readmemw(segment, eaaddr+2)); break;
case 0xC5: fetchea(); setr16(cpu_reg, readmemw(segment, eaaddr)); loadds(readmemw(segment, eaaddr+2)); break;
case 0xC6: fetchea(); seteab(getbyte()); break;
case 0xC7: fetchea(); seteaw(getword()); break;
case 0xC8: ud(4); break;
case 0xC9: ud(5); break;
case 0xCA: tempw = getword(); tempw2 = pop(); loadcs(pop()); ip = tempw; SP_ += tempw; break;
case 0xCB: tempw = getword(); tempw2 = pop(); loadcs(pop()); ip = tempw; break;
case 0xCC: interrupt(3); break;
case 0xCD: interrupt(getbyte()); break;
case 0xCE: if (flags & V_FLAG) interrupt(4); break;
case 0xCF: tempw = pop(); tempw2 = pop(); flags = pop() & 0xfff; loadcs(tempw2); ip = tempw; break;
case 0xD0: fetchea(); seteab(groupshift(cpu_reg, 0, geteab(), 1)); break;
case 0xD1: fetchea(); seteaw(groupshift(cpu_reg, 1, geteaw(), 1)); break;
case 0xD2: fetchea(); seteab(groupshift(cpu_reg, 0, geteab(), CX_&7)); break;
case 0xD3: fetchea(); seteaw(groupshift(cpu_reg, 1, geteaw(), CX_&31)); break;
case 0xD4: aam(); break;
case 0xD5: aad(); break;
case 0xD6: setr8(REG_AL, flags & C_FLAG ? 0xff : 00);
case 0xD7: setr8(REG_AL, readmemb(segment + BX_ + (AX_ & 255))); break;
case 0xD8: case 0xD9: case 0xDA: case 0xDB:
case 0xDC: case 0xDD: case 0xDE: case 0xDF: {
fetchea();
break;
}
case 0xE0: offset = (int8_t) getbyte(); CX_--; if ( CX_ && !(flags & Z_FLAG)) ip += offset; break;
case 0xE1: offset = (int8_t) getbyte(); CX_--; if ( CX_ && (flags & Z_FLAG)) ip += offset; break;
case 0xE2: offset = (int8_t) getbyte(); CX_--; if ( CX_) ip += offset; break;
case 0xE3: offset = (int8_t) getbyte(); if (!CX_) ip += offset; break;
case 0xE4: tempb = getbyte(); setr8(REG_AL, ioread(tempb)); break;
case 0xE5: tempb = getbyte(); setr8(REG_AL, ioread(tempb)); setr8(REG_AH, ioread(tempb+1)); break;
case 0xE6: tempb = getbyte(); iowrite(tempb, AL_); break;
case 0xE7: tempb = getbyte(); iowrite(tempb, AL_); iowrite(tempb+1, AH_); break;
case 0xE8: tempw = getword(); push(ip); ip += tempw; break;
case 0xE9: tempw = getword(); ip += tempw; break;
case 0xEA: tempw = getword(); tempw2 = getword(); loadcs(tempw2); ip = tempw; break;
case 0xEB: tempb = getbyte(); ip += (tempb & 0x80 ? tempb - 256 : tempb); break;
case 0xEC: setr8(REG_AL, ioread(DX_)); break;
case 0xED: setr8(REG_AL, ioread(DX_)); setr8(REG_AH, ioread(DX_+1)); break;
case 0xEE: iowrite(DX_, AL_); break;
case 0xEF: iowrite(DX_, AL_); iowrite(DX_+1, AH_); break;
case 0xF0: cont = 1; break;
case 0xF1: interrupt(1); break;
case 0xF2: rep = REPNZ; cont = 1; break;
case 0xF3: rep = REPZ; cont = 1; break;
case 0xF4: inhlt = 1; ip--; break;
case 0xF5: flags ^= C_FLAG; break;
case 0xF6: {
fetchea(); tempb = geteab();
switch (cpu_reg) {
case 0:
case 1: setand8(tempb, getbyte()); break;
case 2: seteab(~tempb); break;
case 3: seteab(setsub8(0, tempb)); break;
case 4: {
setznp8(AL_);
AX_ = AL_ * tempb;
if (AX_) flags &= ~Z_FLAG; else flags |= Z_FLAG;
if (AH_) flags |= (C_FLAG | V_FLAG); else flags &= ~(C_FLAG|V_FLAG);
break;
}
case 5: {
setznp8(AL_);
AX_ = (int16_t)((int8_t)AL_)*(int16_t)((int8_t)tempb);
if (AX_) flags &= ~Z_FLAG; else flags |= Z_FLAG;
if (AH_) flags |= (C_FLAG|V_FLAG); else flags &= ~(C_FLAG|V_FLAG);
break;
}
case 6: {
tempw = AX_;
if (tempb) {
tempw2 = tempw % tempb;
tempw /= tempb;
setr8(REG_AH, tempw2);
setr8(REG_AL, tempw);
} else interrupt(0);
break;
}
case 7: {
tempws = (int16_t) AX_;
if (tempb) {
tempw2 = tempws % (int16_t)((int8_t)tempb);
tempws /= (int16_t)((int8_t)tempb);
setr8(REG_AH, tempw2);
setr8(REG_AL, tempws);
} else interrupt(0);
break;
}
}
break;
}
case 0xF7: {
fetchea(); tempw = geteaw();
switch (cpu_reg) {
case 0:
case 1: setand16(tempw, getword()); break;
case 2: seteaw(~tempw); break;
case 3: seteaw(setsub16(0, tempw)); break;
case 4: {
setznp16(AX_);
templ = AX_ * tempw;
AX_ = templ;
DX_ = templ >> 16;
if (AX_ | DX_) flags &= ~Z_FLAG; else flags |= Z_FLAG;
if (DX_) flags |= (C_FLAG|V_FLAG); else flags &= ~(C_FLAG|V_FLAG);
break;
}
case 5: {
setznp16(AX_);
templ = (long)((int16_t)AX_) * (long)((int16_t)tempw);
AX_ = templ;
DX_ = (uint16_t)(templ >> 16);
if (AX_ && DX_ != 0xFFFF)
flags |= (C_FLAG | V_FLAG);
else flags &= ~(C_FLAG | V_FLAG);
if (AX_ | DX_) flags &= ~Z_FLAG; else flags |= Z_FLAG;
break;
}
case 6: {
templ = ((uint32_t)DX_ << 16) | AX_;
if (tempw)
{
tempw2 = templ % tempw;
templ /= tempw;
DX_ = tempw2;
AX_ = templ;
}
else interrupt(0);
break;
}
case 7: {
if (DX_ != 0 && DX_ != 0xFFFF) {
interrupt(0);
break;
}
templs = (int)(((int32_t)DX_ << 16) | AX_);
if (tempw)
{
tempw2 = templs % (int32_t)(int16_t)tempw;
templs /= (int32_t)(int16_t)tempw;
DX_ = tempw2;
AX_ = templs;
}
else interrupt(0);
break;
}
}
break;
}
case 0xF8: flags &= ~C_FLAG; break;
case 0xF9: flags |= C_FLAG; break;
case 0xFA: flags &= ~I_FLAG; break;
case 0xFB: flags |= I_FLAG; break;
case 0xFC: flags &= ~D_FLAG; break;
case 0xFD: flags |= D_FLAG; break;
case 0xFE: {
fetchea();
tempb = geteab();
switch (cpu_reg) {
case 0: seteab(setadd8nc(tempb, 1)); break;
case 1: seteab(setsub8nc(tempb, 1)); break;
default: ud(3);
}
break;
}
case 0xFF: {
fetchea();
tempw = geteaw();
switch (cpu_reg) {
case 0: seteaw(setadd16nc(tempw, 1)); break;
case 1: seteaw(setsub16nc(tempw, 1)); break;
case 2: push(ip); ip = tempw; break;
case 3: {
tempw = readmemw(segment, eaaddr);
tempw2 = readmemw(segment, eaaddr + 2);
callfar(tempw2, tempw);
break;
}
case 4: ip = tempw; break;
case 5: {
tempw = readmemw(segment, eaaddr);
tempw2 = readmemw(segment, eaaddr+2);
loadcs(tempw2); ip = tempw;
break;
}
case 6: push(geteaw()); break;
default: ud(1);
}
break;
}
default: ud(2); break;
}
}
while (cont);
if (trap && (flags & T_FLAG) && !noint) interrupt(1);
}
return 0;
}
};