A complete (I think) set of code generator macros to generate published op-codes
Révision | b281f65ed7aeceaaf5feefa53f71dc6a4c0a99ac |
---|---|
Taille | 15,406 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
|
/* M68000/68010 code type definitions for a macro/compiler */
/* by Joel Matthew Rees October 1987 */
/* 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 compile */
/* not designed for cross-compiling */
/* General example: */
/* if (ADD(CLONG, E_Dn|3, 0, 0, E_InXi|2, iDw(1), sum)) */
/* printf("internal error\n"); */
/* generates the same code as the assembler line: */
/* ADD.l D3, sum(A2, D1.w) */
/* or prints an error message. */
/************** it is the user's responsibility **************/
/* to avoid compiling 68010 operators into code targeted for the 68000 */
/* 68010 specific operators: */
/* MOVE CCR, ea; MOVEC; MOVES; RTD */
/* also, on the 68010, RTE uses an extra format word on the system stack */
/* instructions and modes capable of causing privilege violations: */
/* AND #n, SR; OR #n, SR; and EOR #n, SR; */
/* RESET; RTE; STOP; MOVE An, USP; MOVE USP, An; MOVE ea, SR; */
/* and, on the 68010, MOVEC; MOVES; and MOVE SR, ea */
/* Macros and functions whose names are of the form "genXXXX" are the */
/* primary methods of access to code generation. */
/* Modes (E_Dn .. E_IMM); condition types (cc_T .. cc_LE, & cc_NOT); */
/* sizes (CBYTE .. CLONG); register classes (E_An or E_Dn); */
/* index register names (iDw(r) .. iAl(r)); and special register names */
/* (E_SR, E_CCR, E_USP, E_DFC, E_SFC, and E_VBR) should be referenced */
/* symbolically. Registers should be referenced numerically, ergo, */
/* (E_An | 7) for the stack pointer. */
/* Error checking is primarily to avoid generating fake or undefined */
/* machine code. Error codes returned aren't exact, but attempt to be */
/* indicative. */
/* It may be preferable to use general addressing mode generators */
/* instead of specific, for example, */
/* ADD(sz, E_IMM, 0, 8, dm, dx, dao); */
/* will compile the same code as */
/* ADDQ(sz, 8, dm, dx, dao); */
/* or */
/* ADDI(sz, 8, dm, dx, dao); */
/* Access to the status register is by the more general routines: */
/* ORI(CBYTE, 1, E_CCR, 0, 0); */
/* generates code to set the carry bit, and */
/* MOVE(CBYTE, E_InINC|7, 0, 0, E_CCR, 0, 0); */
/* generates code to pop the LSByte of the top word on stack into the */
/* condition codes byte of the status register. */
typedef unsigned short CODE;
/* function pointer types */
typedef int (*PFI)();
typedef char *(*PFP)(); /* would it ever be used? */
#define MAXCODE 0x8000
#define MAXDATA 0x8000
/* operand sizes to generate *\
/* CBYTE, CWORD, and CLONG keyed to machine code, DO NOT CHANGE! */
#define CBYTE 0
#define CWORD 1
#define CLONG 2
#define CUNSPEC 8 /* intended only for internal use */
/* index register macros: keyed to machine code, DO NOT CHANGE! */
/* assume iXx(E_An|n) intends address register, don't bother masking */
#define iDw(r) ((r) << 12)
#define iDl(r) (0x0800 | ((r) << 12))
#define iAw(r) (0x8000 | ((r) << 12))
#define iAl(r) (0x8800 | ((r) << 12))
/* addressing modes: keyed to machine code, DO NOT CHANGE! */
/* register direct, Data and Address */
#define E_Dn 0
#define E_An 010
#define E_SP (E_An | 7) /* for convenience */
/* indirect, auto inc/dec, and indirect-offset */
#define E_In 020
#define E_InINC 030
#define E_InDEC 040
#define E_InOFF 050
/* indexed */
#define E_AnXi 060
/* absolute */
#define E_ABSw 070
#define E_ABSl 071
#define E_pcOFF 072
#define E_pcXi 073
#define E_IMM 074
/* status register operands: encode by size (CCR is low byte of SR) */
#define E_SR 0274
#define E_CCR E_SR
/* control registers: M68010 only, for MOVEC instruction */
#define E_SFC 0x8000
#define E_DFC 0x8001
#define E_USP 0x8800
#define E_VBR 0x8801
/* detect my flag bit and check undefined bits for 68010 */
#define E_CTL(r) ((r) & 0x8000 && !((r) & 0x7fe))
/* macros for conditionals */
#define cc_T 0
#define cc_F 0x100
#define cc_SUB (cc_F | 1) /* BSR is encoded where BF would have been */
#define cc_HI 0x200
#define cc_LS 0x300
#define cc_CC 0x400
#define cc_HS cc_CC
#define cc_CS 0x500
#define cc_LO cc_CS
#define cc_NE 0x600
#define cc_EQ 0x700
#define cc_VC 0x800
#define cc_VS 0x900
#define cc_PL 0xa00
#define cc_MI 0xb00
#define cc_GE 0xc00
#define cc_LT 0xd00
#define cc_GT 0xe00
#define cc_LE 0xf00
#define cc_NOT(cc) ((cc) ^ 0x100)
/* code generation error messages returned */
/* modes not available: source and destination */
#define CERRsmna 1
#define CERRdmna (CERRsmna << 4)
/* data or displacement too large: source and destination */
#define CERRsdtl 2
#define CERRddtl (CERRsdtl << 4)
/* size not available */
#define CERRszna 0x1000
/* source/destination incompatibility */
#define CERRsdi 0x2000
/* not an allowed op (when tested) */
#define CERRopna 0x4000
/* code array full */
#define CERRcful 0x8000
/* macros for shifts/rotates: keyed to machine code, DO NOT CHANGE! */
#define _sRIGHT 0
#define _sLEFT 0400
#define _sARH 0
#define _sLOG 1
#define _sROX 2
#define _sROT 3
/* macros for bit operations: keyed to machine code, DO NOT CHANGE! */
#define _bTST 0
#define _bCHG 0100
#define _bCLR 0200
#define _bSET 0300
/* for MUL and DIV and CHK (REGOPs) */
#define _MUL 0140300
#define _DIV 0100300
#define _SIGNED 0400
#define _CHK 040600
/* macros for binary ops: keyed to machine code, DO NOT CHANGE! */
#define _ADD 0150000
#define _SUB 0110000
#define _CMP 0130000
#define _AND 0140000
#define _OR 0100000
#define _EOR 0120000 /* note that this is not real machine code! */
#define _notBCD 030000 /* mask! */
#define _notLOG 010000 /* mask! */
#define _ABCD _AND
#define _SBCD _OR
/* macros for MOVEM register lists: DO NOT MIX! */
/* example: */
/* err = MOVEM(CWORD, E_InINC|7, 0, 0, E_Dn, 0, */
/* _POP(E_DN|0) | _POP(E_DN|1) | _POP(E_An|6)); */
#define _PUL(r) (1 << (r))
#define _POP(r) _PUL(r)
#define _CTL(r) _PUL(r)
#define _TBL(r) _PUL(r)
#define _PSH(r) (((unsigned) 0x8000) >> (r))
/* externs for users -- functions of form _gXXX are used by macros */
#ifndef IS_code
extern CODE *cap; /* code allocation pointer */
extern CODE *dap; /* data allocation pointer */
/* used externally for 0, 1, and some 2 parameter ops */
extern int _gcode(); /* int err = _gcode((CODE) code); */
/* fill in pc relative address for instruction at (CODE *) addr */
extern int fillpcR(); /* int err = fillpcR(md, addr) */
/* fill in pc relative address for branch to cap at (CODE *) addr */
extern int fillB(); /* int err = fillB(sz, addr) */
/* for branches; offset is calculated from address a */
/* genBRA() and genBSR() are macros using genB(); */
extern int genB(); /* int err = genB(cc, addr); */
extern int genDB(); /* int err = genDB(cc, reg, addr); */
extern int genS(); /* int err = genS(cc, dm, dx, dao); */
/* for ABCD, SBCD, ADDX, SUBX, and CMPM */
extern int _gMULTI(); /* int err = _gMULTI(cd, sz, sm, dm); */
/* for ADDQ and SUBQ */
extern int _gQUICK(); /* int err=_gQUICK(cd, sz, val, dm, dx, dao); */
/* for ADDA, SUBA and CMPA; optimizes to QUICK when possible */
extern int _gADDR(); /* int err = _gADDR(cd, sz, sm, sx, svo, reg); */
/* for ADDI, SUBI, CMPI, ANDI, ORI, and EORI; */
/* optimizes to QUICK when possible, also handles SR, CCR, and ADDR */
extern int _gIMM(); /* int err = _gIMM(cd, sz, val, dm, dx, dao); */
/* for ADD, SUB, CMP, AND, OR, and EOR */
/* also handles IMM (optimized), ADDR, MULTI, SR, and CCR */
/* int err = _gBINOP(cd, sz, sm, sx, svo, dm, dx, dao); */
extern int _gBINOP();
/* for ASL, ASR, LSL, LSR, ROL, ROR, ROXL, ROXR */
/* sm is E_IMM or E_Dn|n, ct contains immediate count */
/* int err = _gSHIFT(cd, sz, sm, ct, dm, dx dao); */
extern int _gSHIFT();
/* for BCHG, BCLR, BSET, and BTST -- sz is implicit to sm */
/* sm is E_IMM or E_Dn|n, bit contains immediate bit number */
extern int _gBIT(); /* int err = _gBIT(op, sm, bit, dm, dx, dao); */
/* for MUL, DIV and CHK -- size is word */
/* int err = _gREGOP((_MUL | _SIGNED), sm, sx, svo, reg); */
extern int _gREGOP();
/* for CLR, NEG, NEGX, NOT, and TST (unary ops) */
extern int _gUNOP(); /* int err = _gUNOP(cd, sz, dm, dx, dao); */
/* for JMP, JSR, PEA, LEA */
extern int _gEA(); /* int err = _gEA(cd, dm, dx, dao, reg); */
/* for MOVEs */
extern int genEXG(); /* int err = genEXG(mx, my); */
/* system access to control registers */
/* genMOVEC() also handles MOVE USP */
extern int genMOVEC(); /* int err = genMOVEC(sm, dm); (super) */
/* int err = genMOVEM(sz, sm, sx, sao, dm, dx, dao); */
/* move register list in offset parameter, see _PSH and _PUL macros */
extern int genMOVEM();
/* int err = genMOVEP(sz, sm, soff, dm, doff); */
extern int genMOVEP();/* move alternate bytes */
/* int err = genMOVES(sz, sm, sx, soff, dm, dx, doff); (super) */
extern int genMOVES(); /* system access to user space */
/* int err = genMOVE(sz, sm, sx, svo, dm, dx, dao); */
extern int genMOVE(); /* general MOVEs, includes some (super) */
#endif
/* (super) denotes privileged instructions */
/* user macros: one word constant op codes */
#define genILLEGAL _gcode((CODE) 045374) /* ILLEGAL operation (trap) */
#define genRESET _gcode((CODE) 047160) /* assert RESET line (super) */
#define genNOP _gcode((CODE) 047161) /* NO oPeration filler code */
#define genRTE _gcode((CODE) 047163) /* ReTurn from Exception (super) */
#define genRTS _gcode((CODE) 047165) /* ReTurn from Subroutine */
#define genTRAPV _gcode((CODE) 047166) /* TRAP to system on oVerflow */
#define genRTR _gcode((CODE) 047167) /* ReTurn and Restore CCR */
/* user macros: one variable simple op codes */
#define genSTOP(cc) ( _gcode((CODE) 047162), /* STOP machine */ \
_gcode((CODE) (cc)) ) /* until exception recognized (super) */
#define genRTD(disp) ( _gcode((CODE) 047164), /* ReTurn */ \
_gcode((CODE) (disp)) ) /* and Deallocate parameters on stack */
#define genTRAP(n) _gcode((CODE) (047100 | ((n) & 0xf))) /* TRAP #n */
#define genUNLK(An) _gcode((CODE) (047130 | ((An) & 7))) /* UNLinK */
/* local space of a nested block or subroutine */
#define genSWAP(Dn) _gcode((CODE) (044100 | ((Dn) & 7))) /* SWAP */
/* low and high order words of Dn */
/* user macros: two variable simple op codes */
#define genEXT(sz, Dn) (((sz) == CWORD || (sz) == CLONG) ? \
_gcode((CODE) (044200 | ((((sz) + 1) & 1) << 6) | ((Dn) & 7))) : \
CERRszna) /* sign EXTend Dn */
#define genLINK(An, disp) (_gcode((CODE) /* LINK local space */ \
(047120 | ((An) & 7))), _gcode((CODE) disp))
/* user macros: conditionals */
#define genBRA(addr) genB(cc_T, addr) /* unconditional BRAnch */
#define genBSR(addr) genB(cc_SUB, addr) /* Branch to SubRoutine */
/* user macros: multi-precision math */
#define genABCD(sm, dm) /* Add Binary Coded Decimal */ \
_gMULTI(_ABCD, CBYTE, sm, dm)
#define genADDX(sz, sm, dm) /* Add Binary Coded Decimal */ \
_gMULTI(_ADD, sz, sm, dm)
#define genSBCD(sm, dm) /* Add Binary Coded Decimal */ \
_gMULTI(_SBCD, CBYTE, sm, dm)
#define genSUBX(sz, sm, dm) /* Add Binary Coded Decimal */ \
_gMULTI(_SUB, sz, sm, dm)
#define genCMPM(sz, sm, dm) /* Add Binary Coded Decimal */ \
_gMULTI(_CMP, sz, sm, dm)
/* user macros: binary operand */
#define genADDQ(sz, val, dm, dx, dao) \
_gQUICK(_ADD, sz, val, dm, dx, dao)
#define genSUBQ(sz, val, dm, dx, dao) \
_gQUICK(_SUB, sz, val, dm, dx, dao)
#define genADDA(sz, sm, sx, svo, reg) \
_gADDR(_ADD, sz, sm, sx, svo, reg)
#define genSUBA(sz, sm, sx, svo, reg) \
_gADDR(_SUB, sz, sm, sx, svo, reg)
#define genCMPA(sz, sm, sx, svo, reg) \
_gADDR(_CMP, sz, sm, sx, svo, reg)
#define genORI(sz, val, dm, dx, dao) /* ORI #x, SR (super) */ \
_gIMM(_OR, sz, val, dm, dx, dao)
#define genANDI(sz, val, dm, dx, dao) /* ANDI #x, SR (super) */ \
_gIMM(_AND, sz, val, dm, dx, dao)
#define genEORI(sz, val, dm, dx, dao) /* EORI #x, SR (super) */ \
_gIMM(_EOR, sz, val, dm, dx, dao)
#define genSUBI(sz, val, dm, dx, dao) \
_gIMM(_SUB, sz, val, dm, dx, dao)
#define genADDI(sz, val, dm, dx, dao) \
_gIMM(_ADD, sz, val, dm, dx, dao)
#define genCMPI(sz, val, dm, dx, dao) \
_gIMM(_CMP, sz, val, dm, dx, dao)
#define genOR(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_OR, sz, sm, sx, svo, dm, dx, dao)
#define genAND(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_AND, sz, sm, sx, svo, dm, dx, dao)
#define genEOR(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_EOR, sz, sm, sx, svo, dm, dx, dao)
#define genADD(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_ADD, sz, sm, sx, svo, dm, dx, dao)
#define genSUB(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_SUB, sz, sm, sx, svo, dm, dx, dao)
#define genCMP(sz, sm, sx, svo, dm, dx, dao) \
_gBINOP(_CMP, sz, sm, sx, svo, dm, dx, dao)
/* user macros: shifts and rotates */
#define genASL(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sLEFT | _sARH), sz, sm, ct, dm, dx, dao)
#define genASR(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sRIGHT | _sARH), sz, sm, ct, dm, dx, dao)
#define genLSL(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sLEFT | _sLOG), sz, sm, ct, dm, dx, dao)
#define genLSR(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sRIGHT | _sLOG), sz, sm, ct, dm, dx, dao)
#define genROL(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sLEFT | _sROT), sz, sm, ct, dm, dx, dao)
#define genROR(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sRIGHT | _sROT), sz, sm, ct, dm, dx, dao)
#define genROXL(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sLEFT | _sROX), sz, sm, ct, dm, dx, dao)
#define genROXR(sz, sm, ct, dm, dx, dao) \
_gSHIFT((_sRIGHT | _sROX), sz, sm, ct, dm, dx, dao)
/* user macros: bit operations */
#define genBCHG(sm, bit, dm, dx, dao) \
_gBIT(_bCHG, sm, bit, dm, dx, dao)
#define genBCLR(sm, bit, dm, dx, dao) \
_gBIT(_bCLR, sm, bit, dm, dx, dao)
#define genBSET(sm, bit, dm, dx, dao) \
_gBIT(_bSET, sm, bit, dm, dx, dao)
#define genBTST(sm, bit, dm, dx, dao) \
_gBIT(_bTST, sm, bit, dm, dx, dao)
/* user macros: MUL, DIV, CHK */
#define genMULS(sm, sx, svo, dr) \
_gREGOP((_MUL | _SIGNED), sm, sx, svo, dr)
#define genMULU(sm, sx, svo, reg) _gREGOP(_MUL, sm, sx, svo, reg)
#define genDIVS(sm, sx, svo, reg) \
_gREGOP((_DIV | _SIGNED), sm, sx, svo, reg)
#define genDIVU(sm, sx, svo, reg) _gREGOP(_DIV, sm, sx, svo, reg)
#define genCHK(sm, sx, svo, reg) _gREGOP(_CHK, sm, sx, svo, reg)
/* user macros: unary ops */
#define genCLR(sz, dm, dx, dao) _gUNOP(041000, sz, dm, dx, dao)
#define genNEG(sz, dm, dx, dao) _gUNOP(042000, sz, dm, dx, dao)
#define genNBCD(dm, dx, dao) _gUNOP(044000, CBYTE, dm, dx, dao)
/* fortunately, CBYTE is 0 (CBYTE | x == x) */
#define genNEGX(sz, dm, dx, dao) _gUNOP(040000, sz, dm, dx, dao)
#define genNOT(sz, dm, dx, dao) _gUNOP(043000, sz, dm, dx, dao)
#define genTST(sz, dm, dx, dao) _gUNOP(045000, sz, dm, dx, dao)
#define genTAS(dm, dx, dao) _gUNOP(045300, CBYTE, dm, dx, dao)
/* fortunately, CBYTE is 0 (CBYTE | x == x) */
/* user macros: effective address group */
#define genJMP(dm, dx, dao) _gEA(047300, dm, dx, dao, 0)
#define genJSR(dm, dx, dao) _gEA(047200, dm, dx, dao, 0)
#define genLEA(dm, dx, dao, reg) _gEA(040700, dm, dx, dao, reg)
#define genPEA(dm, dx, dao) _gEA(044100, dm, dx, dao, 0)
/* user macros: move group */
#define genMOVEQ(val, Dn) /* sz = long only */ \
_gcode((CODE) (070000 | ((Dn & 7) << 9) | (val & 0xff)))
#define genMOVEA(sz, sm, sx, svo, reg) /* to be uniform */ \
genMOVE(sz, sm, sx, svo, E_An|(reg&7), 0, 0)
#define genPUSH(sz, regs, dm, dx, dao) /* for convenience */ \
genMOVEM(sz, E_Dn, 0, regs, dm, dx, dao)
#define genPULL(sz, sm, sx, sao, regs) /* for convenience */ \
genMOVEM(sz, sm, sx, sao, E_Dn, 0, regs)