Plan 9 from Bell Labs’s /usr/web/sources/contrib/yk/dist/9legacy/applied/realemu.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


diff -Nru /sys/src/cmd/aux/realemu/arg.c /sys/src/cmd/aux/realemu/arg.c
--- /sys/src/cmd/aux/realemu/arg.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/arg.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,163 @@
+#include <u.h>
+#include <libc.h>
+#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;
+	}
+}
diff -Nru /sys/src/cmd/aux/realemu/dat.h /sys/src/cmd/aux/realemu/dat.h
--- /sys/src/cmd/aux/realemu/dat.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/dat.h	Fri Feb 19 00:00:00 2016
@@ -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,
+};
diff -Nru /sys/src/cmd/aux/realemu/decode.c /sys/src/cmd/aux/realemu/decode.c
--- /sys/src/cmd/aux/realemu/decode.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/decode.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,625 @@
+#include <u.h>
+#include <libc.h>
+#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;
+	i->a1 = i->a2 = i->a3 = nil;
+
+	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;
+
+	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;
+}
diff -Nru /sys/src/cmd/aux/realemu/fmt.c /sys/src/cmd/aux/realemu/fmt.c
--- /sys/src/cmd/aux/realemu/fmt.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/fmt.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,385 @@
+#include <u.h>
+#include <libc.h>
+#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;
+}
diff -Nru /sys/src/cmd/aux/realemu/fns.h /sys/src/cmd/aux/realemu/fns.h
--- /sys/src/cmd/aux/realemu/fns.h	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/fns.h	Fri Feb 19 00:00:00 2016
@@ -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);
diff -Nru /sys/src/cmd/aux/realemu/loadcom.c /sys/src/cmd/aux/realemu/loadcom.c
--- /sys/src/cmd/aux/realemu/loadcom.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/loadcom.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,43 @@
+#include <u.h>
+#include <libc.h>
+
+#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");
+}
diff -Nru /sys/src/cmd/aux/realemu/main.c /sys/src/cmd/aux/realemu/main.c
--- /sys/src/cmd/aux/realemu/main.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/main.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,796 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+/* for fs */
+#include <auth.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+#include "/386/include/ureg.h"
+
+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 uchar rtcaddr;
+
+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 0x70:	/* RTC addr */
+		w = rtcaddr;
+		break;
+	case 0x71:	/* RTC data */
+		w = 0xFF;
+		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 0x70:	/* RTC addr */
+		rtcaddr = w & 0xFF;
+		break;
+	case 0x71:	/* RTC data */
+		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, wmem,	/* 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; i<nelem(memio); i++){
+		ulong off;
+
+		if(memio[i].r != rmem)
+			continue;
+
+		off = (ulong)i << 16;
+		seek(realmemfd, off, 0);
+		if(readn(realmemfd, memory + off, 0x10000) != 0x10000)
+			sysfatal("read real mem %lux: %r\n", off);
+	}
+
+	cpu.ic = 0;
+	cpu.mem = memio;
+	cpu.port = &portio;
+	cpu.alen = cpu.olen = cpu.slen = 2;
+}
+
+static char Ebusy[] = "device is busy";
+static char Eintr[] = "interrupted";
+static char Eperm[] = "permission denied";
+static char Eio[] = "i/o error";
+static char Emem[] = "bad memory access";
+static char Enonexist[] = "file does not exist";
+static char Ebadspec[] = "bad attach specifier";
+static char Ewalk[] = "walk in non directory";
+static char Ebadureg[] = "write a Ureg";
+static char Ebadoff[] = "invalid offset";
+static char Ebadtrap[] = "bad trap";
+
+static char *trapstr[] = {
+	[EDIV0] "division by zero",
+	[EDEBUG] "debug exception",
+	[ENMI] "not maskable interrupt",
+	[EBRK] "breakpoint",
+	[EINTO] "into overflow",
+	[EBOUND] "bounds check",
+	[EBADOP] "bad opcode",
+	[ENOFPU] "no fpu installed",
+	[EDBLF] "double fault",
+	[EFPUSEG] "fpu segment overflow",
+	[EBADTSS] "invalid task state segment",
+	[ENP] "segment not present",
+	[ESTACK] "stack fault",
+	[EGPF] "general protection fault",
+	[EPF] "page fault",
+};
+
+static int flushed(void *);
+
+#define GETUREG(x)	gw[sizeof(u->x)]((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; i<Nqid; i++){
+			if(strcmp(name, qtab[i].name) != 0)
+				continue;
+			*qid = (Qid){i, 0, 0};
+			fid->qid = *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, "usgae:\t%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);
+}
diff -Nru /sys/src/cmd/aux/realemu/mkfile /sys/src/cmd/aux/realemu/mkfile
--- /sys/src/cmd/aux/realemu/mkfile	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/mkfile	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,9 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin/aux
+
+TARG=realemu
+OFILES=decode.$O arg.$O xec.$O fmt.$O pit.$O main.$O
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
diff -Nru /sys/src/cmd/aux/realemu/notes /sys/src/cmd/aux/realemu/notes
--- /sys/src/cmd/aux/realemu/notes	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/notes	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,22 @@
+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-
diff -Nru /sys/src/cmd/aux/realemu/pit.c /sys/src/cmd/aux/realemu/pit.c
--- /sys/src/cmd/aux/realemu/pit.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/pit.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,357 @@
+#include <u.h>
+#include <libc.h>
+#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; i<Actl; i++){
+		ch = pit + i;
+		if(ch->wlatched){
+			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;
+}
diff -Nru /sys/src/cmd/aux/realemu/vgalist /sys/src/cmd/aux/realemu/vgalist
--- /sys/src/cmd/aux/realemu/vgalist	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/vgalist	Fri Feb 19 00:00:00 2016
@@ -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
diff -Nru /sys/src/cmd/aux/realemu/xec.c /sys/src/cmd/aux/realemu/xec.c
--- /sys/src/cmd/aux/realemu/xec.c	Thu Jan  1 00:00:00 1970
+++ /sys/src/cmd/aux/realemu/xec.c	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,1363 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+#define sign(s)	(1UL<<((s)-1))
+#define mask(s) (sign(s)|(sign(s)-1))
+
+static void
+push(Iarg *sp, Iarg *a)
+{
+	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; j<n; j++){
+			aw(bp, oframe - i->olen*j);
+			push(sp, bp);
+		}
+		push(sp, acon(cpu, i->olen, nframe));
+	}
+	aw(bp, nframe);
+	aw(sp, nframe - ar(i->a1));
+}
+
+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<<n, s);
+	h = sign(s);
+	aw(i->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<<n)|(ar(i->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<<n) | ((a>>(s-n))>>1);
+	f = cpu->reg + RFL;
+	if(*f & CF)
+		r |= sign(n);
+	aw(i->a1, r);
+	*f &= ~(CF|OF);
+	if((a>>(s-n)) & 1)
+		*f |= CF;
+	if((a ^ r) & sign(s))
+		*f |= OF;
+	parity(f, r);
+}
+
+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<<n) | (a>>(s-n));
+	f = cpu->reg + RFL;
+	aw(i->a1, r);
+	*f &= ~(CF|OF);
+	if(r & 1)
+		*f |= CF;
+	if((a ^ r) & sign(s))
+		*f |= OF;
+	parity(f, r);
+}
+
+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<<n;
+	if(a & m)
+		cpu->reg[RFL] |= CF;			
+	else
+		cpu->reg[RFL] &= ~CF;
+	switch(i->op){
+	case OBT:
+		break;
+	case OBTS:
+		aw(x, a | m);
+		break;
+	case OBTR:
+		aw(x, a & ~m);
+		break;
+	case OBTC:
+		aw(x, a ^ m);
+		break;
+	}
+}
+
+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<<j)) == 0; j++)
+				;
+		} else {
+			for(j = i->a2->len*8-1; (a & (1<<j)) == 0; j--)
+				;
+		}
+		aw(i->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)<<s | (uvlong)ar(qa);
+	q = n/d;
+	if(q > m)
+		trap(cpu, EDIV0);
+	r = n%d;
+	aw(ra, r);
+	aw(qa, q);
+}
+
+static void
+opidiv(Cpu *cpu, Inst *i)
+{
+	Iarg *qa, *ra;
+	vlong n, q, min, max;
+	long r, d;
+	int s;
+
+	s = i->a1->len*8;
+	d = ars(i->a1);
+	if(d == 0)
+		trap(cpu, EDIV0);
+	if(s == 8){
+		qa = areg(cpu, 1, RAX);
+		ra = adup(qa);
+		ra->tag |= TH;
+	} else {
+		qa = areg(cpu, i->olen, RAX);
+		ra = areg(cpu, i->olen, RDX);
+	}
+	n = (vlong)ars(ra)<<s | (uvlong)ars(qa);
+	q = n/d;
+	r = n%d;
+
+	max = sign(s)-1;
+	min = ~max;
+
+	if(q > max || q < min)
+		trap(cpu, EDIV0);
+
+	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; i<nelem(tab); i++){
+		if(tab[i].level == cpu->reg[RAX]){
+			cpu->reg[RAX] = tab[i].ax;
+			cpu->reg[RBX] = tab[i].bx;
+			cpu->reg[RCX] = tab[i].cx;
+			cpu->reg[RDX] = tab[i].dx;
+			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 (*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,
+	[OIDIV] = opidiv,
+
+	[OLEA] = oplea,
+	[OMOV] = opmov,
+	[OCBW] = opcbw,
+	[OCWD] = opcwd,
+	[OMOVZX] = opmov,
+	[OMOVSX] = opmovsx,
+	[OXCHG] = opxchg,
+	[OLFP] = oplfp,
+	[OBOUND] = opbound,
+	[OXLAT] = opxlat,
+
+	[OCPUID] = opcpuid,
+
+	[OMOVS] = opmovs,
+	[OLODS] = oplods,
+	[OSTOS] = opstos,
+	[OSCAS] = opscas,
+	[OCMPS] = opcmps,
+
+	[OIN] = opin,
+	[OOUT] = opout,
+
+	[ONOP] = opnop,
+	[OHLT] = ophlt,
+};
+
+void
+trap(Cpu *cpu, int e)
+{
+	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;
+}
--- /n/sources/plan9/sys/src/cmd/aux/mkfile	Thu Aug 16 22:50:45 2012
+++ /sys/src/cmd/aux/mkfile	Fri Feb 19 00:00:00 2016
@@ -52,7 +52,8 @@
 	flashfs\
 	gps\
 	na\
-	vga
+	vga\
+	realemu
 
 all:V:	$DIRS
 
--- /sys/man/8/realemu	Fri Feb 19 21:15:30 2016
+++ /sys/man/8/realemu	Fri Feb 19 00:00:00 2016
@@ -0,0 +1,108 @@
+.TH REALEMU 8
+.SH NAME
+realemu \- software emulation of /dev/realmode
+.SH SYNOPSIS
+.B aux/realemu
+[
+.B -Dpt
+] [
+.B -s
+.I srvname
+] [
+.B -m
+.I mountpoint
+]
+.SH DESCRIPTION
+.PP
+Originally, kernel provided 
+.B /dev/realmode
+files with the
+.IR arch (3)
+device to access and call the
+.SM BIOS.
+.PP
+Interrupts had to be disabled and the processor was switched in the
+legacy 16-bit
+.SM realmode
+with memory protection disabled to execute
+.SM BIOS
+code.
+.PP
+This is problematic in case the
+.SM BIOS
+reprograms hardware currently
+used by the operating system or when it reenables interrupts or just
+crashes. This will freeze or reboot the machine with no way to
+recover or diagnose the problem.
+.PP
+To avoid this,
+.I realemu
+is used to emulate the execution of the
+.SM BIOS
+routines by interpreting the machine instructions and intercepting
+dangerous actions that would compromise the systems stability.
+.PP
+Running
+.I realemu
+with no arguments, it mounts itself before
+.B /dev
+and
+replaces the original
+.B /dev/realmode
+file in the current namespace.
+.PP
+Then programs like
+.IR vga (8)
+can use it to make their
+.SM BIOS
+calls.
+.PP
+The
+.B D
+flag will enable debug messages for 9P.  The
+.B p
+and
+.B t
+flags
+control tracing of i/o port access and cpu instructions to
+stderr (fd 2).
+.PP
+When a
+.I srvname
+is given with the
+.B s
+argument, the default
+.I mountpoint
+is ignored and a
+.SM 9P
+channel is created in
+.B /srv
+that can be used to mount
+the filesystem from another namespace. If a
+.I mountpoint
+is given before
+the
+.I srvname
+argument then it is ignored, otherwise it will be used.
+.SH EXAMPLES
+The
+.I realemu
+process is only needed when accessing
+.B /dev/realmode.
+To invoke a subshell so that
+.I realemu
+exits normally after
+.B aux/vga
+completes:
+.IP
+.EX
+% @{rfork n; aux/realemu; aux/vga -m vesa -l $vgasize}
+.EE
+.SH SOURCE
+.B /sys/src/cmd/aux/realemu
+.SH "SEE ALSO"
+.IR vga (8),
+.IR arch (3)
+.SH HISTORY
+.I Realemu
+first appeared in 9front (April, 2011).

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].