File:  [MW Coherent from dump] / coherent / b / bin / c / n3 / i386 / icode.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * n3/i386/icode.c
 * Machine dependent parts of the intermediate file printer.
 * Read and print encoded machine instructions and operands.
 * Includes tables of opcodes and register names.
 * i386.
 */

#ifdef	vax
#include "INC$LIB:cc3.h"
#else
#include "cc3.h"
#endif

/*
 * Opcode names which depend on assembler format.
 */

#if	AS_FORMAT
#define	ICALL	"icall"
#define	IJMP	"ijmp"
#define	XICALL	"licall"
#define	XIJMP	"lijmp"
#define	XCALL	"lcall"
#define	XJMP	"ljmp"
#define	XRET	"lret"
#define	DBYTE	".byte"
#define	DWORD	".word"
#define	DLONG	".long"
#else
#define	ICALL	"call"
#define	IJMP	"jmp"
#define	XICALL	"call"
#define	XIJMP	"jmp"
#define	XCALL	"call"
#define	XJMP	"jmp"
#define	XRET	"ret"
#define	DBYTE	".db"
#define	DWORD	".dw"
#define	DLONG	".dd"
#endif

/*
 * Instruction names, sizes, and flags.
 * This table is ordered according to h/i8086/opcode.h
 * and thus parallel to n2/i8086/opcode.c.
 * Modifications to any of these require modifications to all of them.
 */
static struct ins {
	char *i_name;
	char  i_size;
	char  i_flag;
} ins[] = {
	"adc",		2,	0,
	"addl",		2,	0,
	"addb",		2,	OP_BYTE,
	"addw",		2,	OP_WORD,
	"andl",		2,	0,
	"andb",		2,	OP_BYTE,
	"andw",		2,	OP_WORD,
	"call",		1,	OP_NPTR,
	"cbw",		0,	OP_WORD,
	"cdq",		0,	0,
	"clc",		0,	0,
	"cld",		0,	0,
	"cli",		0,	0,
	"cmc",		0,	0,
	"cmpl",		2,	0,
	"cmpb",		2,	OP_BYTE,
	"cmpw",		2,	OP_WORD,
	"cmpsw",	0,	0,
	"cmpsb",	0,	0,
	"cmpsw",	0,	OP_WORD,
	"cwd",		0,	OP_WORD,
	"cwde",		0,	0,
	"decl",		1,	0,
	"decb",		1,	OP_BYTE,
	"decw",		1,	OP_WORD,
	"divl",		1,	0,
	"divb",		1,	OP_BYTE,
	"divw",		1,	OP_WORD,
 	"enter",	2,	0,
	"hlt",		0,	0,
	ICALL,		1,	0,
	"idivl",	1,	0,
	"idivb",	1,	OP_BYTE,
	"idivw",	1,	OP_WORD,
	IJMP,		1,	0,
	"imull",	1,	0,
	"imulb",	1,	OP_BYTE,
	"imulw",	1,	OP_WORD,
 	"imul",		3,	0,
	"incl",		1,	0,
	"incb",		1,	OP_BYTE,
	"incw",		1,	OP_WORD,
	"iret",		0,	0,
	XICALL,		1,	OP_DWORD,
	XIJMP,		1,	OP_NPTR,
	"ja",		1,	OP_JUMP,
	"jae",		1,	OP_JUMP,
	"jb",		1,	OP_JUMP,
	"jbe",		1,	OP_JUMP,
	"jcxz",		1,	OP_JUMP,
	"je",		1,	OP_JUMP,
	"jg",		1,	OP_JUMP,
	"jge",		1,	OP_JUMP,
	"jl",		1,	OP_JUMP,
	"jle",		1,	OP_JUMP,
	"jmp",		1,	OP_JUMP,
	"jne",		1,	OP_JUMP,
	"jno",		1,	OP_JUMP,
	"jns",		1,	OP_JUMP,
	"jo",		1,	OP_JUMP,
	"jpe",		1,	OP_JUMP,
	"jpo",		1,	OP_JUMP,
	"js",		1,	OP_JUMP,
	"lea",		2,	0,
 	"leave",	0,	0,
	"lock",		0,	0,
	"lodsw",	0,	0,
	"lodsb",	0,	0,
	"loop",		1,	OP_JUMP,
	"loope",	1,	OP_JUMP,
	"loopne",	1,	OP_JUMP,
	"movl",		2,	0,
	"movb",		2,	OP_BYTE,
	"movw",		2,	OP_WORD,
	"movsw",	0,	0,
	"movsb",	0,	0,
	"movsxw",	2,	0,
	"movsxb",	2,	OP_BYTE,
	"movzxw",	2,	0,
	"movzxb",	2,	OP_BYTE,
	"mull",		1,	0,
	"mulb",		1,	OP_BYTE,
	"mulw",		1,	OP_WORD,
	"negl",		1,	0,
	"negb",		1,	OP_BYTE,
	"negw",		1,	OP_WORD,
	"notl",		1,	0,
	"notb",		1,	OP_BYTE,
	"notw",		1,	OP_WORD,
	"ret",		1,	OP_NPTR,
	"ret",		1,	OP_NPTR,
	"orl",		2,	0,
	"orb",		2,	OP_BYTE,
	"orw",		2,	OP_WORD,
	"pop",		1,	0,
	"popf",		0,	0,
	"push",		1,	0,
	"pushf",	0,	0,
	"rcl",		2,	0,
	"rclb",		2,	OP_BYTE,
	"rcr",		2,	0,
	"rcrb",		2,	OP_BYTE,
	"repe",		0,	0,
	"repne",	0,	0,
	"ret",		0,	0,
	"rol",		2,	0,
	"rolb",		2,	OP_BYTE,
	"ror",		2,	0,
	"rorb",		2,	OP_BYTE,
	"sall",		2,	0,
	"salb",		2,	OP_BYTE,
	"salw",		2,	OP_WORD,
	"sarl",		2,	0,
	"sarb",		2,	OP_BYTE,
	"sarw",		2,	OP_WORD,
	"sbb",		2,	0,
	"scasw",	0,	0,
	"scasb",	0,	0,
	"shll",		2,	0,
	"shlb",		2,	OP_BYTE,
	"shlw",		2,	OP_WORD,
	"shrl",		2,	0,
	"shrb",		2,	OP_BYTE,
	"shrw",		2,	OP_WORD,
	"stc",		0,	0,
	"std",		0,	0,
	"sti",		0,	0,
	"stosw",	0,	0,
	"stosb",	0,	0,
	"subl",		2,	0,
	"subb",		2,	OP_BYTE,
	"subw",		2,	OP_WORD,
	"testl",	2,	0,
	"testb",	2,	OP_BYTE,
	"testw",	2,	OP_WORD,
	"wait",		0,	0,
	XCALL,		1,	OP_NPTR,
	"xchg",		2,	0,
	"xchgb",	2,	OP_BYTE,
	XJMP,		1,	OP_NPTR,
	"xorl",		2,	0,
	"xorb",		2,	OP_BYTE,
	"xorw",		2,	OP_WORD,
	XRET,		0,	0,

/* Specials. */
	DBYTE,		1,	OP_DD|OP_NPTR,
	DWORD,		1,	OP_DD|OP_NPTR,
	DLONG,		1,	OP_DD|OP_NPTR,
	DLONG,		1,	OP_DD|OP_NPTR,
	DLONG,		1,	OP_DD|OP_NPTR,

/* Old, now unused. */
#if	0
	"aaa",		0,	0,
	"aad",		0,	0,
	"aam",		0,	0,
	"aas",		0,	0,
	"adcb",		2,	OP_BYTE,
	"daa",		0,	0,
	"das",		0,	0,
	"in",		1,	0,
	"inb",		1,	OP_BYTE,
	"int",		1,	OP_NPTR,
	"into",		0,	0,
	"lahf",		0,	0,
	"lds",		2,	OP_DWORD,
	"les",		2,	OP_DWORD,
	"out",		1,	0,
	"outb",		1,	OP_BYTE,
	"sahf",		0,	0,
	"sbbb",		2,	OP_BYTE,
	"xlat",		0,	0,
#endif

#if	1
	"faddl",	1,	0,
	"fadds",	1,	0,
	"fiaddl",	1,	0,
	"fiadds",	1,	0,
	"fsubl",	1,	0,
	"fsubs",	1,	0,
	"fisubl",	1,	0,
	"fisubs",	1,	0,
	"fsubrl",	1,	0,
	"fsubrs",	1,	0,
	"fisubrl",	1,	0,
	"fisubrs",	1,	0,
	"fcomp",	0,	0,
	"fcompl",	1,	0,
	"fcomps",	1,	0,
	"ficompl",	1,	0,
	"ficomps",	1,	0,
	"fmull",	1,	0,
	"fmuls",	1,	0,
	"fimull",	1,	0,
	"fimuls",	1,	0,
	"fdivl",	1,	0,
	"fdivs",	1,	0,
	"fidivl",	1,	0,
	"fidivs",	1,	0,
	"fdivrl",	1,	0,
	"fdivrs",	1,	0,
	"fidivrl",	1,	0,
	"fidivrs",	1,	0,
	"fchs",		0,	0,
	"ftst",		0,	0,
	"fldz",		0,	0,
	"fld1",		0,	0,
	"fstsw",	1,	0,
	"fldl",		1,	0,
	"flds",		1,	0,
	"fildl",	1,	0,
	"filds",	1,	0,
	"fldt",		1,	0,
	"fstl",		1,	0,
	"fsts",		1,	0,
	"fistl",	1,	0,
	"fists",	1,	0,
	"fstpl",	1,	0,
	"fstps",	1,	0,
	"fistpl",	1,	0,
	"fistps",	1,	0,
	"fstpt",	1,	0,
	"fwait",	0,	0,
#if	0
	"fdrop",	0,	0,
#else
	"fstp\t%st",	0,	0,
#endif

/* Old, now unused. */
#if	0
	"fadd",		0,	0,
	"fsub",		0,	0,
	"frsub",	0,	0,
	"fmul",		0,	0,
	"fdiv",		0,	0,
	"frdiv",	0,	0,
#endif
#endif
};

/*
 * Handle code nodes.
 */
icode()
{
	register int op, i, n;
	register struct ins *ip;

	op = bget();
	if (dotseg == SSTRN && op == ZBYTE) {
		istring();
		return;
	}
	ip = &ins[op];
	bput('\t');
#if	0
	if (ip->i_flag & OP_WORD)
		fprintf(ofp, "pfx16:\t");
#endif
	fputs(ip->i_name, ofp);
	n = ip->i_size;
	for (i = 0; i < n; i += 1) {
		if (i == 0) {
			bput('\t');
		} else
			fputs(", ", ofp);
		iafield(ip);
	}
	bput('\n');
}

/*
 * Print a string for the assembler.
 * The first ZBYTE op has already been read before the call.
 */
istring()
{
	register int imode, c, op;

	fputs("\t.byte\t\"", ofp);
	for(;;) {
		if (((imode = iget()) & A_AMOD) != A_DIR)
			cbotch("istring: imode=%d\n", imode);
		c = ((imode & A_OFFS) != 0) ? iget() : 0;
		if (c == '\0') {
			fprintf(ofp, "\", 0\n");
			return;
		} else if (c == '\n')
			fprintf(ofp, "\\n");
		else if (c < ' ' || c > 0x7F)
			fprintf(ofp, "\\%03o", c);
		else
			bput(c);
		if ((op = bget()) != CODE) {
			unbget(op);
			break;
		} else if ((op = bget()) != ZBYTE)
			cbotch("istring: %x\n", op);
	}
	fputs("\"\n", ofp);
}

/*
 * These tables are indexed by the regm field of a mode.
 * They contain the ASCII strings used to print reg names in VASM mode.
 */
static	char	*dregs[] = {
	"%eax",	"%ecx",	"%edx",	"%ebx",	"%esp",	"%ebp",	"%esi",	"%edi"
};

static	char	*wregs[] = {
	"%ax",	"%cx",	"%dx",	"%bx",	"%sp",	"%bp",	"%si",	"%di"
};

static	char	*bregs[] = {
	"%al",	"%cl",	"%dl",	"%bl",	"%ah",	"%ch",	"%dh",	"%bh"
};

static	int	scale[] = {
	1,	2,	4,	8
};

/*
 * Read and print an address field.
 * The style of the address is determined by flag bits in the address mode.
 * These bits are cleared away when the mode is actually stored in the afield.
 */
iafield(ip)
register struct ins	*ip;
{
	register int	imode, mode, regm, flag;
	register ival_t	offs;

	imode = iget();
	if ((imode & A_OFFS) != 0)
		offs = iget();
	else
		offs = (ival_t)0;
	if ((imode & A_LID) != 0)
		sprintf(id, ".L%d", (int)iget());
	else if ((imode & A_GID) != 0)
		sget(id, NCSYMB);
	mode = imode & A_AMOD;
	if ((mode & A_X) != 0)
		mode = A_X;			/* indexed in some form */
	regm = imode & A_REGM;
	flag = ip->i_flag;
	switch (mode) {

	case A_IMM:
#if	AS_FORMAT
		bput('$');
#else
		if ((imode & (A_LID|A_GID)) != 0)
			fprintf(ofp, "offset ");
#endif
		/* fall through... */
	case A_DIR:
	case A_X:
		/* Immediate, direct, indexed, all in one grungy case. */
#if	!AS_FORMAT
		if (mode!=A_IMM && (flag&OP_NPTR)==0) {
			if ((flag&OP_BYTE) != 0)
				fprintf(ofp, "byte");
			else if ((flag&OP_WORD) != 0)
				fprintf(ofp, "word");
			else
				fprintf(ofp, "dword");
			fprintf(ofp, " ptr ");
		}
		if (mode == A_X) {
			bput('[');
			if ((imode & A_AMOD) == A_XB)
				fprintf(ofp, "%s", dregs[regm]);
			else if ((imode & A_AMOD) == A_XSIB) {
				if (regm != 5)
					fprintf(ofp, "%s",  dregs[regm]);
				fprintf(ofp, ", %s, %d",
					dregs[IREG(imode)],
					scale[SCALE(imode)]);
			}
		}
#endif
		if ((imode & (A_LID|A_GID)) != 0) {
			/* Symbol-relative. */
#if	!AS_FORMAT
			if (mode == A_X)
				bput('+');
#endif
			fputs(id, ofp);
			if ((SIGNEDADDRESS)offs > 0)
				bput('+');
		}
#if	!AS_FORMAT
		else if (mode==A_X && (SIGNEDADDRESS)offs>0)
			bput('+');
#endif
		if (offs!=0 || ((imode & (A_LID|A_GID))==0 && mode!=A_X)) {
#if	AS_FORMAT
			fprintf(ofp, I_FMT, offs);
#else
			if ((SIGNEDADDRESS)offs<0) {
				bput('-');
				offs = -(SIGNEDADDRESS)offs;
			}
			fprintf(ofp, "0" I_FMTX "h", offs);
#endif
		}
		if (mode == A_X) {
#if	AS_FORMAT
			bput('(');
			if ((imode & A_AMOD) == A_XB)
				fprintf(ofp, "%s", dregs[regm]);
			else if ((imode & A_AMOD) == A_XSIB) {
				if (regm != 5)
					fprintf(ofp, "%s",  dregs[regm]);
				fprintf(ofp, ", %s, %d",
					dregs[IREG(imode)],
					scale[SCALE(imode)]);
			}
			bput(')');
#else
			bput(']');
#endif
		}
		break;

	case A_DR:
		fputs(dregs[regm], ofp);
		break;

	case A_WR:
		fputs(wregs[regm], ofp);
		break;

	case A_BR:
		fputs(bregs[regm], ofp);
		break;

	default:
		cbotch("ifield, mode=%d", mode);
	}
}

/* end of n3/i386/icode.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.