real mode emulation, required for vesa mode on terminal Notes: realmode emulator. binds itself over /dev and provides /dev/realmode and /dev/realmodemem to be used with aux/vga -m vesa ... the command option -t enables instruction tracing to stderr. requires a updated vgavesa driver to use /dev/realmode instead of a direct realmode() call. patch can be found at: /n/sources/patch/vesa-softscreen-resize a list with graphics cards that have been successfully enabled with the aux/vga and realemu can be found in the vgalist file. bug reports / suggestions or failed attempts email to: cinap_lenrek AT gmx DOT de contributors: i stole some code from rsc's 8i /n/sources/contrib/rsc/8i, so thanks russ! :) patient testers from irc: sl, Fish- Reference: /n/patches.lsub.org/patch/realemu Date: Thu Sep 13 21:00:38 CES 2012 Signed-off-by: quanstro@quanstro.net Reviewed-by: elf --- /sys/src/cmd/aux/realemu/arg.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/arg.c Sat Apr 30 22:21:38 2011 @@ -0,0 +1,163 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +#define ause(cpu) (cpu->abuf + (cpu->iabuf++ % nelem(cpu->abuf))) + +Iarg* +adup(Iarg *x) +{ + Iarg *a; + + a = ause(x->cpu); + *a = *x; + return a; +} + +Iarg* +areg(Cpu *cpu, uchar len, uchar reg) +{ + Iarg *a; + + a = ause(cpu); + a->cpu = cpu; + a->tag = TREG; + a->len = len; + a->reg = reg; + return a; +} + +Iarg* +amem(Cpu *cpu, uchar len, uchar sreg, ulong off) +{ + Iarg *a; + + a = ause(cpu); + a->cpu = cpu; + a->tag = TMEM; + a->len = len; + a->sreg = sreg; + a->seg = cpu->reg[sreg]; + a->off = off; + return a; +} + +Iarg* +afar(Iarg *mem, uchar len, uchar alen) +{ + Iarg *a, *p; + + p = adup(mem); + p->len = alen; + a = amem(mem->cpu, len, R0S, ar(p)); + p->off += alen; + p->len = 2; + a->seg = ar(p); + return a; +} + +Iarg* +acon(Cpu *cpu, uchar len, ulong val) +{ + Iarg *a; + + a = ause(cpu); + a->cpu = cpu; + a->tag = TCON; + a->len = len; + a->val = val; + return a; +} + +ulong +ar(Iarg *a) +{ + ulong w, o; + Bus *io; + + switch(a->tag){ + default: + abort(); + case TMEM: + o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF; + io = a->cpu->mem + (o>>16); + w = io->r(io->aux, o, a->len); + break; + case TREG: + w = a->cpu->reg[a->reg]; + break; + case TREG|TH: + w = a->cpu->reg[a->reg] >> 8; + break; + case TCON: + w = a->val; + break; + } + switch(a->len){ + default: + abort(); + case 1: + w &= 0xFF; + break; + case 2: + w &= 0xFFFF; + break; + case 4: + break; + } + return w; +} + +long +ars(Iarg *a) +{ + ulong w = ar(a); + switch(a->len){ + default: + abort(); + case 1: + return (char)w; + case 2: + return (short)w; + case 4: + return (long)w; + } +} + +void +aw(Iarg *a, ulong w) +{ + ulong *p, o; + Cpu *cpu; + Bus *io; + + cpu = a->cpu; + switch(a->tag){ + default: + abort(); + case TMEM: + o = ((a->seg<<4) + (a->off & 0xFFFF)) & 0xFFFFF; + io = cpu->mem + (o>>16); + io->w(io->aux, o, w, a->len); + break; + case TREG: + p = cpu->reg + a->reg; + switch(a->len){ + case 4: + *p = w; + break; + case 2: + *p = (*p & ~0xFFFF) | (w & 0xFFFF); + break; + case 1: + *p = (*p & ~0xFF) | (w & 0xFF); + break; + } + break; + case TREG|TH: + p = cpu->reg + a->reg; + *p = (*p & ~0xFF00) | (w & 0xFF)<<8; + break; + } +} --- /sys/src/cmd/aux/realemu/dat.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/dat.h Sat Apr 30 22:21:38 2011 @@ -0,0 +1,363 @@ +typedef struct Iarg Iarg; +typedef struct Inst Inst; +typedef struct Bus Bus; +typedef struct Cpu Cpu; +typedef struct Pit Pit; + +enum { + RAX, + RCX, + RDX, + RBX, + RSP, + RBP, + RSI, + RDI, + + RES, + RCS, + RSS, + RDS, + RFS, + RGS, + + R0S, /* 0 segment */ + + RIP, + RFL, + + NREG, +}; + +struct Iarg +{ + Cpu *cpu; + + uchar tag; + uchar len; + uchar atype; + + union { + uchar reg; + struct { + uchar sreg; + ulong seg, off; + }; + ulong val; + }; +}; + +struct Inst +{ + uchar op; + uchar code; + uchar olen; + uchar alen; + + Iarg *a1, *a2, *a3; + + uchar rep; + + uchar mod; + uchar reg; + uchar rm; + + uchar scale; + uchar index; + uchar base; + + uchar sreg; + uchar dsreg; + + ulong off; + long disp; +}; + +struct Bus +{ + void *aux; + ulong (*r)(void *aux, ulong off, int len); + void (*w)(void *aux, ulong off, ulong data, int len); +}; + +struct Cpu +{ + ulong reg[NREG]; + + /* instruction counter */ + ulong ic; + + /* mem[16], one entry for each 64k block */ + Bus *mem; + + /* port[1], in/out */ + Bus *port; + + int trap; + ulong oldip; + jmp_buf jmp; + + /* default operand, address and stack pointer length */ + uchar olen, alen, slen; + + /* argument buffers */ + ulong iabuf; + Iarg abuf[0x80]; +}; + +struct Pit +{ + ulong count; + + /* set by setgate(), cleared by clockpit() */ + uchar gateraised; + + /* signals */ + uchar gate; + uchar out; + + /* mode and flags */ + uchar count0; + + uchar bcd; + uchar amode; + uchar omode; + + /* latch for wpit initial count */ + uchar wcount; + uchar wlatched; + uchar wlatch[2]; + + /* latch for rpit status/count */ + uchar rcount; + uchar rlatched; + uchar rlatch[2]; +}; + +/* processor flags */ +enum { + CF = 1<<0, /* carry flag */ + PF = 1<<2, /* parity flag */ + AF = 1<<4, /* aux carry flag */ + ZF = 1<<6, /* zero flag */ + SF = 1<<7, /* sign flag */ + TF = 1<<8, /* trap flag */ + IF = 1<<9, /* interrupts enabled flag */ + DF = 1<<10, /* direction flag */ + OF = 1<<11, /* overflow flag */ + IOPL= 3<<12, /* I/O privelege level */ + NT = 1<<14, /* nested task */ + RF = 1<<16, /* resume flag */ + VM = 1<<17, /* virtual-8086 mode */ + AC = 1<<18, /* alignment check */ + VIF = 1<<19, /* virtual interrupt flag */ + VIP = 1<<20, /* virtual interrupt pending */ + ID = 1<<21, /* ID flag */ +}; + +/* interrupts/traps */ +enum { + EDIV0, + EDEBUG, + ENMI, + EBRK, + EINTO, + EBOUND, + EBADOP, + ENOFPU, + EDBLF, + EFPUSEG, + EBADTSS, + ENP, + ESTACK, + EGPF, + EPF, + + EHALT = 256, /* pseudo-interrupts */ + EMEM, + EIO, +}; + +/* argument tags */ +enum { + TREG, + TMEM, + TCON, + + TH = 0x80, /* special flag for AH,BH,CH,DH */ +}; + +/* argument types */ +enum { + ANONE, /* no argument */ + A0, /* constant 0 */ + A1, /* constant 1 */ + A2, /* constant 2 */ + A3, /* constant 3 */ + A4, /* constant 4 */ + AAp, /* 32-bit or 48-bit direct address */ + AEb, /* r/m8 from modrm byte */ + AEv, /* r/m16 or r/m32 from modrm byte */ + AEw, /* r/m16 */ + AFv, /* flag word */ + AGb, /* r8 from modrm byte */ + AGv, /* r16 or r32 from modrm byte */ + AGw, /* r/m16 */ + AIb, /* immediate byte */ + AIc, /* immediate byte sign-extended */ + AIw, /* immediate 16-bit word */ + AIv, /* immediate 16-bit or 32-bit word */ + AJb, /* relative offset byte */ + AJv, /* relative offset 16-bit or 32-bit word */ + AJr, /* r/m16 or r/m32 register */ + AM, /* memory address from modrm */ + AMa, /* something for bound */ + AMa2, + AMp, /* 32-bit or 48-bit memory address */ + AOb, /* immediate word-sized offset to a byte */ + AOv, /* immediate word-size offset to a word */ + ASw, /* segment register selected by r field of modrm */ + AXb, /* byte at DS:SI */ + AXv, /* word at DS:SI */ + AYb, /* byte at ES:DI */ + AYv, /* word at ES:DI */ + + AAL, + ACL, + ADL, + ABL, + AAH, + ACH, + ADH, + ABH, + + AAX, + ACX, + ADX, + ABX, + ASP, + ABP, + ASI, + ADI, + + AES, + ACS, + ASS, + ADS, + AFS, + AGS, + + NATYPE, +}; + +/* operators */ +enum { + OBAD, + O0F, + OAAA, + OAAD, + OAAM, + OAAS, + OADC, + OADD, + OAND, + OARPL, + OASIZE, + OBOUND, + OBT, + OBTS, + OBTR, + OBTC, + OBSF, + OBSR, + OCALL, + OCBW, + OCLC, + OCLD, + OCLI, + OCMC, + OCMOV, + OCMP, + OCMPS, + OCPUID, + OCWD, + ODAA, + ODAS, + ODEC, + ODIV, + OENTER, + OGP1, + OGP2, + OGP3b, + OGP3v, + OGP4, + OGP5, + OGP8, + OGP10, + OGP12, + OHLT, + OIDIV, + OIMUL, + OIN, + OINC, + OINS, + OINT, + OIRET, + OJUMP, + OLAHF, + OLEA, + OLEAVE, + OLFP, + OLOCK, + OLODS, + OLOOP, + OLOOPNZ, + OLOOPZ, + OMOV, + OMOVS, + OMOVZX, + OMOVSX, + OMUL, + ONEG, + ONOP, + ONOT, + OOR, + OOSIZE, + OOUT, + OOUTS, + OPOP, + OPOPA, + OPOPF, + OPUSH, + OPUSHA, + OPUSHF, + ORCL, + ORCR, + OREPE, + OREPNE, + ORET, + ORETF, + OROL, + OROR, + OSAHF, + OSAR, + OSBB, + OSCAS, + OSEG, + OSET, + OSHL, + OSHLD, + OSHR, + OSHRD, + OSTC, + OSTD, + OSTI, + OSTOS, + OSUB, + OTEST, + OWAIT, + OXCHG, + OXLAT, + OXOR, + NUMOP, +}; --- /sys/src/cmd/aux/realemu/decode.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/decode.c Sat Apr 30 22:21:37 2011 @@ -0,0 +1,625 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +typedef struct Optab Optab; +struct Optab { + uchar op; + uchar a1, a2, a3; +}; + +static Optab optab[256] = { +//00 + {OADD, AEb, AGb}, {OADD, AEv, AGv}, {OADD, AGb, AEb}, {OADD, AGv, AEv}, + {OADD, AAL, AIb}, {OADD, AAX, AIv}, {OPUSH, AES, }, {OPOP, AES }, + {OOR, AEb, AGb}, {OOR, AEv, AGv}, {OOR, AGb, AEb}, {OOR, AGv, AEv}, + {OOR, AAL, AIb}, {OOR, AAX, AIv}, {OPUSH, ACS, }, {O0F, }, +//10 + {OADC, AEb, AGb}, {OADC, AEv, AGv}, {OADC, AGb, AEb}, {OADC, AGv, AEv}, + {OADC, AAL, AIb}, {OADC, AAX, AIv}, {OPUSH, ASS, }, {OPOP, ASS, }, + {OSBB, AEb, AGb}, {OSBB, AEv, AGv}, {OSBB, AGb, AEb}, {OSBB, AGv, AEv}, + {OSBB, AAL, AIb}, {OSBB, AAX, AIv}, {OPUSH, ADS, }, {OPOP, ADS, }, +//20 + {OAND, AEb, AGb}, {OAND, AEv, AGv}, {OAND, AGb, AEb}, {OAND, AGv, AEv}, + {OAND, AAL, AIb}, {OAND, AAX, AIv}, {OSEG, AES, }, {ODAA, }, + {OSUB, AEb, AGb}, {OSUB, AEv, AGv}, {OSUB, AGb, AEb}, {OSUB, AGv, AEv}, + {OSUB, AAL, AIb}, {OSUB, AAX, AIv}, {OSEG, ACS, }, {ODAS, }, +//30 + {OXOR, AEb, AGb}, {OXOR, AEv, AGv}, {OXOR, AGb, AEb}, {OXOR, AGv, AEv}, + {OXOR, AAL, AIb}, {OXOR, AAX, AIv}, {OSEG, ASS, }, {OAAA, }, + {OCMP, AEb, AGb}, {OCMP, AEv, AGv}, {OCMP, AGb, AEb}, {OCMP, AGv, AEv}, + {OCMP, AAL, AIb}, {OCMP, AAX, AIv}, {OSEG, ADS, }, {OAAS, }, +//40 + {OINC, AAX, }, {OINC, ACX, }, {OINC, ADX, }, {OINC, ABX, }, + {OINC, ASP, }, {OINC, ABP, }, {OINC, ASI, }, {OINC, ADI, }, + {ODEC, AAX, }, {ODEC, ACX, }, {ODEC, ADX, }, {ODEC, ABX, }, + {ODEC, ASP, }, {ODEC, ABP, }, {ODEC, ASI, }, {ODEC, ADI, }, +//50 + {OPUSH, AAX, }, {OPUSH, ACX, }, {OPUSH, ADX, }, {OPUSH, ABX, }, + {OPUSH, ASP, }, {OPUSH, ABP, }, {OPUSH, ASI, }, {OPUSH, ADI, }, + {OPOP, AAX, }, {OPOP, ACX, }, {OPOP, ADX, }, {OPOP, ABX, }, + {OPOP, ASP, }, {OPOP, ABP, }, {OPOP, ASI, }, {OPOP, ADI, }, +//60 + {OPUSHA, }, {OPOPA, }, {OBOUND,AGv,AMa,AMa2}, {OARPL, AEw, AGw}, + {OSEG, AFS, }, {OSEG, AGS, }, {OOSIZE, }, {OASIZE, }, + {OPUSH, AIv, }, {OIMUL,AGv,AEv,AIv},{OPUSH, AIb, }, {OIMUL,AGv,AEv,AIb}, + {OINS, AYb, ADX}, {OINS, AYv, ADX}, {OOUTS, ADX, AXb}, {OOUTS, ADX, AXv}, +//70 + {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, + {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, + {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, + {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, {OJUMP, AJb, }, +//80 + {OGP1, AEb, AIb}, {OGP1, AEv, AIv}, {OGP1, AEb, AIb}, {OGP1, AEv, AIc}, + {OTEST, AEb, AGb}, {OTEST, AEv, AGv}, {OXCHG, AEb, AGb}, {OXCHG, AEv, AGv}, + {OMOV, AEb, AGb}, {OMOV, AEv, AGv}, {OMOV, AGb, AEb}, {OMOV, AGv, AEv}, + {OMOV, AEw, ASw}, {OLEA, AGv, AM }, {OMOV, ASw, AEw}, {OGP10, }, +//90 + {ONOP, }, {OXCHG, ACX, AAX}, {OXCHG, ADX, AAX}, {OXCHG, ABX, AAX}, + {OXCHG, ASP, AAX}, {OXCHG, ABP, AAX}, {OXCHG, ASI, AAX}, {OXCHG, ADI, AAX}, + {OCBW, }, {OCWD, }, {OCALL, AAp, }, {OWAIT, }, + {OPUSHF,AFv, }, {OPOPF, AFv, }, {OSAHF, AAH, }, {OLAHF, AAH, }, +//A0 + {OMOV, AAL, AOb}, {OMOV, AAX, AOv}, {OMOV, AOb, AAL}, {OMOV, AOv, AAX}, + {OMOVS, AYb, AXb}, {OMOVS, AYv, AXv}, {OCMPS, AYb, AXb}, {OCMPS, AYv, AXv}, + {OTEST, AAL, AIb}, {OTEST, AAX, AIv}, {OSTOS, AYb, AAL}, {OSTOS, AYv, AAX}, + {OLODS, AAL, AXb}, {OLODS, AAX, AXv}, {OSCAS, AYb, AAL}, {OSCAS, AYv, AAX}, +//B0 + {OMOV, AAL, AIb}, {OMOV, ACL, AIb}, {OMOV, ADL, AIb}, {OMOV, ABL, AIb}, + {OMOV, AAH, AIb}, {OMOV, ACH, AIb}, {OMOV, ADH, AIb}, {OMOV, ABH, AIb}, + {OMOV, AAX, AIv}, {OMOV, ACX, AIv}, {OMOV, ADX, AIv}, {OMOV, ABX, AIv}, + {OMOV, ASP, AIv}, {OMOV, ABP, AIv}, {OMOV, ASI, AIv}, {OMOV, ADI, AIv}, +//C0 + {OGP2, AEb, AIb}, {OGP2, AEv, AIb}, {ORET, AIw, }, {ORET, A0, }, + {OLFP,AES,AGv,AMp},{OLFP,ADS,AGv,AMp},{OGP12, AEb, AIb}, {OGP12, AEv, AIv}, + {OENTER,AIw, AIb}, {OLEAVE, }, {ORETF, AIw, }, {ORETF, A0, }, + {OINT, A3, }, {OINT, AIb, }, {OINT, A4, }, {OIRET, }, +//D0 + {OGP2, AEb, A1 }, {OGP2, AEv, A1 }, {OGP2, AEb, ACL}, {OGP2, AEv, ACL}, + {OAAM, AIb, }, {OAAD, AIb, }, {OBAD, }, {OXLAT, AAL, ABX}, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//E0 + {OLOOPNZ,AJb, }, {OLOOPZ,AJb, }, {OLOOP, AJb, }, {OJUMP, AJb, }, + {OIN, AAL, AIb}, {OIN, AAX, AIb}, {OOUT, AIb, AAL}, {OOUT, AIb, AAX}, + {OCALL, AJv, }, {OJUMP, AJv, }, {OJUMP, AAp, }, {OJUMP, AJb, }, + {OIN, AAL, ADX}, {OIN, AAX, ADX}, {OOUT, ADX, AAL}, {OOUT, ADX, AAX}, +//F0 + {OLOCK, }, {OBAD, }, {OREPNE, }, {OREPE, }, + {OHLT, }, {OCMC, }, {OGP3b, }, {OGP3v, }, + {OCLC, }, {OSTC, }, {OCLI, }, {OSTI, }, + {OCLD, }, {OSTD, }, {OGP4, }, {OGP5, }, +}; + +static Optab optab0F[256] = { +//00 + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//10 - mostly floating point and quadword moves + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//20 - doubleword <-> control register moves, other arcana + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//30 - wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//40 - conditional moves + {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, + {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, + {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, + {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, {OCMOV, AGv, AEv}, +//50 - floating point, mmx stuff + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//60 - floating point, mmx stuff + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//70 - floating point, mmx stuff + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//80 - long-displacement jumps + {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, + {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, + {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, + {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, {OJUMP, AJv, }, +//90 - conditional byte set + {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, + {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, + {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, + {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, {OSET, AEb, }, +//A0 + {OPUSH, AFS, }, {OPOP, AFS, }, {OCPUID, }, {OBT, AEv, AGv}, + {OSHLD,AEv,AGv,AIb}, {OSHLD,AEv,AGv,ACL}, {OBAD, }, {OBAD, }, + {OPUSH, AGS, }, {OPOP, AGS, }, {OBAD, }, {OBTS, AEv, AGv}, + {OSHRD,AEv,AGv,AIb}, {OSHRD,AEv,AGv,ACL}, {OBAD, }, {OIMUL, AGv,AGv,AEv}, +//B0 - mostly arcana + {OBAD, }, {OBAD, }, {OLFP,ASS,AGv,AMp},{OBTR,AEv,AGv }, + {OLFP,AFS,AGv,AMp},{OLFP,AGS,AGv,AMp},{OMOVZX,AGv,AEb }, {OMOVZX,AGv,AEw }, + {OBAD, }, {OBAD, }, {OGP8, }, {OBAD, }, + {OBSF,AGv,AEv }, {OBSR,AGv,AEv }, {OMOVSX,AGv,AEb }, {OMOVSX,AGv,AEw }, +//C0 - more arcana + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//D0 - mmx + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//E0 - mmx + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +//F0 - mmx + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +}; + +/* some operands map to whole groups; group numbers from intel opcode map */ +/* args filled in already (in OGP1 entries) */ +static Optab optabgp1[8] = { + {OADD, }, {OOR, }, {OADC, }, {OSBB, }, + {OAND, }, {OSUB, }, {OXOR, }, {OCMP, }, +}; + +/* args filled in already (in OGP2 entries) */ +static Optab optabgp2[8] = { + {OROL, }, {OROR, }, {ORCL, }, {ORCR, }, + {OSHL, }, {OSHR, }, {OBAD, }, {OSAR, }, +}; + +static Optab optabgp3b[8] = { + {OTEST, AEb, AIb}, {OBAD, }, {ONOT, AEb, }, {ONEG, AEb, }, + {OMUL,AAX,AAL,AEb},{OIMUL,AAX,AAL,AEb},{ODIV, AEb, }, {OIDIV, AEb, }, +}; + +static Optab optabgp3v[8] = { + {OTEST, AEv, AIv}, {OBAD, }, {ONOT, AEv, }, {ONEG, AEv, }, + {OMUL,AAX,AAX,AEv},{OIMUL,AAX,AAX,AEv},{ODIV, AEv, }, {OIDIV, AEv, }, +}; + +static Optab optabgp4[8] = { + {OINC, AEb, }, {ODEC, AEb, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +}; + +static Optab optabgp5[8] = { + {OINC, AEv, }, {ODEC, AEv, }, {OCALL, AEv, }, {OCALL, AMp }, + {OJUMP, AEv, }, {OJUMP, AMp, }, {OPUSH, AEv, }, {OBAD, }, +}; + +static Optab optabgp8[8] = { + {OMOV, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBT, AEv, AIb }, {OBTS, AEv, AIb }, {OBTR, AEv, AIb }, {OBTC, AEv, AIb }, +}; + +static Optab optabgp10[8] = { + {OPOP, AEv, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +}; + +static Optab optabgp12[8] = { + {OMOV, }, {OBAD, }, {OBAD, }, {OBAD, }, + {OBAD, }, {OBAD, }, {OBAD, }, {OBAD, }, +}; + +/* optabg6 unimplemented - mostly segment manipulation */ +/* optabg7 unimplemented - more segment manipulation */ +/* optabg8 unimplemented - bit tests */ + +/* + * most of optabg9 - optabg16 decode differently depending on the mod value of + * the modrm byte. they're mostly arcane instructions so they're not + * implemented. + */ + +static Optab *optabgp[NUMOP] = { + [OGP1] optabgp1, + [OGP2] optabgp2, + [OGP3b] optabgp3b, + [OGP3v] optabgp3v, + [OGP4] optabgp4, + [OGP5] optabgp5, + [OGP8] optabgp8, + [OGP10] optabgp10, + [OGP12] optabgp12, +}; + +static uchar modrmarg[NATYPE] = { + [AEb] 1, + [AEw] 1, + [AEv] 1, + [AGb] 1, + [AGw] 1, + [AGv] 1, + [AM] 1, + [AMp] 1, + [AMa] 1, + [AMa2] 1, + [ASw] 1, + [AJr] 1, +}; + +static void +getmodrm16(Iarg *ip, Inst *i) +{ + Iarg *p; + uchar b; + + b = ar(ip); ip->off++; + + i->mod = b>>6; + i->reg = (b>>3)&7; + i->rm = b&7; + + if(i->mod == 3) + return; + + switch(i->rm){ + case 0: + i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RSI)); + i->off &= 0xFFFF; + break; + case 1: + i->off = ar(areg(ip->cpu, 2, RBX)) + ar(areg(ip->cpu, 2, RDI)); + i->off &= 0xFFFF; + break; + case 2: + i->dsreg = RSS; + i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RSI)); + i->off &= 0xFFFF; + break; + case 3: + i->dsreg = RSS; + i->off = ar(areg(ip->cpu, 2, RBP)) + ar(areg(ip->cpu, 2, RDI)); + i->off &= 0xFFFF; + break; + case 4: + i->off = ar(areg(ip->cpu, 2, RSI)); + break; + case 5: + i->off = ar(areg(ip->cpu, 2, RDI)); + break; + case 6: + if(i->mod == 0){ + p = adup(ip); ip->off += 2; + p->len = 2; + i->off = ar(p); + return; + } + i->dsreg = RSS; + i->off = ar(areg(ip->cpu, 2, RBP)); + break; + case 7: + i->off = ar(areg(ip->cpu, 2, RBX)); + break; + } + switch(i->mod){ + case 1: + i->off += (i->disp = ars(ip)); ip->off++; + i->off &= 0xFFFF; + break; + case 2: + p = adup(ip); ip->off += 2; + p->len = 2; + i->off += (i->disp = ars(p)); + i->off &= 0xFFFF; + break; + } +} + +static void +getmodrm32(Iarg *ip, Inst *i) +{ + static uchar scaler[] = {1, 2, 4, 8}; + Iarg *p; + uchar b; + + b = ar(ip); ip->off++; + + i->mod = b>>6; + i->reg = (b>>3)&7; + i->rm = b&7; + + if(i->mod == 3) + return; + + switch(i->rm){ + case 0: + case 1: + case 2: + case 3: + case 6: + case 7: + i->off = ar(areg(ip->cpu, 4, i->rm + RAX)); + break; + case 4: + b = ar(ip); ip->off++; + i->scale = b>>6; + i->index = (b>>3)&7; + i->base = b&7; + + if(i->base != 5){ + i->off = ar(areg(ip->cpu, 4, i->base + RAX)); + break; + } + case 5: + if(i->mod == 0){ + p = adup(ip); ip->off += 4; + p->len = 4; + i->off = ar(p); + } else { + i->dsreg = RSS; + i->off = ar(areg(ip->cpu, 4, RBP)); + } + break; + } + + if(i->rm == 4 && i->index != 4) + i->off += ar(areg(ip->cpu, 4, i->index + RAX)) * scaler[i->scale]; + + switch(i->mod){ + case 1: + i->off += (i->disp = ars(ip)); ip->off++; + break; + case 2: + p = adup(ip); ip->off += 4; + p->len = 4; + i->off += (i->disp = ars(p)); + break; + } +} + +static Iarg* +getarg(Iarg *ip, Inst *i, uchar atype) +{ + Iarg *a; + uchar len, reg; + + len = i->olen; + switch(atype){ + default: + abort(); + + case A0: + case A1: + case A2: + case A3: + case A4: + a = acon(ip->cpu, len, atype - A0); + break; + + case AEb: + len = 1; + if(0){ + case AEw: + len = 2; + } + case AEv: + if(i->mod == 3){ + reg = i->rm; + goto REG; + } + goto MEM; + + case AM: + case AMp: + case AMa: + case AMa2: + if(i->mod == 3) + trap(ip->cpu, EBADOP); + MEM: + a = amem(ip->cpu, len, i->sreg, i->off); + if(atype == AMa2) + a->off += i->olen; + break; + + case AGb: + len = 1; + if(0){ + case AGw: + len = 2; + } + case AGv: + reg = i->reg; + REG: + a = areg(ip->cpu, len, reg + RAX); + if(len == 1 && reg >= 4){ + a->reg -= 4; + a->tag |= TH; + } + break; + + case AIb: + case AIc: + len = 1; + if(0){ + case AIw: + len = 2; + } + case AIv: + a = adup(ip); ip->off += len; + a->len = len; + break; + + case AJb: + len = 1; + case AJv: + a = adup(ip); ip->off += len; + a->len = len; + a->off = ip->off + ars(a); + break; + + case AJr: + if(i->mod != 3) + trap(ip->cpu, EBADOP); + a = adup(ip); + a->off = ar(areg(ip->cpu, i->olen, i->rm + RAX)); + break; + + case AAp: + a = afar(ip, ip->len, len); ip->off += 2+len; + break; + + case AOb: + len = 1; + case AOv: + a = adup(ip); ip->off += i->alen; + a->len = i->alen; + a = amem(ip->cpu, len, i->sreg, ar(a)); + break; + + case ASw: + reg = i->reg; + SREG: + a = areg(ip->cpu, 2, reg + RES); + break; + + case AXb: + len = 1; + case AXv: + a = amem(ip->cpu, len, i->sreg, ar(areg(ip->cpu, i->alen, RSI))); + break; + + case AYb: + len = 1; + case AYv: + a = amem(ip->cpu, len, RES, ar(areg(ip->cpu, i->alen, RDI))); + break; + + case AFv: + a = areg(ip->cpu, len, RFL); + break; + + case AAL: + case ACL: + case ADL: + case ABL: + case AAH: + case ACH: + case ADH: + case ABH: + len = 1; + reg = atype - AAL; + goto REG; + + case AAX: + case ACX: + case ADX: + case ABX: + case ASP: + case ABP: + case ASI: + case ADI: + reg = atype - AAX; + goto REG; + + case AES: + case ACS: + case ASS: + case ADS: + case AFS: + case AGS: + reg = atype - AES; + goto SREG; + } + a->atype = atype; + return a; +} + +static int +otherlen(int a) +{ + if(a == 2) + return 4; + else if(a == 4) + return 2; + abort(); + return 0; +} + +void +decode(Iarg *ip, Inst *i) +{ + Optab *t, *t2; + Cpu *cpu; + + cpu = ip->cpu; + + i->op = 0; + i->rep = 0; + i->sreg = 0; + i->dsreg = RDS; + i->olen = cpu->olen; + i->alen = cpu->alen; + + for(;;){ + i->code = ar(ip); ip->off++; + t = optab + i->code; + switch(t->op){ + case OOSIZE: + i->olen = otherlen(cpu->olen); + continue; + case OASIZE: + i->alen = otherlen(cpu->alen); + continue; + case OREPE: + case OREPNE: + i->rep = t->op; + continue; + case OLOCK: + continue; + case OSEG: + i->sreg = t->a1-AES+RES; + continue; + case O0F: + i->code = ar(ip); ip->off++; + t = optab0F + i->code; + break; + } + break; + } + t2 = optabgp[t->op]; + if(t2 || modrmarg[t->a1] || modrmarg[t->a2] || modrmarg[t->a3]) + if(i->alen == 2) + getmodrm16(ip, i); + else + getmodrm32(ip, i); + if(i->sreg == 0) + i->sreg = i->dsreg; + + i->a1 = i->a2 = i->a3 = nil; + for(;;){ + if(t->a1) + i->a1 = getarg(ip, i, t->a1); + if(t->a2) + i->a2 = getarg(ip, i, t->a2); + if(t->a3) + i->a3 = getarg(ip, i, t->a3); + if(t2 == nil) + break; + t = t2 + i->reg; + t2 = nil; + } + i->op = t->op; +} --- /sys/src/cmd/aux/realemu/fmt.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/fmt.c Wed Sep 12 00:01:29 2012 @@ -0,0 +1,385 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +static char *opstr[] = { /* Edit s/O(.*),/[O\1]= "\1",/g */ + [OBAD]= "BAD", + [O0F]= "0F", + [OAAA]= "AAA", + [OAAD]= "AAD", + [OAAM]= "AAM", + [OAAS]= "AAS", + [OADC]= "ADC", + [OADD]= "ADD", + [OAND]= "AND", + [OARPL]= "ARPL", + [OASIZE]= "ASIZE", + [OBOUND]= "BOUND", + [OBT]= "BT", + [OBTC]= "BTC", + [OBTR]= "BTR", + [OBTS]= "BTS", + [OBSF]= "BSF", + [OBSR]= "BSR", + [OCALL]= "CALL", + [OCBW]= "CBW", + [OCLC]= "CLC", + [OCLD]= "CLD", + [OCLI]= "CLI", + [OCMC]= "CMC", + [OCMOV]= "CMOV", + [OCMP]= "CMP", + [OCMPS]= "CMPS", + [OCWD]= "CWD", + [ODAA]= "DAA", + [ODAS]= "DAS", + [ODEC]= "DEC", + [ODIV]= "DIV", + [OENTER]= "ENTER", + [OGP1]= "GP1", + [OGP2]= "GP2", + [OGP3b]= "GP3b", + [OGP3v]= "GP3v", + [OGP4]= "GP4", + [OGP5]= "GP5", + [OHLT]= "HLT", + [OIDIV]= "IDIV", + [OIMUL]= "IMUL", + [OIN]= "IN", + [OINC]= "INC", + [OINS]= "INS", + [OINT]= "INT", + [OIRET]= "IRET", + [OJUMP]= "JUMP", + [OLAHF]= "LAHF", + [OLFP]= "LFP", + [OLEA]= "LEA", + [OLEAVE]= "LEAVE", + [OLOCK]= "LOCK", + [OLODS]= "LODS", + [OLOOP]= "LOOP", + [OLOOPNZ]= "LOOPNZ", + [OLOOPZ]= "LOOPZ", + [OMOV]= "MOV", + [OMOVS]= "MOVS", + [OMOVZX]= "MOVZX", + [OMOVSX]= "MOVSX", + [OMUL]= "MUL", + [ONEG]= "NEG", + [ONOP]= "NOP", + [ONOT]= "NOT", + [OOR]= "OR", + [OOSIZE]= "OSIZE", + [OOUT]= "OUT", + [OOUTS]= "OUTS", + [OPOP]= "POP", + [OPOPA]= "POPA", + [OPOPF]= "POPF", + [OPUSH]= "PUSH", + [OPUSHA]= "PUSHA", + [OPUSHF]= "PUSHF", + [ORCL]= "RCL", + [ORCR]= "RCR", + [OREPE]= "REPE", + [OREPNE]= "REPNE", + [ORET]= "RET", + [ORETF]= "RETF", + [OROL]= "ROL", + [OROR]= "ROR", + [OSAHF]= "SAHF", + [OSAR]= "SAR", + [OSBB]= "SBB", + [OSCAS]= "SCAS", + [OSEG]= "SEG", + [OSET]= "SET", + [OSHL]= "SHL", + [OSHLD]= "SHLD", + [OSHR]= "SHR", + [OSHRD]= "SHRD", + [OSTC]= "STC", + [OSTD]= "STD", + [OSTI]= "STI", + [OSTOS]= "STOS", + [OSUB]= "SUB", + [OTEST]= "TEST", + [OWAIT]= "WAIT", + [OXCHG]= "XCHG", + [OXLAT]= "XLAT", + [OXOR]= "XOR", +}; + +static char *memstr16[] = { + "BX+SI", + "BX+DI", + "BP+SI", + "BP+DI", + "SI", + "DI", + "BP", + "BX", +}; + +static char *memstr32[] = { + "EAX", + "ECX", + "EDX", + "EBX", + "0", + "EBP", + "ESI", + "EDI", +}; + +static int +argconv(char *p, Inst *i, Iarg *a) +{ + jmp_buf jmp; + char *s; + + s = p; + switch(a->tag){ + default: + abort(); + + case TCON: + return sprint(p, "%lud", a->val); + case TREG: + case TREG|TH: + switch(a->len){ + case 1: + return sprint(p, "%c%c", "ACDB"[a->reg], "LH"[(a->tag & TH) != 0]); + case 4: + *p++ = 'E'; + case 2: + p += sprint(p, "%c%c", + "ACDBSBSDECSDFGIF"[a->reg], + "XXXXPPIISSSSSSPL"[a->reg]); + return p - s; + } + case TMEM: + break; + } + + /* setup trap jump in case we dereference bad memory */ + memmove(jmp, a->cpu->jmp, sizeof jmp); + if(setjmp(a->cpu->jmp)){ + p += sprint(p, "<%.4lux:%.4lux>", a->seg, a->off); + goto out; + } + + switch(a->atype){ + default: + abort(); + + case AAp: + p += sprint(p, "[%.4lux:%.4lux]", a->seg, a->off); + break; + + case AJb: + case AJv: + p += sprint(p, "[%.4lux]", a->off); + break; + + case AIc: + p += sprint(p, "$%#.2lx", ars(a)); + break; + case AIb: + case AIw: + case AIv: + p += sprint(p, "$%#.*lux", (int)a->len*2, ar(a)); + break; + + case AMp: + *p++ = '*'; + case AEb: + case AEw: + case AEv: + case AM: + case AMa: + case AMa2: + case AOb: + case AOv: + if(i->sreg != RDS) + p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]); + if(a->atype == AOb || a->atype == AOv || (i->mod == 0 && + (i->alen == 2 && i->rm == 6) || + (i->alen == 4 && ((i->rm == 5) || + (i->rm == 4 && i->index == 4 && i->base == 5))))){ + p += sprint(p, "[%.*lux]", (int)i->alen*2, a->off); + break; + } + *p++ = '['; + if(i->alen == 2) + p += sprint(p, "%s", memstr16[i->rm]); + else{ + if(i->rm == 4){ + if(i->index != 4) + p += sprint(p, "%c*%s+", "1248"[i->scale], memstr32[i->index]); + if(i->base != 5) + p += sprint(p, "%s", memstr32[i->base]); + else{ + if(i->mod == 0) + p += sprint(p, "%.4lux", i->off); + else + p += sprint(p, "EBP"); + } + } else + p += sprint(p, "%s", memstr32[i->rm]); + } + if(i->mod != 0) + p += sprint(p, "%+lx", i->disp); + *p++ = ']'; + break; + + case AXb: + case AXv: + if(a->sreg != RDS) + p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]); + p += sprint(p, "[SI]"); + break; + case AYb: + case AYv: + if(a->sreg != RDS) + p += sprint(p, "%cS:", "ECSDFG"[a->sreg - RES]); + p += sprint(p, "[DI]"); + break; + } + +out: + memmove(a->cpu->jmp, jmp, sizeof jmp); + *p = 0; + return p - s; +} + +static char *jmpstr[] = { + "JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA", + "JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG", +}; + +int +instfmt(Fmt *fmt) +{ + Inst *i; + char *p, buf[256]; + + i = va_arg(fmt->args, Inst*); + p = buf; + + if(i->olen == 4) + p += sprint(p, "O32: "); + if(i->alen == 4) + p += sprint(p, "A32: "); + if(i->rep) + p += sprint(p, "%s: ", opstr[i->rep]); + + if(i->op == OXLAT && i->sreg != RDS) + p += sprint(p, "%cS:", "ECSDFG"[i->sreg - RES]); + + if(i->op == OJUMP){ + switch(i->code){ + case 0xE3: + p += sprint(p, "%s ", "JCXZ"); + break; + case 0xEB: + case 0xE9: + case 0xEA: + case 0xFF: + p += sprint(p, "%s ", "JMP"); + break; + default: + p += sprint(p, "%s ", jmpstr[i->code&0xF]); + break; + } + } else + p += sprint(p, "%s ", opstr[i->op]); + + + for(;;){ + if(i->a1 == nil) + break; + p += argconv(p, i, i->a1); + if(i->a2 == nil) + break; + *p++ = ','; + *p++ = ' '; + p += argconv(p, i, i->a2); + if(i->a3 == nil) + break; + *p++ = ','; + *p++ = ' '; + p += argconv(p, i, i->a3); + break; + } + *p = 0; + fmtstrcpy(fmt, buf); + return 0; +} + +int +flagfmt(Fmt *fmt) +{ + char buf[16]; + ulong f; + + f = va_arg(fmt->args, ulong); + sprint(buf, "%c%c%c%c%c%c%c", + (f & CF) ? 'C' : 'c', + (f & SF) ? 'S' : 's', + (f & ZF) ? 'Z' : 'z', + (f & OF) ? 'O' : 'o', + (f & PF) ? 'P' : 'p', + (f & DF) ? 'D' : 'd', + (f & IF) ? 'I' : 'i'); + fmtstrcpy(fmt, buf); + return 0; +} + +int +cpufmt(Fmt *fmt) +{ + char buf[512]; + jmp_buf jmp; + Cpu *cpu; + Inst i; + + cpu = va_arg(fmt->args, Cpu*); + + memmove(jmp, cpu->jmp, sizeof jmp); + if(setjmp(cpu->jmp) == 0) + decode(amem(cpu, 1, RCS, cpu->reg[RIP]), &i); + memmove(cpu->jmp, jmp, sizeof jmp); + + snprint(buf, sizeof(buf), + "%.6lux " + "%.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux " + "%.4lux %.4lux %.4lux %.4lux " + "%J %.4lux %.2ux %I", + + cpu->ic, + + cpu->reg[RAX], + cpu->reg[RBX], + cpu->reg[RCX], + cpu->reg[RDX], + + cpu->reg[RDI], + cpu->reg[RSI], + + cpu->reg[RBP], + cpu->reg[RSP], + + cpu->reg[RDS], + cpu->reg[RES], + cpu->reg[RSS], + cpu->reg[RCS], + + cpu->reg[RFL], + cpu->reg[RIP], + + i.code, + &i); + + fmtstrcpy(fmt, buf); + return 0; +} --- /sys/src/cmd/aux/realemu/fns.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/fns.h Sat Apr 30 22:21:38 2011 @@ -0,0 +1,31 @@ +/* arg */ +Iarg *adup(Iarg *x); +Iarg *areg(Cpu *cpu, uchar len, uchar reg); +Iarg *amem(Cpu *cpu, uchar len, uchar sreg, ulong off); +Iarg *afar(Iarg *mem, uchar len, uchar alen); +Iarg *acon(Cpu *cpu, uchar len, ulong val); +ulong ar(Iarg *a); +long ars(Iarg *a); +void aw(Iarg *a, ulong w); + +/* decode */ +void decode(Iarg *ip, Inst *i); + +/* xec */ +void trap(Cpu *cpu, int e); +int intr(Cpu *cpu, int v); +int xec(Cpu *cpu, int n); + +#pragma varargck type "I" Inst* +#pragma varargck type "J" ulong +#pragma varargck type "C" Cpu* + +int instfmt(Fmt *fmt); +int flagfmt(Fmt *fmt); +int cpufmt(Fmt *fmt); + +/* pit */ +void clockpit(Pit *pit, vlong cycles); +void setgate(Pit *ch, uchar gate); +uchar rpit(Pit *pit, uchar addr); +void wpit(Pit *pit, uchar addr, uchar data); --- /sys/src/cmd/aux/realemu/loadcom.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/loadcom.c Sat Apr 30 22:21:38 2011 @@ -0,0 +1,43 @@ +#include +#include + +#include "/386/include/ureg.h" + +static uchar buf[0xFF01]; + +void +main(int argc, char *argv[]) +{ + struct Ureg u; + int fd, rreg, rmem, len; + + ARGBEGIN { + } ARGEND; + + if(argc == 0){ + fprint(2, "usage:\t%s file.com\n", argv0); + exits("usage"); + } + if((fd = open(*argv, OREAD)) < 0) + sysfatal("open: %r"); + + if((rreg = open("/dev/realmode", OWRITE)) < 0) + sysfatal("open realmode: %r"); + if((rmem = open("/dev/realmodemem", OWRITE)) < 0) + sysfatal("open realmodemem: %r"); + if((len = readn(fd, buf, sizeof buf)) < 2) + sysfatal("file too small"); + + memset(&u, 0, sizeof u); + u.cs = u.ds = u.es = u.fs = u.gs = 0x1000; + u.ss = 0x0000; + u.sp = 0xfffe; + u.pc = 0x0100; + + seek(rmem, (u.cs<<4) + u.pc, 0); + if(write(rmem, buf, len) != len) + sysfatal("write mem: %r"); + + if(write(rreg, &u, sizeof u) != sizeof u) + sysfatal("write reg: %r"); +} --- /sys/src/cmd/aux/realemu/main.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/main.c Sun Sep 9 23:38:57 2012 @@ -0,0 +1,786 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +/* for fs */ +#include +#include +#include +#include <9p.h> + +#pragma pack on +#include "/386/include/ureg.h" +#pragma pack off + +enum { + MEMSIZE = 0x100000, + + RMBUF = 0x9000, + RMCODE = 0x8000, + + PITHZ = 1193182, + PITNS = 1000000000/PITHZ, +}; + +static Cpu cpu; +static uchar memory[MEMSIZE+4]; +static uchar pageregtmp[0x10]; +static int portfd[5]; +static int realmemfd; +static int cputrace; +static int porttrace; +static Pit pit[3]; + +static vlong pitclock; + +static void +startclock(void) +{ + pitclock = nsec(); +} + +static void +runclock(void) +{ + vlong now, dt; + + now = nsec(); + dt = now - pitclock; + if(dt >= PITNS){ + clockpit(pit, dt/PITNS); + pitclock = now; + } +} + +static ulong +gw1(uchar *p) +{ + return p[0]; +} +static ulong +gw2(uchar *p) +{ + return (ulong)p[0] | (ulong)p[1]<<8; +} +static ulong +gw4(uchar *p) +{ + return (ulong)p[0] | (ulong)p[1]<<8 | (ulong)p[2]<<16 | (ulong)p[3]<<24; +} +static ulong (*gw[5])(uchar *p) = { + [1] gw1, + [2] gw2, + [4] gw4, +}; + +static void +pw1(uchar *p, ulong w) +{ + p[0] = w & 0xFF; +} +static void +pw2(uchar *p, ulong w) +{ + p[0] = w & 0xFF; + p[1] = (w>>8) & 0xFF; +} +static void +pw4(uchar *p, ulong w) +{ + p[0] = w & 0xFF; + p[1] = (w>>8) & 0xFF; + p[2] = (w>>16) & 0xFF; + p[3] = (w>>24) & 0xFF; +} +static void (*pw[5])(uchar *p, ulong w) = { + [1] pw1, + [2] pw2, + [4] pw4, +}; + +static ulong +rbad(void *, ulong off, int) +{ + fprint(2, "bad mem read %.5lux\n", off); + trap(&cpu, EMEM); + + /* not reached */ + return 0; +} + +static void +wbad(void *, ulong off, ulong, int) +{ + fprint(2, "bad mem write %.5lux\n", off); + trap(&cpu, EMEM); +} + +static ulong +rmem(void *, ulong off, int len) +{ + return gw[len](memory + off); +} + +static void +wmem(void *, ulong off, ulong w, int len) +{ + pw[len](memory + off, w); +} + +static ulong +rrealmem(void *, ulong off, int len) +{ + uchar data[4]; + + if(pread(realmemfd, data, len, off) != len){ + fprint(2, "bad real mem read %.5lux: %r\n", off); + trap(&cpu, EMEM); + } + return gw[len](data); +} + +static void +wrealmem(void *, ulong off, ulong w, int len) +{ + uchar data[4]; + + pw[len](data, w); + if(pwrite(realmemfd, data, len, off) != len){ + fprint(2, "bad real mem write %.5lux: %r\n", off); + trap(&cpu, EMEM); + } +} + + +static ulong +rport(void *, ulong p, int len) +{ + uchar data[4]; + ulong w; + + switch(p){ + case 0x20: /* PIC 1 */ + case 0x21: + w = 0; + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + runclock(); + w = rpit(pit, p - 0x40); + break; + case 0x60: /* keyboard data output buffer */ + w = 0; + break; + case 0x61: /* keyboard controller port b */ + runclock(); + w = pit[2].out<<5 | pit[2].gate; + break; + case 0x62: /* PPI (XT only) */ + runclock(); + w = pit[2].out<<5; + break; + case 0x63: /* PPI (XT only) read dip switches */ + w = 0; + break; + case 0x65: /* A20 gate */ + w = 1 << 2; + break; + case 0x80: /* extra dma registers (temp) */ + case 0x84: + case 0x85: + case 0x86: + case 0x88: + case 0x8c: + case 0x8d: + case 0x8e: + w = pageregtmp[p-0x80]; + break; + case 0x92: /* A20 gate (system control port a) */ + w = 1 << 1; + break; + case 0xa0: /* PIC 2 */ + case 0xa1: + w = 0; + break; + default: + if(pread(portfd[len], data, len, p) != len){ + fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p); + trap(&cpu, EIO); + } + w = gw[len](data); + } + if(porttrace) + fprint(2, "rport %.4lux %.*lux\n", p, len<<1, w); + return w; +} + +static void +wport(void *, ulong p, ulong w, int len) +{ + uchar data[4]; + + if(porttrace) + fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w); + + switch(p){ + case 0x20: /* PIC 1 */ + case 0x21: + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + runclock(); + wpit(pit, p - 0x40, w); + break; + case 0x60: /* keyboard controller data port */ + break; + case 0x61: /* keyboard controller port B */ + setgate(&pit[2], w & 1); + break; + case 0x62: /* PPI (XT only) */ + case 0x63: + case 0x64: /* KB controller input buffer (ISA, EISA) */ + case 0x65: /* A20 gate (bit 2) */ + break; + case 0x80: + case 0x84: + case 0x85: + case 0x86: + case 0x88: + case 0x8c: + case 0x8d: + case 0x8e: + pageregtmp[p-0x80] = w & 0xFF; + break; + case 0x92: /* system control port a */ + case 0x94: /* system port enable setup register */ + case 0x96: + break; + case 0xA0: /* PIC 2 */ + case 0xA1: + break; + + default: + pw[len](data, w); + if(pwrite(portfd[len], data, len, p) != len){ + fprint(2, "bad %d bit port write %.4lux: %r\n", len*8, p); + trap(&cpu, EIO); + } + } +} + +static Bus memio[] = { + /* 0 */ memory, rmem, wmem, /* RAM: IVT, BIOS data area */ + /* 1 */ memory, rmem, wmem, /* custom */ + /* 2 */ nil, rbad, wbad, + /* 3 */ nil, rbad, wbad, + /* 4 */ nil, rbad, wbad, + /* 5 */ nil, rbad, wbad, + /* 6 */ nil, rbad, wbad, + /* 7 */ nil, rbad, wbad, + /* 8 */ nil, rbad, wbad, + /* 9 */ memory, rmem, wmem, /* RAM: extended BIOS data area */ + /* A */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */ + /* B */ nil, rrealmem, wrealmem, /* RAM: VGA framebuffer */ + /* C */ memory, rmem, wmem, /* ROM: VGA BIOS */ + /* D */ nil, rbad, wbad, + /* E */ memory, rmem, wbad, /* ROM: BIOS */ + /* F */ memory, rmem, wbad, /* ROM: BIOS */ +}; + +static Bus portio = { + nil, rport, wport, +}; + +static void +cpuinit(void) +{ + int i; + + fmtinstall('I', instfmt); + fmtinstall('J', flagfmt); + fmtinstall('C', cpufmt); + + if((portfd[1] = open("#P/iob", ORDWR)) < 0) + sysfatal("open iob: %r"); + if((portfd[2] = open("#P/iow", ORDWR)) < 0) + sysfatal("open iow: %r"); + if((portfd[4] = open("#P/iol", ORDWR)) < 0) + sysfatal("open iol: %r"); + + if((realmemfd = open("#P/realmodemem", ORDWR)) < 0) + sysfatal("open realmodemem: %r"); + + for(i=0; ix)]((uchar*)&u->x) +#define PUTUREG(x,y) pw[sizeof(u->x)]((uchar*)&u->x,y) + +static char* +realmode(Cpu *cpu, struct Ureg *u, void *r) +{ + char *err; + int i; + + cpu->reg[RDI] = GETUREG(di); + cpu->reg[RSI] = GETUREG(si); + cpu->reg[RBP] = GETUREG(bp); + cpu->reg[RBX] = GETUREG(bx); + cpu->reg[RDX] = GETUREG(dx); + cpu->reg[RCX] = GETUREG(cx); + cpu->reg[RAX] = GETUREG(ax); + + cpu->reg[RGS] = GETUREG(gs); + cpu->reg[RFS] = GETUREG(fs); + cpu->reg[RES] = GETUREG(es); + cpu->reg[RDS] = GETUREG(ds); + + cpu->reg[RFL] = GETUREG(flags); + + if(i = GETUREG(trap)){ + cpu->reg[RSS] = 0x0000; + cpu->reg[RSP] = 0x7C00; + cpu->reg[RCS] = (RMCODE>>4)&0xF000; + cpu->reg[RIP] = RMCODE & 0xFFFF; + memory[RMCODE] = 0xf4; /* HLT instruction */ + if(intr(cpu, i) < 0) + return Ebadtrap; + } else { + cpu->reg[RSS] = GETUREG(ss); + cpu->reg[RSP] = GETUREG(sp); + cpu->reg[RCS] = GETUREG(cs); + cpu->reg[RIP] = GETUREG(pc); + } + + startclock(); + for(;;){ + if(cputrace) + fprint(2, "%C\n", cpu); + switch(i = xec(cpu, (porttrace | cputrace) ? 1 : 100000)){ + case -1: + if(flushed(r)){ + err = Eintr; + break; + } + runclock(); + continue; + + /* normal interrupts */ + default: + if(intr(cpu, i) < 0){ + err = Ebadtrap; + break; + } + continue; + + /* pseudo-interrupts */ + case EHALT: + err = nil; + break; + case EIO: + err = Eio; + break; + case EMEM: + err = Emem; + break; + + /* processor traps */ + case EDIV0: + case EDEBUG: + case ENMI: + case EBRK: + case EINTO: + case EBOUND: + case EBADOP: + case ENOFPU: + case EDBLF: + case EFPUSEG: + case EBADTSS: + case ENP: + case ESTACK: + case EGPF: + case EPF: + PUTUREG(trap, i); + err = trapstr[i]; + break; + } + + break; + } + + if(err) + fprint(2, "%s\n%C\n", err, cpu); + + PUTUREG(di, cpu->reg[RDI]); + PUTUREG(si, cpu->reg[RSI]); + PUTUREG(bp, cpu->reg[RBP]); + PUTUREG(bx, cpu->reg[RBX]); + PUTUREG(dx, cpu->reg[RDX]); + PUTUREG(cx, cpu->reg[RCX]); + PUTUREG(ax, cpu->reg[RAX]); + + PUTUREG(gs, cpu->reg[RGS]); + PUTUREG(fs, cpu->reg[RFS]); + PUTUREG(es, cpu->reg[RES]); + PUTUREG(ds, cpu->reg[RDS]); + + PUTUREG(flags, cpu->reg[RFL]); + + PUTUREG(pc, cpu->reg[RIP]); + PUTUREG(cs, cpu->reg[RCS]); + PUTUREG(sp, cpu->reg[RSP]); + PUTUREG(ss, cpu->reg[RSS]); + + return err; +} + +enum { + Qroot, + Qcall, + Qmem, + Nqid, +}; + +static struct Qtab { + char *name; + int mode; + int type; + int length; +} qtab[Nqid] = { + "/", + DMDIR|0555, + QTDIR, + 0, + + "realmode", + 0666, + 0, + 0, + + "realmodemem", + 0666, + 0, + MEMSIZE, +}; + +static int +fillstat(ulong qid, Dir *d) +{ + struct Qtab *t; + + memset(d, 0, sizeof(Dir)); + d->uid = "realemu"; + d->gid = "realemu"; + d->muid = ""; + d->qid = (Qid){qid, 0, 0}; + d->atime = time(0); + t = qtab + qid; + d->name = t->name; + d->qid.type = t->type; + d->mode = t->mode; + d->length = t->length; + return 1; +} + +static void +fsattach(Req *r) +{ + char *spec; + + spec = r->ifcall.aname; + if(spec && spec[0]){ + respond(r, Ebadspec); + return; + } + r->fid->qid = (Qid){Qroot, 0, QTDIR}; + r->ofcall.qid = r->fid->qid; + respond(r, nil); +} + +static void +fsstat(Req *r) +{ + fillstat((ulong)r->fid->qid.path, &r->d); + r->d.name = estrdup9p(r->d.name); + r->d.uid = estrdup9p(r->d.uid); + r->d.gid = estrdup9p(r->d.gid); + r->d.muid = estrdup9p(r->d.muid); + respond(r, nil); +} + +static char* +fswalk1(Fid *fid, char *name, Qid *qid) +{ + int i; + ulong path; + + path = fid->qid.path; + switch(path){ + case Qroot: + if (strcmp(name, "..") == 0) { + *qid = (Qid){Qroot, 0, QTDIR}; + fid->qid = *qid; + return nil; + } + for(i = fid->qid.path; iqid = *qid; + return nil; + } + return Enonexist; + + default: + return Ewalk; + } +} + +static void +fsopen(Req *r) +{ + static int need[4] = { 4, 2, 6, 1 }; + struct Qtab *t; + int n; + + t = qtab + r->fid->qid.path; + n = need[r->ifcall.mode & 3]; + if((n & t->mode) != n) + respond(r, Eperm); + else + respond(r, nil); +} + +static int +readtopdir(Fid*, uchar *buf, long off, int cnt, int blen) +{ + int i, m, n; + long pos; + Dir d; + + n = 0; + pos = 0; + for (i = 1; i < Nqid; i++){ + fillstat(i, &d); + m = convD2M(&d, &buf[n], blen-n); + if(off <= pos){ + if(m <= BIT16SZ || m > cnt) + break; + n += m; + cnt -= m; + } + pos += m; + } + return n; +} + +static Channel *reqchan; + +static void +cpuproc(void *) +{ + static struct Ureg rmu; + ulong path; + vlong o; + ulong n; + char *p; + Req *r; + + threadsetname("cpuproc"); + + while(r = recvp(reqchan)){ + if(flushed(r)){ + respond(r, Eintr); + continue; + } + + path = r->fid->qid.path; + + p = r->ifcall.data; + n = r->ifcall.count; + o = r->ifcall.offset; + + switch(((int)r->ifcall.type<<8)|path){ + case (Tread<<8) | Qmem: + readbuf(r, memory, MEMSIZE); + respond(r, nil); + break; + + case (Tread<<8) | Qcall: + readbuf(r, &rmu, sizeof rmu); + respond(r, nil); + break; + + case (Twrite<<8) | Qmem: + if(o < 0 || o >= MEMSIZE || o+n > MEMSIZE){ + respond(r, Ebadoff); + break; + } + memmove(memory + o, p, n); + r->ofcall.count = n; + respond(r, nil); + break; + + case (Twrite<<8) | Qcall: + if(n != sizeof rmu){ + respond(r, Ebadureg); + break; + } + memmove(&rmu, p, n); + if(p = realmode(&cpu, &rmu, r)){ + respond(r, p); + break; + } + r->ofcall.count = n; + respond(r, nil); + break; + } + } +} + +static Channel *flushchan; + +static int +flushed(void *r) +{ + return nbrecvp(flushchan) == r; +} + +static void +fsflush(Req *r) +{ + nbsendp(flushchan, r->oldreq); + respond(r, nil); +} + +static void +dispatch(Req *r) +{ + if(!nbsendp(reqchan, r)) + respond(r, Ebusy); +} + +static void +fsread(Req *r) +{ + switch((ulong)r->fid->qid.path){ + case Qroot: + r->ofcall.count = readtopdir(r->fid, (void*)r->ofcall.data, r->ifcall.offset, + r->ifcall.count, r->ifcall.count); + respond(r, nil); + break; + default: + dispatch(r); + } +} + +static void +fsend(Srv*) +{ + threadexitsall(nil); +} + +static Srv fs = { + .attach= fsattach, + .walk1= fswalk1, + .open= fsopen, + .read= fsread, + .write= dispatch, + .stat= fsstat, + .flush= fsflush, + .end= fsend, +}; + +static void +usage(void) +{ + fprint(2, "usage: %s [-Dpt] [-s srvname] [-m mountpoint]\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + char *mnt = "/dev"; + char *srv = nil; + + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 'p': + porttrace = 1; + break; + case 't': + cputrace = 1; + break; + case 's': + srv = EARGF(usage()); + mnt = nil; + break; + case 'm': + mnt = EARGF(usage()); + break; + default: + usage(); + }ARGEND + + cpuinit(); + + reqchan = chancreate(sizeof(Req*), 8); + flushchan = chancreate(sizeof(Req*), 8); + procrfork(cpuproc, nil, 16*1024, RFNAMEG|RFNOTEG); + threadpostmountsrv(&fs, srv, mnt, MBEFORE); +} --- /sys/src/cmd/aux/realemu/mkfile Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/mkfile Sat Apr 30 22:24:00 2011 @@ -0,0 +1,19 @@ + +#include +#include "dat.h" +#include "fns.h" + +enum { + AC0 = 0, + AC1, + AC2, + Actl, + + Readback = 3, + + RBC0 = 1<<1, + RBC1 = 1<<2, + RBC2 = 1<<3, + RBlatchstatus = 1<<4, + RBlatchcount = 1<<5, + + AMlatchcount = 0, + AMloonly, + AMhionly, + AMlohi, + + OM0 = 0, + OM1, + OM2, + OM3, + OM4, + OM5, + OM2b, + OM3b, +}; + +static void +latchstatus(Pit *ch) +{ + if(ch->rlatched) + return; + ch->rlatch[0] = ch->bcd | ch->omode<<1 | ch->amode<<4 | ch->count0<<6 | ch->out<<7; + ch->rcount = 0; + ch->rlatched = 1; +} + +static void +latchcount(Pit *ch) +{ + ulong w; + + if(ch->rlatched) + return; + w = ch->count & 0xFFFF; + if(ch->bcd) + w = (w % 10) + ((w/10) % 10)<<4 + ((w/100) % 10)<<8 + ((w/1000) % 10)<<12; + ch->rlatch[0] = w & 0xFF; + ch->rlatch[1] = (w >> 8) & 0xFF; + ch->rcount = 0; + ch->rlatched = 1; + switch(ch->amode){ + case AMhionly: + ch->rcount++; + break; + case AMlohi: + ch->rlatched++; + break; + } +} + +static void +setcount(Pit *ch) +{ + ulong w; + + w = (ulong)ch->wlatch[0] | (ulong)ch->wlatch[1] << 8; + if(ch->bcd) + w = (w & 0xF) + 10*((w >> 4)&0xF) + 100*((w >> 8)&0xF) + 1000*((w >> 12)&0xF); + ch->count = w; + ch->count0 = 0; +} + +static int +deccount(Pit *ch, vlong *cycles) +{ + if(ch->count0){ + *cycles = 0; + return 0; + } else { + vlong passed, remain; + + passed = *cycles; + if(ch->count == 0){ + ch->count = ch->bcd ? 9999 : 0xFFFF; + passed--; + } + if(passed <= ch->count){ + remain = 0; + ch->count -= passed; + } else { + remain = passed - ch->count; + ch->count = 0; + } + *cycles = remain; + return ch->count == 0; + } +} + +void +setgate(Pit *ch, uchar gate) +{ + if(ch->gate == 0 && gate) + ch->gateraised = 1; + ch->gate = gate; +} + +static void +clockpit1(Pit *ch, vlong *cycles) +{ + switch(ch->omode){ + case OM0: /* Interrupt On Terminal Count */ + if(ch->count0){ + setcount(ch); + ch->out = 0; + Next: + --*cycles; + return; + } + if(ch->gate && deccount(ch, cycles)){ + ch->out = 1; + return; + } + break; + + case OM1: /* Hardware Re-triggerable One-shot */ + if(ch->gateraised){ + ch->gateraised = 0; + setcount(ch); + ch->out = 0; + goto Next; + } + if(deccount(ch, cycles) && ch->out == 0){ + ch->out = 1; + return; + } + break; + + case OM2: /* Rate Generator */ + case OM2b: + ch->out = 1; + if(ch->count0){ + setcount(ch); + goto Next; + } + if(ch->gate == 0) + break; + if(ch->gateraised){ + ch->gateraised = 0; + setcount(ch); + goto Next; + } + if(deccount(ch, cycles)){ + setcount(ch); + ch->out = 0; + return; + } + break; + + case OM3: /* Square Wave Generator */ + case OM3b: + if(ch->count0){ + setcount(ch); + goto Next; + } + if(ch->gate == 0) + break; + if(ch->gateraised){ + ch->gateraised = 0; + setcount(ch); + goto Next; + } + if(deccount(ch, cycles)){ + setcount(ch); + ch->out ^= 1; + return; + } + break; + + case OM4: /* Software Triggered Strobe */ + ch->out = 1; + if(ch->count0){ + setcount(ch); + goto Next; + } + if(ch->gate && deccount(ch, cycles)){ + ch->out = 0; + return; + } + break; + + case OM5: /* Hardware Triggered Strobe */ + ch->out = 1; + if(ch->gateraised){ + ch->gateraised = 0; + setcount(ch); + goto Next; + } + if(deccount(ch, cycles)){ + ch->out = 0; + return; + } + break; + } + *cycles = 0; +} + +void +clockpit(Pit *pit, vlong cycles) +{ + Pit *ch; + int i; + + if(cycles <= 0) + return; + for(i = 0; iwlatched){ + vlong c; + + switch(ch->omode){ + case OM3: + case OM3b: + c = cycles * 2; + break; + default: + c = cycles; + } + while(c > 0) + clockpit1(ch, &c); + } + ch->gateraised = 0; + } +} + +uchar +rpit(Pit *pit, uchar addr) +{ + Pit *ch; + uchar data; + + if(addr >= Actl) + return 0; + ch = pit + addr; + if(ch->rlatched){ + data = ch->rlatch[ch->rcount & 1]; + ch->rlatched--; + } else { + data = 0; + switch(ch->amode){ + case AMloonly: + data = ch->count & 0xFF; + break; + case AMhionly: + data = (ch->count >> 8) & 0xFF; + break; + case AMlohi: + data = (ch->count >> ((ch->rcount & 1)<<3)) & 0xFF; + break; + } + } + ch->rcount++; + if(0) fprint(2, "rpit %p: %.2x %.2x\n", pit, (int)addr, (int)data); + return data; +} + +void +wpit(Pit *pit, uchar addr, uchar data) +{ + Pit *ch; + + if(0) fprint(2, "wpit %p: %.2x %.2x\n", pit, (int)addr, (int)data); + if(addr > Actl) + return; + if(addr == Actl){ + uchar sc, amode, omode, bcd; + + bcd = (data & 1); + omode = (data >> 1) & 7; + amode = (data >> 4) & 3; + sc = (data >> 6) & 3; + + if(sc == Readback){ + ch = nil; + for(;;){ + if(data & RBC0){ + ch = pit; + break; + } + if(data & RBC1){ + ch = pit + 1; + break; + } + if(data & RBC2){ + ch = pit + 2; + break; + } + break; + } + if(ch == nil) + return; + if((data & RBlatchcount) == 0) + latchcount(ch); + if((data & RBlatchstatus) == 0) + latchstatus(ch); + return; + } + + ch = pit + sc; + if(amode == AMlatchcount){ + latchcount(ch); + return; + } + ch->bcd = bcd; + + ch->amode = amode; + ch->omode = omode; + + ch->rlatched = 0; + ch->rcount = 0; + ch->rlatch[0] = 0; + ch->rlatch[1] = 0; + + ch->wlatched = 0; + ch->wcount = 0; + ch->wlatch[0] = 0; + ch->wlatch[1] = 0; + + ch->count0 = 1; + ch->out = !!omode; + return; + } + + ch = pit + addr; + switch(ch->amode){ + case AMloonly: + case AMhionly: + ch->wlatch[ch->amode - AMloonly] = data; + ch->wcount++; + break; + case AMlohi: + ch->wlatch[ch->wcount++ & 1] = data; + if(ch->wcount < 2) + return; + break; + } + ch->wlatched = ch->wcount; + ch->wcount = 0; + ch->count0 = 1; +} --- /sys/src/cmd/aux/realemu/vgalist Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/vgalist Sat Apr 30 22:21:37 2011 @@ -0,0 +1,9 @@ +#vid did bios wired product name +100b 0030 5.30 STI NSC Geode GX2 +5533 8c2e 1.0 - T23 / S3 savage +1002 791e 01.00 - ATI RS690 +10de 002c B1 STI NVidia RivaTNT +15ad 0405 2.0 - VMware +- - 1.26 - Bochs +102b 0519 00 STI Matrox MILLENNIUM +5333 8901 Rev E - S3 Trio64V2/DX/GX --- /sys/src/cmd/aux/realemu/xec.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/aux/realemu/xec.c Tue Sep 11 23:55:42 2012 @@ -0,0 +1,1331 @@ +#include +#include +#include "dat.h" +#include "fns.h" + +#define sign(s) (1UL<<((s)-1)) +#define mask(s) (sign(s)|(sign(s)-1)) + +int cputrace; + +static void +push(Iarg *sp, Iarg *a) +{ + 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); +} + +static void +pop(Iarg *sp, Iarg *a) +{ + Iarg *p; + + p = amem(sp->cpu, a->len, RSS, ar(sp)); + aw(a, ar(p)); + aw(sp, p->off + a->len); +} + +static void +jump(Iarg *to) +{ + 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; + } +} + +static void +opcall(Cpu *cpu, Inst *i) +{ + 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); +} + +static void +opint(Cpu *cpu, Inst *i) +{ + cpu->trap = ar(i->a1); + longjmp(cpu->jmp, 1); +} + +static void +opiret(Cpu *cpu, Inst *i) +{ + 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)); +} + +static void +opret(Cpu *cpu, Inst *i) +{ + Iarg *sp; + ulong c; + + sp = areg(cpu, cpu->slen, RSP); + pop(sp, areg(cpu, i->olen, RIP)); + if(c = ar(i->a1)) + aw(sp, ar(sp) + c); +} + +static void +opretf(Cpu *cpu, Inst *i) +{ + Iarg *sp; + ulong 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); +} + +static void +openter(Cpu *cpu, Inst *i) +{ + Iarg *sp, *bp; + ulong 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; jolen*j); + push(sp, bp); + } + push(sp, acon(cpu, i->olen, nframe)); + } + aw(bp, nframe); + aw(sp, nframe - ar(i->a1)); +} + +static void +opleave(Cpu *cpu, Inst *i) +{ + Iarg *sp; + + sp = areg(cpu, cpu->slen, RSP); + aw(sp, ar(areg(cpu, cpu->slen, RBP))); + pop(sp, areg(cpu, i->olen, RBP)); +} + +static void +oppush(Cpu *cpu, Inst *i) +{ + 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); +} + +static void +oppop(Cpu *cpu, Inst *i) +{ + pop(areg(cpu, cpu->slen, RSP), i->a1); +} + +static void +oppusha(Cpu *cpu, Inst *i) +{ + 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)); +} + +static void +oppopa(Cpu *cpu, Inst *i) +{ + 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)); +} + +static void +oppushf(Cpu *cpu, Inst *i) +{ + push(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL)); +} + +static void +oppopf(Cpu *cpu, Inst *i) +{ + ulong *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)); +} + +static void +oplahf(Cpu *cpu, Inst *i) +{ + aw(i->a1, cpu->reg[RFL]); +} + +static void +opsahf(Cpu *cpu, Inst *i) +{ + enum { MASK = SF|ZF|AF|PF|CF }; + ulong *f; + + f = cpu->reg + RFL; + *f &= ~MASK; + *f |= (ar(i->a1) & MASK); +} + +static void +opcli(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] &= ~IF; +} + +static void +opsti(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] |= IF; +} + +static void +opcld(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] &= ~DF; +} + +static void +opstd(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] |= DF; +} + +static void +opclc(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] &= ~CF; +} + +static void +opstc(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] |= CF; +} + +static void +opcmc(Cpu *cpu, Inst *) +{ + cpu->reg[RFL] ^= CF; +} + +static void +parity(ulong *f, ulong r) +{ + static ulong tab[8] = { + 0x96696996, + 0x69969669, + 0x69969669, + 0x96696996, + 0x69969669, + 0x96696996, + 0x96696996, + 0x69969669, + }; + r &= 0xFF; + if((tab[r/32] >> (r%32)) & 1) + *f &= ~PF; + else + *f |= PF; +} + +static ulong +test(ulong *f, long r, int s) +{ + *f &= ~(CF|SF|ZF|OF|PF); + r &= mask(s); + if(r == 0) + *f |= ZF; + if(r & sign(s)) + *f |= SF; + parity(f, r); + return r; +} + +static void +opshl(Cpu *cpu, Inst *i) +{ + ulong *f, r, a, h; + int s, n; + + if((n = ar(i->a2) & 31) == 0) + return; + s = i->a1->len*8; + a = ar(i->a1); + f = cpu->reg + RFL; + r = test(f, a<a1, r); + if((a<<(n-1)) & h) + *f |= CF; + if(n == 1 && ((a^r) & h)) + *f |= OF; +} + +static void +opshr(Cpu *cpu, Inst *i) +{ + ulong *f, a; + int s, n; + + if((n = ar(i->a2) & 31) == 0) + 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; +} + +static void +opsar(Cpu *cpu, Inst *i) +{ + ulong *f; + long a; + int n; + + if((n = ar(i->a2) & 31) == 0) + 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; +} + +static void +opshld(Cpu *cpu, Inst *i) +{ + ulong *f, a; + int s, n; + + if((n = ar(i->a3) & 31) == 0) + return; + s = i->a1->len*8; + a = ar(i->a1); + f = cpu->reg + RFL; + aw(i->a1, test(f, (a<a2)>>(s-n)), s)); + if((a<<(n-1)) & sign(s)) + *f |= CF; +} + +static void +opshrd(Cpu *cpu, Inst *i) +{ + ulong *f, a; + int s, n; + + if((n = ar(i->a3) & 31) == 0) + 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; +} + + +static void +oprcl(Cpu *cpu, Inst *i) +{ + ulong *f, a, r; + int s, n; + + s = i->a1->len*8; + n = ar(i->a2) % (s+1); + a = ar(i->a1); + r = (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); +} + +static void +oprcr(Cpu *cpu, Inst *i) +{ + ulong *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); +} + +static void +oprol(Cpu *cpu, Inst *i) +{ + ulong *f, a, r; + int s, n; + + s = i->a1->len*8; + n = ar(i->a2) & (s-1); + a = ar(i->a1); + r = (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); +} + +static void +opror(Cpu *cpu, Inst *i) +{ + ulong *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); +} + +static void +opbittest(Cpu *cpu, Inst *i) +{ + ulong 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<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; + } +} + +static void +opbitscan(Cpu *cpu, Inst *i) +{ + ulong a; + + if((a = ar(i->a2)) == 0) + cpu->reg[RFL] |= ZF; + else { + int j; + + if(i->op == OBSF){ + for(j = 0; (a & (1<a2->len*8-1; (a & (1<a1, j); + cpu->reg[RFL] &= ~ZF; + } +} + +static void +opand(Cpu *cpu, Inst *i) +{ + aw(i->a1, test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8)); +} + +static void +opor(Cpu *cpu, Inst *i) +{ + aw(i->a1, test(cpu->reg + RFL, ars(i->a1) | ars(i->a2), i->a1->len*8)); +} + +static void +opxor(Cpu *cpu, Inst *i) +{ + aw(i->a1, test(cpu->reg + RFL, ars(i->a1) ^ ars(i->a2), i->a1->len*8)); +} + +static void +opnot(Cpu *, Inst *i) +{ + aw(i->a1, ~ar(i->a1)); +} + +static void +optest(Cpu *cpu, Inst *i) +{ + test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8); +} + +static ulong +add(ulong *f, long a, long b, int c, int s) +{ + ulong 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); + return r; +} + +static ulong +sub(ulong *f, long a, long b, int c, int s) +{ + ulong 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); + return r; +} + +static void +opadd(Cpu *cpu, Inst *i) +{ + aw(i->a1, add(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8)); +} + +static void +opadc(Cpu *cpu, Inst *i) +{ + ulong *f = cpu->reg + RFL; + + aw(i->a1, add(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8)); +} + +static void +opsub(Cpu *cpu, Inst *i) +{ + aw(i->a1, sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8)); +} + +static void +opsbb(Cpu *cpu, Inst *i) +{ + ulong *f = cpu->reg + RFL; + + aw(i->a1, sub(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8)); +} + +static void +opneg(Cpu *cpu, Inst *i) +{ + aw(i->a1, sub(cpu->reg + RFL, 0, ars(i->a1), 0, i->a1->len*8)); +} + +static void +opcmp(Cpu *cpu, Inst *i) +{ + sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8); +} + +static void +opinc(Cpu *cpu, Inst *i) +{ + ulong *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); +} + +static void +opdec(Cpu *cpu, Inst *i) +{ + ulong *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); +} + +static void +opmul(Cpu *cpu, Inst *i) +{ + Iarg *la, *ha; + ulong l, h, m; + uvlong 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); +} + +static void +opimul(Cpu *cpu, Inst *i) +{ + ulong l, h, m, n; + vlong 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 > (vlong)n-1) || (r < -(vlong)n)) + cpu->reg[RFL] |= (CF|OF); + else + cpu->reg[RFL] &= ~(CF|OF); +} + +static void +opdiv(Cpu *cpu, Inst *i) +{ + Iarg *qa, *ra; + uvlong n, q; + ulong 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 = (uvlong)ar(ra)< m) + trap(cpu, EGPF); + r = n%d; + aw(ra, r); + aw(qa, q); +} + + +static int +cctrue(Cpu *cpu, Inst *i) +{ + enum { SO = 1<<16, /* pseudo-flag SF != OF */ }; + static ulong 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 */ + }; + ulong f, t; + uchar c; + + c = i->code; + switch(c){ + case 0xE3: /* JCXZ */ + return ar(areg(cpu, i->alen, RCX)) == 0; + case 0xEB: /* JMP */ + case 0xE9: + case 0xEA: + case 0xFF: + return 1; + default: + f = cpu->reg[RFL]; + if(((f&SF)!=0) ^ ((f&OF)!=0)) + f |= SO; + t = test[(c>>1)&7]; + return ((t&f) != 0) ^ (c&1); + } +} + +static void +opjump(Cpu *cpu, Inst *i) +{ + if(cctrue(cpu, i)) + jump(i->a1); +} + +static void +opset(Cpu *cpu, Inst *i) +{ + aw(i->a1, cctrue(cpu, i)); +} + +static void +oploop(Cpu *cpu, Inst *i) +{ + Iarg *cx; + ulong c; + + switch(i->op){ + default: + abort(); + case OLOOPNZ: + if(cpu->reg[RFL] & ZF) + return; + break; + case OLOOPZ: + if((cpu->reg[RFL] & ZF) == 0) + return; + break; + case OLOOP: + break; + } + cx = areg(cpu, i->alen, RCX); + c = ar(cx) - 1; + aw(cx, c); + if(c) + jump(i->a1); +} + +static void +oplea(Cpu *, Inst *i) +{ + aw(i->a1, i->a2->off); +} + +static void +opmov(Cpu *, Inst *i) +{ + aw(i->a1, ar(i->a2)); +} + +static void +opcbw(Cpu *cpu, Inst *i) +{ + aw(areg(cpu, i->olen, RAX), ars(areg(cpu, i->olen>>1, RAX))); +} + +static void +opcwd(Cpu *cpu, Inst *i) +{ + aw(areg(cpu, i->olen, RDX), ars(areg(cpu, i->olen, RAX))>>(i->olen*8-1)); +} + +static void +opmovsx(Cpu *, Inst *i) +{ + aw(i->a1, ars(i->a2)); +} + +static void +opxchg(Cpu *, Inst *i) +{ + ulong x; + + x = ar(i->a1); + aw(i->a1, ar(i->a2)); + aw(i->a2, x); +} + +static void +oplfp(Cpu *, Inst *i) +{ + Iarg *p; + + p = afar(i->a3, i->olen, i->olen); + aw(i->a1, p->seg); + aw(i->a2, p->off); +} + +static void +opbound(Cpu *cpu, Inst *i) +{ + ulong p, s, e; + + p = ar(i->a1); + s = ar(i->a2); + e = ar(i->a3); + if((p < s) || (p >= e)) + trap(cpu, EBOUND); +} + +static void +opxlat(Cpu *cpu, Inst *i) +{ + aw(i->a1, ar(amem(cpu, i->a1->len, i->sreg, ar(areg(cpu, i->alen, i->a2->reg)) + ar(i->a1)))); +} + +static void +opcpuid(Cpu *cpu, Inst *) +{ + static struct { + ulong level; + + ulong ax; + ulong bx; + ulong cx; + ulong 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; ireg[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; + return; + } + } + trap(cpu, EBADOP); +} + +static void +opmovs(Cpu *cpu, Inst *i) +{ + Iarg *cx, *d, *s; + ulong 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); +} + +static void +oplods(Cpu *cpu, Inst *i) +{ + Iarg *cx, *s; + ulong 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); +} + +static void +opstos(Cpu *cpu, Inst *i) +{ + Iarg *cx, *d; + ulong 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); +} + +static int +repcond(ulong *f, int rep) +{ + if(rep == OREPNE) + return (*f & ZF) == 0; + return !rep || (*f & ZF) != 0; +} + +static void +opscas(Cpu *cpu, Inst *i) +{ + Iarg *cx, *d; + ulong *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); +} + +static void +opcmps(Cpu *cpu, Inst *i) +{ + Iarg *cx, *s, *d; + ulong *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); +} + +static void +opin(Cpu *cpu, Inst *i) +{ + Bus *io; + + io = cpu->port; + aw(i->a1, io->r(io->aux, ar(i->a2) & 0xFFFF, i->a1->len)); +} + +static void +opout(Cpu *cpu, Inst *i) +{ + Bus *io; + + io = cpu->port; + io->w(io->aux, ar(i->a1) & 0xFFFF, ar(i->a2), i->a2->len); +} + +static void +opnop(Cpu *, Inst *) +{ +} + +static void +ophlt(Cpu *cpu, Inst *) +{ + trap(cpu, EHALT); +} + +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, + + [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) +{ + cpu->reg[RIP] = cpu->oldip; + cpu->trap = e; + longjmp(cpu->jmp, 1); +} + +int +intr(Cpu *cpu, int v) +{ + Iarg *sp, *ip, *cs, *iv; + + if(v < 0 || v > 0xff || cpu->olen != 2) + 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); + return 0; +} + +int +xec(Cpu *cpu, int n) +{ + if(setjmp(cpu->jmp)) + 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); + } + return n; +}