A complete (I think) set of code generator macros to generate published op-codes
Révision | b281f65ed7aeceaaf5feefa53f71dc6a4c0a99ac |
---|---|
Taille | 18,047 octets |
l'heure | 2020-10-08 20:37:04 |
Auteur | Joel Matthew Rees |
Message de Log | As it survived the trip across the Mac and ocean
|
/* code generation for the MC68000 and 68010 */
/* written for CS431 by Joel Matthew Rees, at BYU, January 1988 */
/* Assigned by the author to the public domain, February 2000, Takino, Japan. */
/* joel_rees@sannet.ne.jp */
/* http://www.page.sannet.ne.jp/joel_rees */
/* unsigned short integer should be 16 bits for native machine compile */
/* not designed for cross-compiling */
/* flag that this pass is on the code generator */
#define IS_code
#include "code.h"
/* allocation spaces */
static CODE code_array[MAXCODE];
CODE *cap = code_array;
static CODE *catop = &(code_array[MAXCODE]);
static CODE data_array[MAXDATA];
CODE *dap = data_array;
static CODE *datop = &(data_array[MAXDATA]);
/* parameters for code generators: */
/* unsigned short integer code; (cd) */
/* integer size; (sz) */
/* integer mode; (sm, mx, dm, my) containing mode and register bits */
/* integer register; (reg) containing register bits only */
/* integer index register; (sx, dx, ix) */
/* per the 68000 index extension word */
/* long integer immediate value/offset/absolute address; */
/* (svo, sao, soff, dvo, dao, doff, offs, addr) */
/* integer condition; (cc) for conditionals */
int _gcode(cd) /* push machine code words into the code array */
register CODE cd;
{ register int err = 0;
register CODE *pt = cap;
if (pt < catop)
{ *pt++ = cd;
cap = pt;
}
else
err = CERRcful;
return(err);
}
/* generate extension words: check errors & order before using! */
static int extension(size, mode, ix, offs) /* one extension at a time! */
register int size, mode, ix;
register long offs;
{ register int err = 0;
if ((mode & 070) == E_AnXi || mode == E_pcXi) /* index word */
err = _gcode((CODE) ((ix & 0xf800) | (offs & 0xff)));
else if (mode >= E_InOFF) /* offset/address/immediate word */
{ if (mode == E_ABSl || (mode == E_IMM && size == CLONG))
err = _gcode((CODE) (offs >> 16)); /* high word */
if (mode == E_IMM && size == CBYTE)
offs &= 0xff;
err = _gcode((CODE) offs); /* low word */
}
return(err); /* only code array full errors produced here */
}
/* macro for generating effective address fields */
/* part is (mode & 070), usually in a register */
#define EA(mode, part) \
(((mode) < E_ABSw) ? ((part) | ((mode) & 7)) : ((mode) & 077))
int fillpcR(md, pcat) /* fill in pc relative address, after instruction */
int md;
register CODE *pcat;
{ register long disp = (long) cap - (long) pcat - 2; /* offset */
register int err = 0;
pcat++; /* bump to extension word */
if (md == E_pcXi)
if (disp > -0x80 && disp < 0x7f)
{ *pcat &= 0xff00; /* clear previous offset byte */
*pcat |= (char) disp;
}
else
err = CERRddtl;
else if (md == E_pcOFF)
if (disp > (long) -0x8000 && disp < (long) 0x7fff)
*pcat = (CODE) disp;
else
err = CERRddtl;
else
err = CERRdmna;
return(err);
}
int fillB(sz, brat) /* fill in pc relative address, after branch */
int sz;
register CODE *brat;
{ register long disp = (long) cap - (long) brat - 2; /* offset */
register int err = 0;
*brat &= 0xff00; /* clear previous offset byte (long branch has problems with this) */
if (sz == CBYTE)
if (disp > -0x80 && disp < 0x7f)
*brat |= (char) disp;
else
err = CERRddtl;
else if (sz == CWORD)
if (disp > (long) -0x8000 && disp < (long) 0x7fff)
*(++brat) = (CODE) disp; /* bump to word offset first */
else
err = CERRddtl;
else
err = CERRszna;
return(err);
}
int genB(cc, addr) /* Branch to address on condition */
register int cc;
register CODE *addr;
{ register CODE cd = 0x6000 | (cc & 0xf00); /* strip other bits */
register int err = 0;
register long disp = (long) addr - (long) cap - 2; /* offset */
if (cc == cc_F) /* cc_SUB != cc_F => cc_SUB can be encoded */
err = CERRopna;
else
if (disp > -0x80 && disp < 0x7f)
err = _gcode((CODE) (cd | (disp & 0xff)));
else if (disp > (long) -0x8000 && disp < (long) 0x7fff)
{ err = _gcode(cd);
err = _gcode((CODE) disp);
}
else
err = CERRddtl;
return(err);
}
int genDB(cc, reg, addr) /* Decrement word reg, Branch on ~cc to a */
register int cc;
register int reg;
register CODE *addr;
{ register CODE cd = 0x50c8 | (cc & 0xf00) | (reg & 7);
register err = 0;
register long disp = (long) addr - (long) cap - 2; /* offset */
if (disp > (long) -0x8000 && disp < (long) 0x8000)
{ err = _gcode(cd);
err = _gcode((CODE) disp);
}
else
err = CERRddtl;
return(err);
}
int genS(cc, dm, dx, dao) /* Set conditional, byte only */
int cc; /* a unary operator with a condition and only one size */
register int dm;
int dx;
long dao;
{ register CODE cd = 050300 | (cc & 0xf00);
register int err = 0;
register int pdm = dm & 070; /* partial */
if (pdm == E_An || dm > E_ABSl)
err = CERRdmna;
else
{ err = _gcode((CODE) (cd | EA(dm, pdm)));
err = extension(CUNSPEC, dm, dx, dao);
}
return(err);
}
int genEXG(mx, my) /* EXchanGe two registers */
register int mx, my; /* mode is (E_An | n) or (E_Dn | n) */
{ register CODE cd = 0140400;
register int pmx = mx & 070;
register int pmy = my & 070;
register int err = 0;
if (pmx == E_An)
if (pmy == E_An)
err = _gcode((CODE) (cd | 0110 | ((my & 7) << 9) | (mx & 7)));
else if (pmy == E_Dn)
err = _gcode((CODE) (cd | 0210 | ((my & 7) << 9) | (mx & 7)));
else
err = CERRsdi;
else if (pmx == E_Dn)
if (pmy == E_Dn)
err = _gcode((CODE) (cd | 0100 | ((mx & 7) << 9) | (my & 7)));
else if (pmy == E_An)
err = _gcode((CODE) (cd | 0210 | ((mx & 7) << 9) | (my & 7)));
else
err = CERRsdi;
else
err = CERRsmna | CERRsmna;
return(err);
}
int genMOVEC(sm, dm) /* 68010 superviser only access to Control regs */
register int sm, dm; /* mode is (E_An | n) or (E_Dn | n) or CTL reg */
{ register int err = 0;
if (E_CTL(sm))
if (dm < E_In)
if ((dm & 070) == E_An && sm == E_USP) /* optimize to MOVE USP */
err = _gcode((CODE) (047150 | (dm & 7)));
else
{ err = _gcode(047172);
err = _gcode((CODE) (((dm & 017) << 12) | (sm & 0xfff)));
}
else
err = CERRdmna;
else if (E_CTL(dm))
if (sm < E_In)
if ((sm & 070) == E_An && dm == E_USP) /* optimize to MOVE USP */
err = _gcode((CODE) (047140 | (sm & 7)));
else
{ err = _gcode(047173);
err = _gcode((CODE) (((sm & 017) << 12) | (dm & 0xfff)));
}
else
err = CERRsmna;
else
err = CERRsmna | CERRdmna;
return(err);
}
/* MOVE uses different size encodings */
static CODE mvsztran[] = { 0x1000, 0x3000, 0x2000 };
/* note that MOVE ea, SR is privileged mode only */
/* and MOVE SR, ea is privileged mode only on the 68010 */
/* also note that MOVEC and MOVE CCR, ea are 68010 ops only */
int genMOVE(sz, sm, sx, svo, dm, dx, dao)
register int sz;
register int sm;
int sx;
long svo;
register int dm;
int dx;
long dao;
{ register int err = 0;
register int psm = sm & 070;
register int pdm = dm & 070;
if (sz < CBYTE || sz > CLONG)
err = CERRszna;
else if (E_CTL(sm) || E_CTL(dm))
err = genMOVEC(sm, dm);
else if (sm == E_SR) /* do Status Registers */
err = ((sz > CWORD || pdm == E_An || dm > E_ABSl)
? CERRsmna
: (_gcode((CODE) (((sz == CBYTE) ? 041300 : 040300)
| EA(dm, pdm))),
extension(sz, dm, dx, dao))); /* watch (super) */
else if (dm == E_SR)
err = ((sz > CWORD || psm == E_An || sm > E_IMM)
? CERRdmna
: (_gcode((CODE) (((sz == CBYTE) ? 042300 : 043300)
| EA(sm, psm))),
extension(sz, sm, sx, svo))); /* watch (super) */
else if (dm > E_ABSl || (sz == CBYTE && pdm == E_An))
err = CERRdmna;
else if (sm > E_IMM || (sz == CBYTE && psm == E_An))
err = CERRsmna;
else if (sm == E_IMM && pdm == E_Dn && sz == CLONG && svo < 255)
err = genMOVEQ(svo, dm); /* optimize */
else /* general MOVE, or MOVEA */
{ err = _gcode((CODE) (mvsztran[sz] | EA(sm, psm)
| (pdm << 3) | ((dm & 7) << 9)));
err = extension(sz, sm, sx, svo);
err = extension(sz, dm, dx, dao);
}
return(err);
}
/* if mode is E_Dn or E_An, value/offset is list */
int genMOVEM(sz, sm, sx, svo, dm, dx, dvo)
register int sz, sm;
int sx;
long svo;
register int dm;
int dx;
long dvo;
{ register int err = 0;
register psm = sm & 070;
register pdm = dm & 070;
if (sz < CWORD || sz > CLONG)
err = CERRszna;
else if (sm < E_In)
if (dm < E_In || pdm == E_InINC || dm > E_ABSl)
err = CERRdmna;
else
{ err = _gcode((CODE) (044200 | ((sz & 2) << 5)
| EA(dm, pdm)));
err = _gcode((CODE) svo);
err = extension(sz, dm, dx, dvo);
}
else if (dm < E_In)
if (psm == E_InDEC || sm > E_pcXi)
err = CERRsmna;
else
{ err = _gcode((CODE) (046200 | ((sz & 2) << 5)
| EA(sm, psm)));
err = _gcode((CODE) dvo);
err = extension(sz, sm, sx, svo);
}
else
err = CERRsmna | CERRdmna;
return(err);
}
int genMOVEP(sz, sm, soff, dm, doff) /* move alternate bytes */
register int sz, sm;
long soff;
register int dm;
long doff;
{ register int err = 0;
register int psm = sm & 070;
register int pdm = dm & 070;
if (sz > CLONG || (sz = (sz - 1) << 6) < 0)
err = CERRszna;
else if (psm == E_Dn && pdm == E_InOFF)
{ err = _gcode((CODE) (0610 | (sz & 0100)
| ((sm & 7) << 9) | (dm & 7)));
err = _gcode((CODE) doff);
}
else if (pdm == E_Dn && psm == E_InOFF)
{ err = _gcode((CODE) (0410 | (sz & 0100)
| ((dm & 7) << 9) | (sm & 7)));
err = _gcode((CODE) soff);
}
else
err = CERRsmna | CERRdmna;
return(err);
}
int genMOVES(sz, sm, sx, soff, dm, dx, doff)
register int sz, sm;
int sx;
long soff;
register int dm;
int dx;
long doff;
{ register CODE cd = 07000 | (sz & 3) << 6;
register int err = 0;
if (sz < CBYTE || sz > CLONG)
err = CERRszna;
else if (sm < E_In && dm >= E_In && dm < E_pcOFF)
{ err = _gcode((CODE) (cd | EA(dm, dm & 070)));
err = _gcode((CODE) ((sm << 12) | 0x800));
err = extension(sz, dm, dx, doff);
}
else if (dm < E_In && sm >= E_In && sm < E_pcOFF)
{ err = _gcode((CODE) (cd | EA(sm, sm & 070)));
err = _gcode((CODE) (dm << 12));
err = extension(sz, sm, sx, soff);
}
else
err = CERRsmna | CERRdmna;
return(err);
}
int _gMULTI(cd, sz, sm, dm)
register CODE cd;
register int sz;
int sm, dm;
{ register int err = 0;
register int psm = sm & 070;
register int pdm = dm & 070;
if (psm != pdm)
err = CERRsdi;
else if ((!(cd & _notBCD) && sz != CBYTE) || sz < CBYTE || sz > CLONG)
err = CERRszna;
else if ((cd == _CMP && psm != E_InINC)
|| (cd != _CMP && psm != E_Dn && psm != E_InDEC))
err = CERRsmna | CERRdmna;
else
{ if (cd & _notBCD)
cd |= (sz & 3) << 6;
if (psm != E_Dn)
cd |= 010; /* memory bit */
err = _gcode((CODE) (cd | 0400 | (sm & 7) | ((dm & 7) << 9)));
}
return(err);
}
int _gQUICK(cd, sz, val, dm, dx, dao) /* ADD and SUB only */
register CODE cd;
register int sz;
long val;
register int dm;
int dx;
long dao;
{ register int err = 0;
register int pdm = dm & 070;
if (cd == _SUB)
cd = 050400;
else /* assume add */
cd = 050000;
if (dm >= E_pcOFF || ((pdm == E_An) && sz == CBYTE))
err = CERRdmna;
else if (sz < CBYTE || sz > CLONG || (pdm == E_An && sz < CWORD))
err = CERRszna;
else /* assume val == 0 => intended val = 8: no size check */
{ err = _gcode((CODE) (cd | ((val & 7) << 9) | ((sz & 3) << 6)
| EA(dm, pdm)));
err = extension(sz, dm, dx, dao);
}
return(err);
}
int _gADDR(cd, sz, sm, sx, svo, reg) /* ADD, CMP, and SUB */
register CODE cd; /* reg is destination (An) */
register int sz;
register int sm;
int sx;
long svo;
int reg;
{ register int err = 0;
register int psm = sm & 070;
if (sm > E_IMM)
err = CERRsmna;
else if (sz < CWORD || sz > CLONG)
err = CERRszna;
else if (cd != _CMP && sm == E_IMM && svo > 0 && svo <= 8)
err = _gQUICK(cd, sz, svo, reg, 0, 0); /* optimize */
else
{ cd |= (~sz & 1) << 8; /* CWORD == 1, CLONG == 2 */
err = _gcode((CODE) (cd | 0300 | ((reg & 7) << 9) | EA(sm, psm)));
err = extension(sz, sm, sx, svo);
}
return(err);
}
/* translation for immediate: _OR, _SUB, _EOR, _CMP, _AND, _ADD */
static CODE immtran[] = { 0, 02000, 05000, 06000, 01000, 03000 };
int _gIMM(cd, sz, val, dm, dx, dao) /* all binary ops */
register CODE cd;
register int sz;
long val;
register int dm;
int dx;
long dao;
{ register int pdm = dm & 070;
register int err = 0;
if (!(cd & _notLOG) && dm == E_SR && sz == CLONG)
err = CERRszna | CERRdmna; /* SR is word, CCR is byte */
else if (dm >= E_pcOFF && !(!(cd & _notLOG) && dm == E_SR))
err = CERRdmna; /* allow AND, OR, EOR to status reg */
else if (pdm == E_An)
if (cd & _notLOG) /* _ADD, _SUB, _CMP */
err = _gADDR(cd, sz, E_IMM, 0, val, dm);
else
err = CERRdmna;
else if ((cd == _ADD || cd == _SUB) && val > 0 && val <= 8)
err = _gQUICK(cd, sz, val, dm, dx, dao);
else if (sz < CBYTE || sz > CLONG)
err = CERRszna;
else if (cd > _ADD)
err = CERRopna;
else /* do it here! */
{ err = _gcode((CODE) (immtran[(cd >> 12) & 7] | ((sz & 3) << 6)
| EA(dm, pdm)));
err = extension(sz, E_IMM, 0, val); /* immediate operand */
if (dm != E_SR) /* no ea if dest is status reg */
err = extension(sz, dm, dx, dao);
}
return(err);
}
int _gBINOP(cd, sz, sm, sx, svo, dm, dx, dao)
register CODE cd;
int sz;
register int sm;
int sx;
long svo;
register int dm;
int dx;
long dao;
{ register int err = 0;
register int pdm = dm & 070;
register int psm = sm & 070;
if (sm == E_IMM) /* vastly different op-code */
if ((cd == _ADD || cd == _SUB) && svo > 0 && svo <= 8)
err = _gQUICK(cd, sz, svo, dm, dx, dao); /* optimize here */
else
err = _gIMM(cd, sz, svo, dm, dx, dao);
else if (pdm == E_An)
if (cd & _notLOG)
err = _gADDR(cd, sz, sm, sx, svo, dm); /* different op-code */
else
err = CERRdmna;
else if (dm >= E_pcOFF) /* logic immediate to status already caught */
err = CERRdmna;
else if (psm == E_An && (!(cd & _notLOG) || sz == CBYTE))
err = CERRsmna;
else if (pdm == E_Dn && cd != _EOR) /* dest ea field can't be Dn */
{ err = _gcode((CODE) (cd | ((dm & 7) << 9) | (sz & 3) << 6
| EA(sm, psm)));
err = extension(sz, sm, sx, svo);
}
else if (psm == E_Dn && cd != _CMP)
{ if (cd == _EOR) /* CMP and EOR inhabit same code */
cd = _CMP;
err = _gcode((CODE) (cd | 0400 | (sm & 7) << 9 | (sz & 3) << 6
| EA(dm, pdm)));
err = extension(sz, dm, dx, dao);
}
else if (psm == pdm && ((psm == E_InDEC && (cd == _ADD || cd == _SUB))
|| (psm == E_InINC && cd == _CMP)))
err = _gMULTI(cd, sz, sm, dm); /* anomalous op! */
else
err = CERRsdi;
return(err);
}
int _gSHIFT(op, sz, sm, ct, dm, dx, dao) /* sm is E_IMM or E_Dn|n */
register int op;
int sz;
register int sm;
int ct;
register int dm;
int dx;
long dao;
{ register CODE cd = 0160000 | (op & _sLEFT);
register int pdm = dm & 070;
register int err = 0;
if (pdm == E_Dn)
{ if ((sm & 070) == E_Dn)
{ ct = sm; /* put number of register containing count in ct */
cd |= 040;
}
else if (sm != E_IMM)
err = CERRsmna;
if (!err) /* no range check, assume 0 means 8 if immediate */
err = _gcode((CODE) (cd | ((ct & 7) << 9)
| ((sz & 3) << 6) | ((op & 3) << 3) | (dm & 7)));
}
else if (pdm == E_An || dm > E_ABSl)
err = CERRdmna;
else if (sm != E_IMM)
err = CERRsdi;
else if (sz != CBYTE)
err = CERRszna;
else if (ct != 1) /* this mode shifts one bit at a time */
err = CERRsdtl;
else
{ err = _gcode((CODE) (cd | 0300 | ((op & 3) << 9)
| EA(dm, pdm))); /* direction, type, and ea */
err = extension(sz, dm, dx, dao);
}
return(err);
}
int _gBIT(op, sm, bit, dm, dx, dao) /* sm is E_IMM or E_Dn */
register int op, sm;
int bit;
register int dm;
int dx;
long dao;
{ register CODE cd = op & 0300;
register int pdm = dm & 070;
register err = 0;
if (pdm == E_An || (op != _bTST && dm > E_ABSl)
|| (sm == E_IMM && dm == E_IMM) || dm > E_IMM)
err = CERRdmna;
else
{ cd |= EA(dm, pdm);
if ((sm & 070) == E_Dn)
err = _gcode((CODE) (cd | 0400 | ((sm & 7) << 9)));
else if (sm = E_IMM)
{ err = _gcode((CODE) (cd | 04000));
err = _gcode((CODE) (bit & 0x1f));
}
else
err = CERRsmna;
if (!err && pdm != E_Dn)
err = extension(CUNSPEC, dm, dx, dao);
}
return(err);
}
int _gREGOP(cd, sm, sx, svo, reg) /* MUL, DIV, CHK */
register CODE cd;
register int sm;
int sx;
long svo;
int reg;
{ register int err = 0;
register int psm = sm & 070;
if (psm == E_An)
err = CERRsmna;
else
{ err = _gcode((CODE) (cd | ((reg & 7) << 9) | EA(sm, psm)));
err = extension(CWORD, sm, sx, svo);
}
return(err);
}
int _gUNOP(cd, sz, dm, dx, dao) /* CLR, NEG, NEGX, NOT, TST */
register CODE cd;
register int sz, dm;
int dx;
long dao;
{ register int err = 0;
register int pdm = dm & 070;
if (pdm == E_An || dm > E_ABSl)
err = CERRdmna;
else if (sz < CBYTE || sz > CLONG)
err = CERRszna;
else
{ err = _gcode((CODE) (cd | ((sz & 3) << 6) | EA(dm, pdm)));
err = extension(sz, dm, dx, dao);
}
return(err);
}
int _gEA(cd, dm, dx, dao, reg) /* unary ops with no size, also LEA */
register CODE cd; /* reg should be 0 for JMP, JSR, and PEA */
register int dm;
int dx;
long dao;
int reg;
{ register int err = 0;
register pdm = dm & 070;
if ((pdm < E_InOFF && pdm != E_In) || dm >= E_IMM)
err = CERRdmna;
else
{ err = _gcode((CODE) (cd | ((reg & 7) << 9) | EA(dm, pdm)));
err = extension(CUNSPEC, dm, dx, dao);
}
return(err);
}