• R/O
  • HTTP
  • SSH
  • HTTPS

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

A complete (I think) set of code generator macros to generate published op-codes


File Info

Révision b281f65ed7aeceaaf5feefa53f71dc6a4c0a99ac
Taille 11,545 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

Content

Notes for the code generator for the 68000/68010 by Joel Matthew Rees
This was 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


It isn't actually a code generator, just the lowest level piece thereof.
It provides embedded assembly, such as might be used in direct code generation.

code_array and data_array are provided as default assembly target spaces. I 
wrote these before I had the C skills to generalize the targeting. Now that I 
know several ways, I don't have the motivation or the time. 

Unsigned short integer should be 16 bits for native machine compile.
Not designed for cross-compiling.

The include file should be named code.h, not 68kcode.h.  If you like the
latter name, change the include line in code.c (68kcode.c) to
#include "68kcode.h"

Much of the code generation is done through C pre-processor macros, so code.c
and code.h should be used together in most situations.

Parameter order and number is intended to reflect the assembler syntax.  The
include file describes the use of several of the generation functions, and
the macro definitions in the include file may be examined to understand 
most of the rest.

Definition of external functions is controlled in the include file by the
variable "IS_code".  "IS_code" is defined in the file "code.c" only, by which
convention the external definition of the code generator functions is
suppressed while "code.c" is compiling.  All files which use code.o should
leave "IS_code" undefined.


***************************************************************************
A general M68000/M68010 assembler operand has one of the forms below:
(one size specified for both operands)

n		for an absolute address n
	mode: E_ABSw, E_ABSl (word and long addresses)
	arguments: mode and value

#n		for an immediate value n
	mode: E_IMM
	arguments: mode and value

Dn or An	for an address or data register n
	mode: E_Dn, E_An (with register number masked in: E_Dn|Dreg, E_An|Areg)
	arguments: mode|reg only

(An)		for indirection through an address register
	mode: E_In (with register number masked in: E_In|Areg)
	arguments: mode|Areg only

-(An) or (An)+	for auto-indirection
	mode: E_InDEC, E_InINC (with register number masked in: E_InDEC|Areg)
	arguments: mode|Areg only

d(An)		for indirection with constant displacement d
	mode: E_InOFF (with register number masked in: E_InOFF|Areg)
	arguments: mode|Areg and offset

d(PC)		for pc-relative by constant displacement d
	mode: E_pcOFF
	arguments: mode and offset

d(An, Rm.l)	for complex indexing with index register Rm of length l,
	(Rm is either a data or address register, l is either word or long.)
	mode: E_AnXi (with address register number masked in: E_AnXi|Areg)
	arguments: mode|Areg, index register, and offset

d(PC, Rm.l)	for pc-relative indexing
	mode: E_pcXi
	arguments: mode, index register, and offset

Move multiple registers (push, pop, et. al.) uses a register list operand:
Rm/Rn/../Rz	Rm -- Rz can be any data or address registers
	mode: not relevant for register list operand (see macro definition)
	arguments: register list with source/destination arguments

Special operands include the following:
CCR		the condition code register (low byte of SR)
	mode: E_CCR with size = CBYTE

SR		the status register (CCR and interrupt, processor state bits)
	mode: E_SR with size = CWORD

SP		equivalent to A7, the hardware or subroutine stack pointer
	mode: E_An|7, E_In|7, E_InINC|7, E_InDEC|7, E_InOFF|7, E_InXi|7

SSP		system stack pointer (A7 in supervisor state)
	mode: irrelevant

USP		user stack pointer (A7 in user state)
	mode: E_USP (MOVEC, MOVE to/from USP)

VBR		M68010 virtual machine vector base register
	mode: E_VBR (MOVEC)

SFC and DFC	M68010 source and destination function code registers
	mode: E_SFC and E_DFC (MOVEC)
	(for moving from or to alternate memory spaces)

The code generator arguments and definitions for the above are as follows:

sz:		the operand size
	CBYTE, CWORD, CLONG

sm or dm:	the mode argument, with the primary register number r masked in
	E_Dn, E_An, et. al.

sx or dx:	the index register number for complex and pc-relative indexing
	iDw(n), iDl(n), iAw(n), iAl(n) -- word (16 bit) and long (32 bit)

svo, dvo, sao, dao, val, etc.: the value, address, or offset, when appropriate
	no specific relevant definitions

regs:		a register list for MOVEM (push, pop, etc.)
	_PSH(r), _POP(r), _PUL(r), _CTL(r), _TBL(r)

**************************************************************************

Some examples of usage:
( ***** Not intended to be an assembler manual! *****
I recommend the purchase of the M68000 16/32-bit Microprocessor Programmer's
Reference Manual by Motorola.)

int err; /* all functions return an integer error code, non-zero on error */

/* to generate a register to register add: */
/* 	ADD.w	D0, D1 */
   err = genADD(CWORD, E_Dn|0, 0, 0, E_Dn|1, 0, 0);

/* to generate a dynamic register shift */
/*	ASR.l	D0, D1	arithmetic shift left D1 by count in D0 */
   err = genASR(CLONG, E_Dn|0, 0, E_Dn|1, 0, 0);

/* to generate a dynamic bit operation */
char FLAG;
/*	BCHG	D2, FLAG	toggle bit of memory numbered in D2 */
   err = genBCHG(E_Dn|2, E_ABSl, 0, (long) &FLAG);

/* to generate a backward branch */
CODE *targ1;
/* . . . . */
/* TARGET	EQU * */
   targ1 = cap;
/* . . . . */
/*	BVC	TARGET */
   err = genB(cc_VC, targ1); /* automatically chooses short or long */

/* to generate a short forward branch */
CODE *b1;
/* . . . . */
/*	BNE	TARGET */
   b1 = cap;
   err = genB(cc_NE, cap); /* small offset forces short branch */
/* . . . . */
/* TARGET	EQU * */
   err = fillB(CBYTE, b1);

/* to generate a long forward branch */
CODE *b1;
/* . . . . */
/*	BNE	TARGET */
   b1 = cap;
   err = genB(cc_NE, cap[128]); /* large offset forces long branch */
/* . . . . */
/* TARGET	EQU * */
   err = fillB(CWORD, b1);

/* err = fillB(CWORD, label) will fill in a DBcc forward reference */

/* to generate a 64 bit binary integer add in memory: N2 = N2 + N1 */
CODE *N1, *N2;
/* . . . . */
/* N1	DC.w	$0012	initial contents of N1, N2
	DC.w	$3289
	DC.w	$5543
	DC.w	$1287
N2	DC.w	$0404
	DC.w	$9840
	DC.w	$1743
	DC.w	$6637 */
   N1 = dap; /* dap is the data allocation pointer */
   *dap++ = 0x12; *dap++ = 0x3289; *dap++ = 0x5543; *dap++ = 0x1287;
   N2 = dap;
   *dap++ = 0x404; *dap++ = 0x9840; *dap++ = 0x1743; *dap++ = 0x6637;
/*	LEA	N1+8, A0
	LEA	N2+8, A1 */
   err = genLEA(E_ABSl, 0, (long) N1+4, E_An|0);
   err = genLEA(E_ABSl, 0, (long) N2+4, E_An|1);
/*	AND	#$ee, CCR	clear carry and extend bits */
   err = genAND(CBYTE, E_IMM, 0, ~0x11, E_CCR, 0, 0);
/*	ADDX.l	-(A0), -(A1)
	ADDX.l	-(A0), -(A1) */
   err = genADDX(CLONG, E_InDEC|0, E_InDEC|1);
   err = genADDX(CLONG, E_InDEC|0, E_InDEC|1);

/* to generate a 32 bit pc relative call using no registers */
CODE *jump, *ret;
long offs;
/* . . . . */
/*	PEA	RTLBL-*-2(PC)	push return address */
   jump = cap; /* cap is code allocation pointer */
   err = genPEA(E_pcOFF, 0, 0); /* will fill in later */
/*	PEA	2(PC)		push run-time PC */
   err = genPEA(E_pcOFF, 0, 2);
/*	ADD.L	#TARGET-*, (A7)	add constant offset to top of stack */
   ret = cap;
   err = genADD(CLONG, E_IMM, 0, 0, E_In|7, 0, 0); /* fill in later */
/*	RTS	pop destination into PC */
   err = genRTS;
/* RTLBL	EQU * */
   err = fillpcR(E_pcOFF, jump); /* calculate return offset and fill in */
/* . . . . */
/* TARGET	EQU * */
   offs = ((long) cap) - ((long) ret); /* calculate constant offset */
   ret[1] = (short) (offs >> 16); /* fill it in */
   ret[2] = (short) offs;

/* to generate a PC relative call through a relocatable call table: */
/* table index in D0 */
CODE *tblent, *tblbase;
long offs;
/* . . . . */
/*	ASL.w	#2, D0	convert index to offset */
   err = genASL(CWORD, E_IMM, 2, E_Dn|0, 0, 0);
/*	MOVE.l	JMPTBL-*-2(PC, D0.w), A1	get table entry */
   tblent = cap;
   err = genMOVEA(CLONG, E_pcXi, iDw(0), 0, E_An|1); /* fill in later */
/*	JMP	2(PC, A1.l)	add entry to PC, with adjustment */
   err = genJMP(E_pcXi, iAl(1), 2);
/* JMPTBL	EQU * */
   err = fillpcR(E_pcXi, tblent); /* calculate table offset and fill */
   tblbase = cap;
/*	DC.l	CODE1-JMPTBL */
   offs = ((long) CODE1) - ((long) tblbase);
   err = gcode((short) (offs >> 16));
   err = gcode((short) offs);
/*	DC.l	CODE2-JMPTBL 	etc. */

/* Move a constant length character string at s1 to s2, absolute addressed, */
/* one byte at a time (there are other ways to do this): */
char s1[STRLEN];
char s2[STRLEN];
CODE *L1;
/* . . . */
/* 	MOVE.w #STRLEN, D0 */
   err = genMOVE(CWORD, E_IMM, 0, STRLEN, E_Dn|0);
/*	MOVE.l #s1, A0 */
   err = genMOVE(CLONG, E_IMM, 0, (long) s1, E_An|0, 0, 0);
/*	MOVE.l #s2, A0 */
   err = genMOVE(CLONG, E_IMM, 0, (long) s2, E_An|1, 0, 0);
/* L1	MOVE.b (A0)+, (A1)+ */
   L1 = cap;
   err = genMOVE(CBYTE, E_InINC|0, 0, 0, E_InINC|1, 0, 0);
/*	DBRA	D0, L1 */
   err = genDB(cc_F, E_Dn|0, L1); /* Decrement and Branch until False */

/* there are several ways to push and pop (pull) registers: */
/*	using the auto modes: */
/*	MOVE.l	D1, -(A7)	push D1 */
   err = genMOVE(CLONG, E_Dn|1, 0, 0, E_InDEC|7, 0, 0);

/*	MOVE.b	(A7)+, CCR	pop (pull) the condition codes */
   err = genMOVE(CBYTE, E_InINC|7, 0, 0, E_CCR, 0, 0); /* pops a word */
/*	MOVE.b	(A4)+, CCR	pop (pull) the condition codes */
   err = genMOVE(CBYTE, E_InINC|4, 0, 0, E_CCR, 0, 0); /* pops a byte */

/* push an immediate value: */
/*	MOVE.w	#VALUE, -(A7) */
   err = genMOVE(CWORD, E_IMM, 0, VALUE, E_InDEC|7, 0, 0);

/* using the MOVE Multiple instruction: */
/*	MOVEM.l	A1/A3/A5/D2/D4, -(A7)	push a register list */
   err = genPUSH(CLONG, _PSH(E_An|1)|_PSH(E_An|3)|_PSH(E_An|5)
		 |_PSH(E_Dn|2)|_PSH(E_Dn|4), E_InDEC|7, 0, 0);

/*	MOVEM.w	D0-D4, (A6)+	pop a register list */
   err = genPULL(CWORD, E_InINC|6, 0, 0, _PUL(E_Dn|0)|_PUL(E_Dn|1)
		 |_PUL(E_Dn|2)|_PUL(E_Dn|3)|_PUL(E_Dn|4));

/* load a register list from a control table */
/*	MOVE.w	PROCNUM, D6
	MUL	#ENTSIZE, D6	convert entry number to offset
	LEA	CTLTBL, A5
	MOVE.w	0(A5, D6.l), SR
	MOVEM.l 6(A5, D6.l), A0-A7/D0-D7	wipes out index regs */
   err = genMOVE(CWORD, E_ABSw, 0, (long) PROCNUM, E_Dn|6, 0, 0);
   err = genMUL(E_IMM, 0, ENTSIZE, E_Dn|6);
   err = genLEA(E_ABSl, 0, (long) CTLTBL, E_An|5);
   err = genMOVE(CWORD, E_AnXi|5, iDl(6), 0, E_SR, 0, 0);
   err = genPULL(CLONG, E_AnXi|5, iDl(6), 6, 0xffff);

/* note that A7 is the hardware (flow of control) stack pointer.  Any
time a byte is pushed referencing A7, a word actually goes on the stack with
its most significant byte clear.
For the above methods of pushing and popping registers, any address register
may be used, but only A7 forces all pushes to word boundaries. */

**************************************************************************

On the AT&T PC-7300 (UNIX PC), sdb misreads certain obscure combinations
of machine codes and addressing modes:
	Scc to an absolute address (sdb says it's TRAPcc -- 68020 code)
	BTST Dn, #val
	ILLEGAL
	JSR to an absolute address (sdb says it's JSR immediate)
The code generator generated these codes correctly when I released it.

			Joel Matthew Rees
			(801) 486-4812 (Salt Lake City).