Plan 9 from Bell Labs’s /usr/web/sources/contrib/rsc/8i/decode.c

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


#include <u.h>
#include <libc.h>
#include "8i.h"

typedef struct Optab Optab;
struct Optab {
	uchar op;
	uchar arg1;
	uchar arg2;
	uchar arg3;
};

static uchar needmodrm[NAMODE] = {
[AEb] 1,
[AEv] 1,
[AGb] 1,
[AGv] 1,
[AM]  1,
[AMp] 1,
[ASw] 1,
};

static uchar small[NAMODE] = {
[ANONE]	1,
[AEb] 1,
[AGb] 1,
[AOb] 1,
[AXb] 1,
[AYb] 1,
[AIb] 1,
[AAL] 1,
[ABL] 1,
[ACL] 1,
[ADL] 1,
[AAH] 1,
[ABH] 1,
[ACH] 1,
[ADH] 1,
};

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,  AEv, AIc}, {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}, {OPOP,  AEv,    },
//90
  {ONOP,          }, {OXCHG, AAX, ACX}, {OXCHG, AAX, ADX}, {OXCHG, AAX, ABX},
  {OXCHG, AAX, ASP}, {OXCHG, AAX, ABP}, {OXCHG, AAX, ASI}, {OXCHG, AAX, ADI},
  {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, AXb, AYb}, {OMOVS, AXv, AYv}, {OCMPS, AXb, AYb}, {OCMPS, AXv, AYv},
  {OTEST, AAL, AIb}, {OTEST, AAX, AIv}, {OSTOS, AYb, AAL}, {OSTOS, AYv, AAX},
  {OLODS, AAL, AXb}, {OLODS, AAX, AXv}, {OSCAS, AAL, AYb}, {OSCAS, AAX, AYv},
//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},{OMOV,  AEb, AIb}, {OMOV,  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,ACX}, {OLOOPZ,AJb, ACX}, {OLOOP, AJb, ACX}, {OJUMP, AJb, ACX},
  {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,    }, {OBAD,          }, {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},{OBAD,          },
  {OLFP,AFS,AGv,AMp},{OLFP,AGS,AGv,AMp},{OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//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,  AEp    },
  {OJUMP, AEv,    }, {OJUMP, AEp,    }, {OPUSH,  AEv,   }, {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,
};

static void crackarg(Cpu*, Inst*, Iarg*, Wordop*);
static void crackmodrm(Cpu*, Inst*, Wordop*);
void
nextinst(Cpu *cpu, Inst *inst)
{
	Optab *gtab, tab, tab2;
	Wordop *wop;

	memset(inst, 0, sizeof *inst);
	inst->epc = cpu->pc;
	inst->spc = cpu->pc;
	inst->addrsize = cpu->addrsize;
	inst->opsize = cpu->opsize;

	/* loop through prefixes */
	for(;;){
		inst->i = wop8.fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc++);
		tab = optab[inst->i];
		switch(tab.op){
		case OOSIZE:
			inst->opsize = 48 - cpu->opsize;
			continue;
		case OASIZE:
			inst->addrsize = 48 - cpu->addrsize;
			continue;
		case OREPE:
		case OREPNE:
			inst->repeat = tab.op;
			continue;
		case OSEG:
			inst->sreg = "ECSD"[tab.arg1-AES];
			inst->seg = wop16.rreg(cpu, tab.arg1-AES+RES, 0);
			continue;
		}
		break;
	}

	if(inst->opsize == 16)
		wop = &wop16;
	else
		wop = &wop32;

	/* check 0F */
	if(tab.op == O0F){
		inst->i = wop8.fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc++);
		tab = optab0F[inst->i];
	}

	/* check instruction group information */
	if(gtab = optabgp[tab.op]){
		crackmodrm(cpu, inst, wop);
		inst->havemodrm = 1;
		tab2 = gtab[inst->rop];
		tab.op = tab2.op;
		if(tab2.arg1)
			tab.arg1 = tab2.arg1;
		if(tab2.arg2)
			tab.arg2 = tab2.arg2;
		if(tab2.arg3)
			tab.arg3 = tab2.arg3;
	}

	/* fetch modrm if necessary */
	if(!inst->havemodrm && (needmodrm[tab.arg1]||needmodrm[tab.arg2]||needmodrm[tab.arg3]))
		crackmodrm(cpu, inst, wop);

	if(inst->sreg == 0){
		inst->sreg = 'D';
		inst->seg = wop16.rreg(cpu, RDS, 0);
	}
	/* cobble together arguments */
	inst->op = tab.op;
	inst->arg1.atype = tab.arg1;
	inst->arg2.atype = tab.arg2;
	inst->arg3.atype = tab.arg3;
	crackarg(cpu, inst, &inst->arg1, wop);
	crackarg(cpu, inst, &inst->arg2, wop);
	crackarg(cpu, inst, &inst->arg3, wop);

	switch(inst->op){
	case OPUSH:
	case OPOP:
		break;
	default:
		if(tab.arg1 != ANONE && small[tab.arg1] && small[tab.arg2] && small[tab.arg3]){
			assert(inst->opsize == cpu->opsize);
			inst->opsize = 8;
		}
		if((tab.op == OIN || tab.op == OOUT) && (tab.arg1 == AAL || tab.arg2 == AAL))
			inst->opsize = 8;
		break;
	}
}

static void
crackmodrm(Cpu *cpu, Inst *inst, Wordop *wop)
{
	uchar i;
	int s;

	i = wop8.fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc++);
	inst->mod = i>>6;
	inst->rop = (i>>3)&7;
	inst->rm = i&7;

	if(inst->mod == 3)	/* denotes register, get it later */
		return;

	if(inst->mod == 0 && inst->rm == 6){
		inst->off = inst->disp = wop16.fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += 2;
		return;
	}

	switch(inst->rm){
	default:
		abort();
	case 0:	/* [BX+SI] */
		s = RDS;
		inst->off = wop->rreg(cpu, RBX, 0)+wop->rreg(cpu, RSI, 0);	
		break;
	case 1:	/* [BX+DI] */
		s = RDS;
		inst->off = wop->rreg(cpu, RBX, 0)+wop->rreg(cpu, RDI, 0);
		break;
	case 2:	/* [BP+SI] */
		s = RSS;
		inst->off = wop->rreg(cpu, RBP, 0)+wop->rreg(cpu, RSI, 0);
		break;
	case 3:	/* [BP+DI] */
		s = RSS;
		inst->off = wop->rreg(cpu, RBP, 0)+wop->rreg(cpu, RDI, 0);
		break;
	case 4:	/* [SI] */
		s = RDS;
		inst->off = wop->rreg(cpu, RSI, 0);
		break;
	case 5:	/* [DI] */
		s = RDS;
		inst->off = wop->rreg(cpu, RDI, 0);
		break;
	case 6:	/* [BP] */
		s = RSS;
		inst->off = wop->rreg(cpu, RBP, 0);
		break;
	case 7:	/* [BX] */
		s = RDS;
		inst->off = wop->rreg(cpu, RBX, 0);
		break;
	}
	switch(inst->mod){
	case 0:
		break;
	case 1:
		inst->off += (inst->disp = wop8.fetchs(cpu, wop16.rreg(cpu, RCS, 0), inst->epc++));
		break;
	case 2:
		inst->off += (inst->disp = wop16.fetchs(cpu, wop16.rreg(cpu, RCS, 0), inst->epc));
		inst->epc += 2;
		break;
	}
	if(inst->sreg == 0){
		inst->sreg = "ECSD"[s-RES];
		inst->seg = wop16.rreg(cpu, s, 0);
	}
}

static void
regarg(Cpu *cpu, Wordop *wop, Iarg *iarg, int r)
{
	iarg->val = wop->rreg(cpu, r, 0);
	iarg->seg = r;
	iarg->w = wop->wreg;
}

/*
 * BUG: we should avoid fetches when not necessary to avoid bogus faults
 * that would require a bitmap of which operators need which arguments
 * to be read in.
 */
static void
crackarg(Cpu *cpu, Inst *inst, Iarg *iarg, Wordop *wop)
{
	long t;

	iarg->w = (void*)abort;
	switch(iarg->atype){
	default:
print("bad type %d\n", iarg->atype);
		abort();
	case ANONE:	/* no argument */
		break;
	case A0:	/* constant 0 */
		iarg->val = 0;
		break;
	case A1:	/* constant 1 */
		iarg->val = 1;
		break;
	case A3:	/* constant 3 */
		iarg->val = 3;
		break;
	case A4:	/* constant 4 */
		iarg->val = 4;
		break;

	case AAp:	/* 32-bit or 48-bit direct address */
		iarg->sreg = 0;
		iarg->seg = wop16.fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += 2;
		iarg->off = wop->fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += wop->len;
		break;

	case AEp:	/* r/m-ptr from modrm byte */
		if(inst->mod == 3)
			trap(cpu, TBADOP);
		iarg->sreg = inst->sreg;
		iarg->seg = wop16.fetch(cpu, inst->seg, inst->off);
		iarg->off = wop16.fetch(cpu, inst->seg, inst->off+2);	//ADDRSIZE
		break;
	case AEb:	/* r/m8 from modrm byte */
		wop = &wop8;
		goto AE;
	case AEw:	/* r/m16 from modrm byte */
		wop = &wop16;
		/* fall through */
	case AEv:	/* r/m16 or r/m32 from modrm byte */
	AE:
		if(inst->mod == 3)	/* register */
			regarg(cpu, wop, iarg, inst->rm);
		else{
			iarg->sreg = inst->sreg;
			iarg->seg = inst->seg;
			iarg->off = inst->off;
			iarg->val = wop->fetch(cpu, inst->seg, inst->off);
			iarg->w = wop->store;
		}
		break;

	case AFv:
		iarg->val = cpu->flags;
		iarg->w = putflags;
		break;

	case AM:	/* memory address from modrm */
	case AMa:	/* weird thing for bound */
	case AMp:	/* memory address from modrm */
		if(inst->mod == 3)
			trap(cpu, TBADOP);
		iarg->sreg = inst->sreg;
		iarg->seg = inst->seg;
		iarg->off = inst->off;
		break;

	case AMa2:	/* weird thing for bound */
		iarg->sreg = inst->sreg;
		iarg->seg = inst->seg;
		iarg->off = inst->off+2;
		break;

	/* case AMp: see case AAp above */

	case AGw:	/* r16 from modrm byte */
		wop = &wop16;
		goto AG;
	case AGb:	/* r8 from modrm byte */
		wop = &wop8;
		/* fall through */
	case AGv:	/* r16 or r32 from modrm byte */
	AG:
		regarg(cpu, wop, iarg, inst->rop);
		break;

	case AIb:	/* immediate byte */
		wop = &wop8;
		goto AI;
	case AIw:	/* immediate 16-bit word */
		wop = &wop16;
		/* fall through */
	case AIv:	/* immediate 16-bit or 32-bit word */
	AI:
		iarg->val = wop->fetch(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += wop->len;
		break;
	case AIc:	/* immediate byte sign-extend */
		iarg->val = wop8.fetchs(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc++;
		break;

	case AJb:	/* relative offset byte */
		wop = &wop8;
		/* fall through */
	case AJv:	/* relative offset 16-bit or 32-bit word */
		iarg->sreg = 'C';
		iarg->seg = wop16.rreg(cpu, RCS, 0);
		t = wop->fetchs(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += wop->len;
		iarg->off = inst->epc + t;
		break;
	case AJr:
		if(inst->mod != 3)
			trap(cpu, TBADOP);
		inst->sreg = 'C';
		inst->seg = wop16.rreg(cpu, RCS, 0);
		inst->off = wop->rreg(cpu, inst->rm, 0);
		break;

	case AOb:	/* immediate word-sized offset to a byte */
		wop = &wop8;
		/* fall through */
	case AOv:	/* immediate word-size offset to a word */
		iarg->sreg = inst->sreg;
		iarg->seg = inst->seg;
		iarg->off = wop16.fetchs(cpu, wop16.rreg(cpu, RCS, 0), inst->epc);
		inst->epc += wop16.len;
		iarg->val = wop->fetch(cpu, iarg->seg, iarg->off);
		iarg->w = wop->store;
		break;

	case ASw:	/* segment register selected by r field of modrm */
		regarg(cpu, &wop16, iarg, RES+inst->rop);
		break;

	case AXb:	/* byte at DS:SI */
		wop = &wop8;
		/* fall through */
	case AXv:	/* word at DS:SI */
		iarg->sreg = 'D';
		iarg->seg = wop16.rreg(cpu, RDS, 0);
		iarg->off = wop16.rreg(cpu, RSI, 0);	//ADDRSIZE
		iarg->val = wop->fetch(cpu, iarg->seg, iarg->off);
		iarg->w = wop->store;
		iarg->p = bumpdssi;
		break;

	case AYb:	/* byte at ES:DI */
		wop = &wop8;
		/* fall through */
	case AYv:	/* word at ES:DI */
		iarg->sreg = 'E';
		iarg->seg = wop16.rreg(cpu, RES, 0);
		iarg->off = wop16.rreg(cpu, RDI, 0);	//ADDRSIZE
		iarg->val = wop->fetch(cpu, iarg->seg, iarg->off);
		iarg->w = wop->store;
		iarg->p = bumpesdi;
		break;

	case AAL:
	case AAH:
	case ABL:
	case ABH:
	case ACL:
	case ACH:
	case ADL:
	case ADH:
		iarg->seg = iarg->atype - AAL;
		iarg->val = wop8.rreg(cpu, iarg->atype - AAL, 0);
		iarg->w = wop8.wreg;
		break;

	case AAX:
	case ABX:
	case ACX:
	case ADX:
	case ABP:
	case ASP:
	case ADI:
	case ASI:
	case AES:
	case ACS:
	case ASS:
	case ADS:
	case AFS:
	case AGS:
		iarg->seg = iarg->atype - AAX;
		iarg->val = wop->rreg(cpu, iarg->atype - AAX, 0);
		iarg->w = wop->wreg;
		break;
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.