%{
/*
This file is an almost complete machine description file of the MC68000
family for the lburg code generator generator.  What's missing can be
easily filled in for a specific MC68k assembler.  A change must be made to
config.h in order to use this file.  The Xnode struct's kids field must be
enlarged to 4.  A completed version of this file forms the basis for the
MPW version of the lcc compiler targeted for the Apple Macintosh.  The code
emitted by this specification is for the Apple MPW Assembler which has a
syntax similar to Motorola's assembler. A major difference between this
lburg specification and the examples in the lcc distribution is that switch
statement tables are stored in the code segment and are addressed by the pc
relative addressing mode.

Registers A2-A7,D3-D7,FP4-FP7 are preserved across function calls.
Registers D0 and FP0 store function results.  Parameters are passed from
right to left on the stack.  All floating point values are first promoted
to Motorola extended format before being pushed on the stack.

Here are some benchmark results of some compilers available for the Apple
Macintosh.  The programs are similar to those found in the Hennessy suite.
MPW C is the Apple C compiler. Gcc is the MPW port of gcc version
1.37.1r15. SC is the Symantec C compiler (ex-Zortech with m68k backend).
SCG is the Symantec C compiler with all optimizations on.  This compiler
does global optimizations.  LCC is the lcc compiler produced with this
machine description file.  MW is the Metrowerks 68k C compiler from Code
Warrior.  All tests were run on a Macintosh Centris 650 with MC68040 @25MHz
using 020 addressing modes and FPU.

        MPW C   gcc     gcc -O  SC      SCG     LCC     MW opt
Perm     13     13       11     17      19      12        22
Towers   12     15       10     17      16      12        11
Queens    6      7        5     7        8       8         4
Intmm    19     18       16     18      11      19        17
Mm       17     19       16     18      10      20        18
Puzzle   68     86       48     74      35      74        47
Quick     8     10        5     13      11       8        14
Bubble   11     16        7     19      10      12        11
FFT      25     28       16     24      20      25        19

Hopefully this file will prove useful to those wishing to target lcc to
Atari's, Amiga's, Sun's and Next's.  Let me know if you retarget lcc to any
other m68k machines using this file.
Please report any bugs to:

Woodrow Yeung
yeung@reed.edu

*/
enum { D0, D1, D2, D3, D4, D5, D6, D7 };
enum { A0, A1, A2, A3, A4, A5, A6, A7 };
enum { FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7 };
#if 0
#define realparamsize 12
#endif
#ifndef AMIGA
#include "c.h"
#include <ctype.h>
#else
/* Work around some incompatibilities between system/lcc header files and
   <exec/types.h> */
#define SHORT	_SHORT
#define LONG	_LONG
#define FLOAT	_FLOAT
#define DOUBLE	_DOUBLE
#include "c.h"
#undef SHORT
#undef LONG
#undef FLOAT
#undef DOUBLE
#include <ctype.h>
#ifdef BITSPERBYTE
#undef BITSPERBYTE
#endif
#ifdef MAXINT
#undef MAXINT
#endif
#ifdef MININT
#undef MININT
#endif
#ifdef LONGBITS
#undef LONGBITS
#endif
#include <dos/dos.h>
#include <proto/dos.h>
#undef STATIC
#undef GLOBAL
#endif
#define NODEPTR_TYPE Node
#define OP_LABEL(p) ((p)->op)
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define STATE_LABEL(p) ((p)->x.state)
#define FILEPART(x) (strrchr((x),'/') ? strrchr((x),'/')+1 : \
		    (strrchr((x),':') ? strrchr((x),':')+1 : (x)))
static void address ARGS((Symbol, Symbol, int));
static void blkfetch    ARGS((int, int, int, int));
static void blkloop ARGS((int, int, int, int, int, int[]));
static void blkstore    ARGS((int, int, int, int));
static void defaddress  ARGS((Symbol));
static void defconst    ARGS((int, Value));
static void defstring   ARGS((int, char *));
static void defsymbol   ARGS((Symbol));
static void doarg   ARGS((Node));
static void emit2   ARGS((Node));
static void export  ARGS((Symbol));
static void clobber ARGS((Node));
static void function    ARGS((Symbol, Symbol [], Symbol [], int));
static void global  ARGS((Symbol));
static void import  ARGS((Symbol));
static void local   ARGS((Symbol));
static void progbeg ARGS((int, char **));
static void progend ARGS((void));
static void segment ARGS((int));
static void space   ARGS((int));
static void target  ARGS((Node));

static int sametree ARGS((Node, Node));
static int memop ARGS((Node));

static void symname ARGS((Symbol p));
static void stabend ARGS((Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *));
static void stabline ARGS((Coordinate *));

static Symbol ireg[32], *dreg = &ireg[0], areg[32], freg[32];
 
static int cseg;
 
%}
%start stmt
%term ADDD=306 ADDF=305 ADDI=309 ADDP=311 ADDU=310 ADDC=307 ADDS=308
%term ADDRFP=279
%term ADDRGP=263
%term ADDRLP=295
%term ARGB=41 ARGD=34 ARGF=33 ARGI=37 ARGP=39
%term ASGNB=57 ASGNC=51 ASGND=50 ASGNF=49 ASGNI=53 ASGNP=55 ASGNS=52 ASGNU=54
%term BANDU=390
%term BCOMU=406
%term BORU=422
%term BXORU=438
%term CALLB=217 CALLD=210 CALLF=209 CALLI=213 CALLV=216
%term CNSTC=19 CNSTD=18 CNSTF=17 CNSTI=21 CNSTP=23 CNSTS=20 CNSTU=22
%term CVCI=85 CVCU=86
%term CVDF=97 CVDI=101
%term CVFD=114
%term CVIC=131 CVID=130 CVIS=132 CVIU=134
%term CVPU=150
%term CVSI=165 CVSU=166
%term CVUC=179 CVUI=181 CVUP=183 CVUS=180
%term DIVD=450 DIVF=449 DIVI=453 DIVU=454
%term EQD=482 EQF=481 EQI=485
%term GED=498 GEF=497 GEI=501 GEU=502
%term GTD=514 GTF=513 GTI=517 GTU=518
%term INDIRB=73 INDIRC=67 INDIRD=66 INDIRF=65 INDIRI=69 INDIRP=71 INDIRS=68
%term JUMPV=584
%term LABELV=600
%term LED=530 LEF=529 LEI=533 LEU=534
%term LOADB=233 LOADC=227 LOADD=226 LOADF=225 LOADI=229 LOADP=231 LOADS=228 LOADU=230
%term LSHI=341 LSHU=342
%term LTD=546 LTF=545 LTI=549 LTU=550
%term MODI=357 MODU=358
%term MULD=466 MULF=465 MULI=469 MULU=470
%term NED=562 NEF=561 NEI=565
%term NEGD=194 NEGF=193 NEGI=197
%term RETD=242 RETF=241 RETI=245
%term RSHI=373 RSHU=374
%term SUBD=322 SUBF=321 SUBI=325 SUBP=327 SUBU=326 SUBC=323 SUBS=324
%term VREGP=615
%%
reg:  INDIRC(VREGP) "# read register\n"
reg:  INDIRD(VREGP) "# read register\n"
reg:  INDIRF(VREGP) "# read register\n"
reg:  INDIRI(VREGP) "# read register\n"
reg:  INDIRP(VREGP) "# read register\n"
reg:  INDIRS(VREGP) "# read register\n"
stmt: ASGNC(VREGP,reg)  "# write register\n"
stmt: ASGND(VREGP,reg)  "# write register\n"
stmt: ASGNF(VREGP,reg)  "# write register\n"
stmt: ASGNI(VREGP,reg)  "# write register\n"
stmt: ASGND(VREGP,reg)  "# write register\n"
stmt: ASGNP(VREGP,reg)  "# write register\n"
stmt: ASGNS(VREGP,reg)  "# write register\n"
con: CNSTC  "%#%a"
con: CNSTI  "%#%a"
con: CNSTP  "%#%a"
con: CNSTS  "%#%a"
con: CNSTU  "%#%a"
stmt: reg  ""
reg: CVIU(reg)  "%0"  notarget(a)
reg: CVUI(reg)  "%0"  notarget(a)
 
disp16: CNSTI   "%a"     range(a, -32768, 32767)
disp8:  CNSTI   "%a"     range(a, -128, 127)
 
base:  ADDP(reg,disp16) "%1(%0"
base:  ADDRFP   "%a(A5"  range(a, -32768, 32767)
base:  ADDRLP   "%a(A5"  range(a, -32768, 32767)
base:  basei    "%0"
basei: reg      "0(%0"
basei: ADDP(reg,disp8)   "%1(%0"
basei: ADDRFP   "%a(A5"  range(a, -128, 127)
basei: ADDRLP   "%a(A5"  range(a, -128, 127)
basei: ADDRFP   "0(%a,A5"  1
basei: ADDRLP   "0(%a,A5"  1

addr:  ADDRGP   "%a"
acon:  ADDRGP   "%a"
table: ADDRGP   "\tLEA %a,%c\n"

index: reg "%0"
index: LSHI(reg,scf)   "%0*%1"

addr: base    "%0)"
 
addr: ADDP(index,basei) "%1,%0)"
case: ADDP(index,table) "0(%1,%0)"
 
avar: acon     "%0"
avar: reg      "(%0)"  1
avar: addr     "%0"    2
 
con0:  CNSTI "%#0"   range(a, 0, 0)
con0:  CNSTP "%#0"   range(a, 0, 0)
con0:  CNSTU "%#0"   range(a, 0, 0)
con3:  CNSTI "%#%a"  range(a, 1, 8)
con3:  CNSTP "%#%a"  range(a, 1, 8)

scf:  CNSTI "2"     range(a, 1, 1)
scf:  CNSTI "4"     range(a, 2, 2)
scf:  CNSTI "8"     range(a, 3, 3)
 
mem: INDIRI(addr)  "%0"
mem: INDIRP(addr)  "%0"
 
pcrel: INDIRP(case) "\tMOVE.L %0,%c\n"
 
ri:   reg  "%0"
ri:   con  "%0"
ri3:  con3 "%0"
ri3:  reg  "%0"
 
ea0: mem  "%0"
ea0: ri   "%0"
ea1: mem  "%0"  1
ea1: ri   "%0"
ea3: mem  "%0"  3
ea3: ri   "%0"
 
reg:  addr    "\tLEA %0,%c\n"    1
reg:  ri      "\tMOVE.L %0,%c\n" 1
reg: INDIRC(addr)  "\tMOVE.B %0,%c\n"  1
reg: INDIRI(addr)  "\tMOVE.L %0,%c\n"  1
reg: INDIRP(addr)  "\tMOVE.L %0,%c\n"  1
reg: INDIRS(addr)  "\tMOVE.W %0,%c\n"  1
 
reg:  LOADC(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg:  LOADI(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg:  LOADP(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg:  LOADS(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg:  LOADU(reg)  "\tMOVE.L %0,%c\n"  move(a)
 
reg:  ADDI(reg,con3)  "?\tMOVE.L %0,%c\n\tADDQ.L %1,%c\n"
reg:  SUBI(reg,con3)  "?\tMOVE.L %0,%c\n\tSUBQ.L %1,%c\n"
 
reg:  ADDI(reg,ea1)  "?\tMOVE.L %0,%c\n\tADD.L %1,%c\n"  1
reg:  ADDP(reg,ea1)  "?\tMOVE.L %0,%c\n\tADDA.L %1,%c\n" 1
reg:  ADDU(reg,ea1)  "?\tMOVE.L %0,%c\n\tADD.L %1,%c\n"  1
reg:  SUBI(reg,ea1)  "?\tMOVE.L %0,%c\n\tSUB.L %1,%c\n"  1
reg:  SUBP(reg,ea1)  "?\tMOVE.L %0,%c\n\tSUBA.L %1,%c\n" 1
reg:  SUBU(reg,ea1)  "?\tMOVE.L %0,%c\n\tSUB.L %1,%c\n"  1
 
stmt: ASGNI(addr,ADDI(mem,ri))  "\tADD.L %2,%1\n"  memop(a)
stmt: ASGNI(addr,ADDU(mem,ri))  "\tADD.L %2,%1\n"  memop(a)
stmt: ASGNI(addr,SUBI(mem,ri))  "\tSUB.L %2,%1\n"  memop(a)
stmt: ASGNI(addr,SUBU(mem,ri))  "\tSUB.L %2,%1\n"  memop(a)
 
reg: BANDU(reg,ea1)  "?\tMOVE.L %0,%c\n\tAND.L %1,%c\n"  1
reg: BORU(reg,ea1)   "?\tMOVE.L %0,%c\n\tOR.L %1,%c\n"   1
reg: BXORU(reg,reg)  "?\tMOVE.L %0,%c\n\tEOR.L %1,%c\n"  1
 
stmt: ASGNI(addr,BANDU(mem,ri))  "\tAND.L %2,%1\n"   memop(a)
stmt: ASGNI(addr,BORU(mem,ri))   "\tOR.L %2,%1\n"    memop(a)
stmt: ASGNI(addr,BXORU(mem,reg))  "\tEOR.L %2,%1\n"   memop(a)
 
reg: BCOMU(reg)  "?\tMOVE.L %0,%c\n\tNOT.L %c\n"  1
reg: NEGI(reg)   "?\tMOVE.L %0,%c\n\tNEG.L %c\n"  1
  
stmt: ASGNI(addr,BCOMU(mem))  "\tNOT.L %1\n"  memop(a)
stmt: ASGNI(addr,NEGI(mem))   "\tNEG.L %1\n"  memop(a)
 
reg: LSHI(reg,ri3)  "?\tMOVE.L %0,%c\n\tASL.L %1,%c\n"  1
reg: LSHU(reg,ri3)  "?\tMOVE.L %0,%c\n\tLSL.L %1,%c\n"  1
reg: RSHI(reg,ri3)  "?\tMOVE.L %0,%c\n\tASR.L %1,%c\n"  1
reg: RSHU(reg,ri3)  "?\tMOVE.L %0,%c\n\tLSR.L %1,%c\n"  1
 
reg: MULI(reg,ea3)  "?\tMOVE.L %0,%c\n\tMULS.L %1,%c\n"   12
reg: MULU(reg,ea3)  "?\tMOVE.L %0,%c\n\tMULU.L %1,%c\n"   12
 
reg: DIVU(reg,ea3)  "?\tMOVE.L %0,%c\n\tDIVU.L %1,%c\n"
reg: DIVI(reg,ea3)  "?\tMOVE.L %0,%c\n\tDIVS.L %1,%c\n"
reg: MODU(reg,ea3)  "\tMOVE.L %0,D1\n\tCLR.L %c\n\tDIVU.L %1,%c:D1\n"
reg: MODI(reg,reg)  "#\tCLR.L %c\n\tDIVS.L %1,%0\n"
 
reg: CVCI(reg)  "\tMOVE.B %0,%c\n\tEXT.W %c\n\tEXT.L %c\n" 2
reg: CVCU(reg)  "\tMOVE.B %0,%c\n\tAND.L #$FF,%0\n"        3
reg: CVSI(reg)  "\tMOVE.W %0,%c\n\tEXT.L %c\n"             1
reg: CVSU(reg)  "\tMOVE.W %0,%c\n\tAND.L #$FFFF,%0\n"      3
reg: CVCI(INDIRC(addr))  "\tMOVE.B %0,%c\n\tEXT.W %c\n\tEXT.L %c\n" 2
reg: CVCU(INDIRC(addr))  "\tMOVE.B %0,%c\n\tANDI.L #$ff,%c\n"    2
reg: CVSI(INDIRS(addr))  "\tMOVE.W %0,%c\n\tEXT.L %c\n"          2
reg: CVSU(INDIRS(addr))  "\tMOVE.W %0,%c\n\tANDI.L #$ffff,%c\n"  2
reg: CVIC(reg)  "%0"  notarget(a)
reg: CVIS(reg)  "%0"  notarget(a)
reg: CVUC(reg)  "%0"  notarget(a)
reg: CVUS(reg)  "%0"  notarget(a)
reg: CVIC(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg: CVIS(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg: CVIU(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg: CVPU(reg)  "\tMOVE.L %0,%c\n"
reg: CVUC(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg: CVUI(reg)  "\tMOVE.L %0,%c\n"  move(a)
reg: CVUP(reg)  "\tMOVE.L %0,%c\n"
reg: CVUS(reg)  "\tMOVE.L %0,%c\n"  move(a)
 
reg: CVDF(reg)  "%0"  notarget(a)
reg: CVFD(reg)  "%0"  notarget(a)
reg: CVDF(reg)  "\tFMOVE.D %0,%c\n" move(a)
reg: CVFD(reg)  "\tFMOVE.D %0,%c\n" move(a)
reg: CVID(ea0)  "\tFMOVE.L %0,%c\n"
reg: CVDI(reg)  "\tFMOVE.L %0,%c\n"
 
stmt: ASGNC(addr,ea1)  "\tMOVE.B %1,%0\n"    1
stmt: ASGNC(addr,con0)  "\tCLR.L %0\n"
stmt: ASGNI(addr,ea1)  "\tMOVE.L %1,%0\n"    1
stmt: ASGNI(addr,con0)  "\tCLR.L %0\n"
stmt: ASGNI(addr,CVDI(reg))  "\tFMOVE.L %1,%0\n"
stmt: ASGNP(addr,ea1)  "\tMOVE.L %1,%0\n"    1
stmt: ASGNP(addr,con0)  "\tCLR.L %0\n"
stmt: ASGNS(addr,ea1)  "\tMOVE.W %1,%0\n"    1
stmt: ASGNS(addr,con0)  "\tCLR.W %0\n"
 
stmt: ARGI(ea0)   "\tMOVE.L %0,-(SP)\n"  1
stmt: ARGI(addr)  "\tPEA.L %0\n"         1
stmt: ARGP(ea0)   "\tMOVE.L %0,-(SP)\n"  1
stmt: ARGP(addr)  "\tPEA.L %0\n"         1
stmt: ASGNB(reg, INDIRB(reg)) "# MOVE (src)+,(dst)+\n" 2
stmt: ARGB(INDIRB(reg))  "# Copy to stack\n" 2
 
reg: LOADD(reg)        "\tFMOVE.D %0,%c\n"   move(a)
reg: LOADF(reg)        "\tFMOVE.D %0,%c\n"   move(a)
 
reg: INDIRD(addr)      "\tFMOVE.D %0,%c\n"   3
reg: INDIRF(addr)      "\tFMOVE.S %0,%c\n"   3
mem: INDIRD(addr)      "%0"
mem: INDIRF(addr)      "%0"
 
stmt: ASGND(addr,reg)  "\tFMOVE.D %1,%0\n"  4
stmt: ASGND(addr,mem)  "\tLEA.L %1,A0\n\tLEA.L %0,A1\n\tMOVE.L (A0)+,(A1)+\n\tMOVE.L (A0),(A1)\n"  3
stmt: ASGNF(addr,reg)  "\tFMOVE.S %1,%0\n"  4
stmt: ASGNF(addr,mem)  "\tMOVE.L %1,%0\n"   1
stmt: ARGD(reg)        "\tFMOVE.D %0,-(SP)\n" 3
stmt: ARGF(reg)        "\tFMOVE.D %0,-(SP)\n" 3
 
reg: ADDD(reg,reg)  "?\tFMOVE.D %0,%c\n\tFADD.D %1,%c\n"
reg: ADDF(reg,reg)  "?\tFMOVE.D %0,%c\n\tFADD.D %1,%c\n"
reg: SUBD(reg,reg)  "?\tFMOVE.D %0,%c\n\tFSUB.D %1,%c\n"
reg: SUBF(reg,reg)  "?\tFMOVE.D %0,%c\n\tFSUB.D %1,%c\n"
reg: MULD(reg,reg)  "?\tFMOVE.D %0,%c\n\tFMUL.D %1,%c\n"
reg: MULF(reg,reg)  "?\tFMOVE.D %0,%c\n\tFMUL.D %1,%c\n"
reg: DIVD(reg,reg)  "?\tFMOVE.D %0,%c\n\tFDIV.D %1,%c\n"
reg: DIVF(reg,reg)  "?\tFMOVE.D %0,%c\n\tFDIV.D %1,%c\n"
 
reg: NEGD(reg)  "\tFNEG.D %c\n"
reg: NEGF(reg)  "\tFNEG.D %c\n"
 
stmt:  JUMPV(acon)    "\tBRA.L %0\n"
stmt:  JUMPV(pcrel)   "\tJMP 0(%0)\n"
stmt:  LABELV         "%a:\n"
 
stmt: EQI(ea0,con0)  "\tTST.L %0\n\tBEQ.L %a\n"   2
stmt: NEI(ea0,con0)  "\tTST.L %0\n\tBNE.L %a\n"   2

stmt: EQI(reg,ea1)  "\tCMP.L %1,%0\n\tBEQ.L %a\n"   3
stmt: GEI(reg,ea1)  "\tCMP.L %1,%0\n\tBGE.L %a\n"   3
stmt: GTI(reg,ea1)  "\tCMP.L %1,%0\n\tBGT.L %a\n"   3
stmt: LEI(reg,ea1)  "\tCMP.L %1,%0\n\tBLE.L %a\n"   3
stmt: LTI(reg,ea1)  "\tCMP.L %1,%0\n\tBLT.L %a\n"   3
stmt: NEI(reg,ea1)  "\tCMP.L %1,%0\n\tBNE.L %a\n"   3
 
stmt: GEU(reg,ea1)  "\tCMP.L %1,%0\n\tBHS.L %a\n"   3
stmt: GTU(reg,ea1)  "\tCMP.L %1,%0\n\tBHI.L %a\n"   3
stmt: LEU(reg,ea1)  "\tCMP.L %1,%0\n\tBLS.L %a\n"   3
stmt: LTU(reg,ea1)  "\tCMP.L %1,%0\n\tBLO.L %a\n"   3
 
stmt: EQD(reg,reg)  "\tFCMP.D %1,%0\n\tFBEQ.W %a\n"
stmt: GED(reg,reg)  "\tFCMP.D %1,%0\n\tFBGE.W %a\n"
stmt: GTD(reg,reg)  "\tFCMP.D %1,%0\n\tFBGT.W %a\n"
stmt: LED(reg,reg)  "\tFCMP.D %1,%0\n\tFBLE.W %a\n"
stmt: LTD(reg,reg)  "\tFCMP.D %1,%0\n\tFBLT.W %a\n"
stmt: NED(reg,reg)  "\tFCMP.D %1,%0\n\tFBNE.W %a\n"
 
stmt: EQF(reg,reg)  "\tFCMP.D %1,%0\n\tFBEQ.W %a\n"
stmt: GEF(reg,reg)  "\tFCMP.D %1,%0\n\tFBGE.W %a\n"
stmt: GTF(reg,reg)  "\tFCMP.D %1,%0\n\tFBGT.W %a\n"
stmt: LEF(reg,reg)  "\tFCMP.D %1,%0\n\tFBLE.W %a\n"
stmt: LTF(reg,reg)  "\tFCMP.D %1,%0\n\tFBLT.W %a\n"
stmt: NEF(reg,reg)  "\tFCMP.D %1,%0\n\tFBNE.W %a\n"
 
reg:  CALLI(avar)   "\tJSR %0\n\tADDA.L %#%a,SP\n"
stmt: CALLV(avar)   "\tJSR %0\n\tADDA.L %#%a,SP\n"
reg:  CALLF(avar)   "\tJSR %0\n\tADDA.L %#%a,SP\n"
reg:  CALLD(avar)   "\tJSR %0\n\tADDA.L %#%a,SP\n"
 
stmt: RETI(reg)    "# RTS\n"
stmt: RETF(reg)    "# RTS\n"
stmt: RETD(reg)    "# RTS\n"
 
%%
static void progend() {
  print( "\tend\n" ) ;
  }

static void segment(n) {
  switch( n ) {
    case CODE : print( "\tSECTION text,code\n" ) ; break ;
    case BSS  : print( "\tSECTION udata,bss\n"  ) ; break ;
    case DATA : print( "\tSECTION data,data\n" ) ; break ;
    case LIT  : print( "\tSECTION data,data\n"  ) ; break ;
    }
}

/* Mark nodes that must be evaluated into a specific register (p. 357)
 */
static void target(p) Node p; {
    assert(p);
    switch (p->op) {
    case ASGNB:
        rtarget(p, 1, areg[A0+8]); /* A0 Source */
        rtarget(p, 0, areg[A1+8]); /* A1 Destination */
        break;
    case ARGB:
            rtarget(p->kids[0], 0, areg[A0+8]); /* A0 Source */
        break;
    case CALLI: case CALLV:
            setreg(p, dreg[D0]);
        break;
    case CALLD: case CALLF:
            setreg(p, freg[FP0]);
            break;
    case RETI:
        rtarget(p, 0, ireg[D0]);
        break;
    case RETF: case RETD:
            rtarget(p, 0, freg[FP0]);
        break;
    }
}
 
/* spills to memory and later reloads all registers destroyed by a
 * given function (p. 357)
 */
static void clobber(p) Node p; {
    assert(p);
    switch (p->op) {
    case MULI: case MULU:
        break;
    case DIVI: case DIVU:
        break;
    case MODI: case MODU:
        spill(1<<D1, IREG, p);
        break;
    case ASGND:
        spill(1<<D0 | 1<<A0+8 | 1<<A1+8, IREG, p);
        break;
    case ASGNB: case ARGB:
        spill(1<<D0 | 1<<A0+8 | 1<<A1+8, IREG, p);
        break;
    case CALLI:
            /* save scratch registers but not return register */
        spill(1<<D1 | 1<<D2 | 1<<A0+8 | 1<<A1+8, IREG, p);
        spill(1<<FP0 | 1<<FP1 | 1<<FP2 | 1<<FP3, FREG, p);
        break;
    case CALLV:
            /* save scratch registers */
        spill(1<<D0 | 1<<D1 | 1<<D2 | 1<<A0+8 | 1<<A1+8, IREG, p);
        spill(1<<FP0 | 1<<FP1 | 1<<FP2 | 1<<FP3, FREG, p);
        break;
            break;
    case CALLD: case CALLF:
            /* save scratch registers but not return register */
        spill(1<<D0 | 1<<D1 | 1<<D2 | 1<<A0+8 | 1<<A1+8, IREG, p);
        spill(1<<FP1 | 1<<FP2 | 1<<FP3, FREG, p);
        break;
    }
}

/* confirms that the destination is the same as the first source operand
 * (p. 507)
 */
static int sametree(p, q) Node p, q; {
    return p == 0 && q == 0
    || p && q && p->op == q->op && p->syms[0] == q->syms[0]
        && sametree(p->kids[0], q->kids[0]) && sametree(p->kids[1], q->kids[1]);

}
 
/* confirms that the tree has the form ASGNa( x, b(INDIR(x), c)) (p. 507)
 */
static int memop(p) Node p; {
    assert(p);
    assert(generic(p->op) == ASGN);
    assert(p->kids[0]);
    assert(p->kids[1]);
    if (generic(p->kids[1]->kids[0]->op) == INDIR) {
        assert(p->kids[1]->kids[0]);
        return sametree(p->kids[0], p->kids[1]->kids[0]->kids[0]) ? 2 : SHRT_MAX
;
    } else
        return SHRT_MAX;
}

/* Deals with instructions that cannot be handled with simple templates.
 * (p. 356)
 */
static void emit2(p) Node p; {
    switch(p->op) {
    case ASGNB: {
        int lab1 = genlabel(1), lab2 = genlabel(1);
        int src = getregnum(p->x.kids[1]), dst = getregnum(p->x.kids[0]);
        int size = p->syms[0]->u.c.v.i;
        
        if(size % 2)
            print("\tMOVE.L %#%d,D0\n", size);
        else
            print("\tMOVE.L %#%d,D0\n", size / 2);
        print("\tBRA.S .%d\n", lab2);
        print(".%d:\n", lab1);
        if(size % 2)
            print("\tMOVE.B (A%d)+,(A%d)+\n", src, dst);
        else
            print("\tMOVE.W (A%d)+,(A%d)+\n", src, dst);
        print(".%d:\n", lab2);
        print("\tDBF.W D0,.%d\n", lab1);
        break;
        }
    case ARGB: {
        int lab1 = genlabel(1), lab2 = genlabel(1);
        int size = p->syms[0]->u.c.v.i, src = getregnum(p->x.kids[0]);
        
        if(size % 2) ++size;
        print("\tSUBA.L %#%d,SP\n", size);
        print("\tMOVE.L SP,A1\n");
        print("\tMOVE.L %#%d,D0\n", size / 2);
        print("\tBRA.S .%d\n", lab2);
        print(".%d:\n", lab1);
        print("\tMOVE.W (A%d)+,(A1)+\n", src);
        print(".%d:\n", lab2);
        print("\tDBF.W D0,.%d\n", lab1);
        }
        break;
    case MODI: {
        int lab1 = genlabel(1);
        int rem = getregnum(p), quo = getregnum(p->x.kids[0]);
        int divisor = getregnum(p->x.kids[1]);
	print("\tMOVEQ.L #-1,D%d\n", D1);
	print("\tMOVE.L #31,D%d\n", D2);
	print("\tBTST.L D%d,D%d\n", D2, quo);
	print("\tBNE.S .%d\n", lab1);
	print("\tCLR.L D%d\n", D1);
	print(".%d:\n", lab1);
#if 0
  	print("\tDIVS.L D%d,D%d:D%d\n", divisor, D1, rem);
#else
	print("\tDIVS.L D%d,D%d:D%d\n", divisor, D1, quo);
#endif
	print("\tMOVE.L D%d,D%d\n", D1, rem);
        break;
        }
    }
}


/* Compute the register or stack cell assigned to the next argument (p. 356)
 */
static void doarg(p) Node p; {
    assert(p && p->syms[0]);
        switch(p->op) {
#if 0
        case ARGD: case ARGF:
            mkactual(2,realparamsize); /* pass all floats as extended which are 96-bits */
            break;
#endif
        default:
        mkactual(2, p->syms[0]->u.c.v.i);
    }
}

/* load register tmp with k bytes from off(reg) (p. 356) */
static void blkfetch(k, off, reg, tmp) {
  assert(0) ;
}

/* store k bytes from register tmp  at off(reg) (p. 356) */
static void blkstore(k, off, reg, tmp) {
  assert(0) ;
}

/* emit a loop to copy size bytes from soff(sreg) to doff(dreg) using the
 * 3 temporary registers in tmps (p. 356)
 */
static void blkloop(dreg, doff, sreg, soff, size, tmps)
    int tmps[]; {
  assert(0) ;
}

/* called by the front end to announce a local variable (p. 90) */
static void local(p) Symbol p; {
    if (askregvar(p, rmap[ttob(p->type)]) == 0)
        mkauto(p);
}

/* initialize prolog and epilog code (p. 93) */
static void function(f, caller, callee, n)
Symbol f, callee[], caller[]; {
    int i, count, acount, inseq;
        char reglist[256];
        char temp[4];

    print("%s:\n", f->x.name);
#ifdef AMIGA
    if (glevel > 1) {
        print("\tDEBUG\t%d\n",f->src.y);
    }
#endif

    usedmask[0] = usedmask[1] = 0;
    freemask[0] = freemask[1] = ~(unsigned)0;
    offset = 4 + 4; /* FP and return address */
    for (i = 0; callee[i]; i++) {
        Symbol p = callee[i];
        Symbol q = caller[i];
        assert(q);
        p->x.offset = q->x.offset = offset;
        p->x.name = q->x.name = stringf("%d", p->x.offset);
        p->sclass = q->sclass = AUTO;
#if 0
        if( p->type == floattype || p->type == doubletype)
            offset += roundup(realparamsize, 2);
        else
#endif
            offset += roundup(q->type->size, 2);
    }
    assert(caller[i] == 0);
    offset = maxoffset = 0;
    gencode(caller, callee);
    framesize = roundup(maxoffset, 2);
    
    if (framesize > 0)
        print("\tLINK A5,#%d\n", -framesize);
    else
        print("\tLINK A5,#0\n");
        
    /* format save register mask */
    reglist[0]= 0;
    count = acount = inseq = 0;
    for(i=D3;i<=D7;++i) {       
        if(usedmask[IREG] & (1<<i)) {
            if(count==0) {
                reglist[0] = 'D';
                reglist[1] = i + '0';
                reglist[2] = 0;
            } else if(!inseq) {
                temp[0] = '/';
                temp[1] = 'D';
                temp[2] = i + '0';
                temp[3] = 0;
                strcat(reglist,temp);
            }
            inseq++; count++;
        } else {
            if(inseq>1) {
                temp[0] = '-';
                temp[1] = 'D';
                temp[2] = i - 1 + '0';
                temp[3] = 0;
                strcat(reglist,temp);
            }
            inseq = 0;
        }
    }
    if(inseq>1) {
        temp[0] = '-';
        temp[1] = 'D';
        temp[2] = '7';
        temp[3] = 0;
        strcat(reglist,temp);
    }

    if(usedmask[IREG] & ((1<<A2+8) | (1<<A3+8) | (1<<A4+8))) {
        i = 0;
        if(count)
            temp[i++] = '/';
        temp[i] = 0;
        if(i)
            strcat(reglist, temp);

        acount = inseq = 0;
        for(i=A2;i<=A4;++i) {       
            if(usedmask[IREG] & (1<<i+8)) {
                if(acount==0) {
                    temp[0] = 'A';
                    temp[1] = i + '0';
                    temp[2] = 0;
                    strcat(reglist,temp);
                } else if(!inseq) {
                    temp[0] = '/';
                    temp[1] = 'A';
                    temp[2] = i + '0';
                    temp[3] = 0;
                    strcat(reglist,temp);
                }
                inseq++; acount++;
            } else {
                if(inseq>1) {
                    temp[0] = '-';
                    temp[1] = 'A';
                    temp[2] = i - 1 + '0';
                    temp[3] = 0;
                    strcat(reglist,temp);
                }
                inseq = 0;
            }
        }
        if(inseq>1) {
            temp[0] = '-';
            temp[1] = 'A';
            temp[2] = '4';
            temp[3] = 0;
            strcat(reglist,temp);
        }
    }
    
    count += acount;
    if(count > 1)
        print("\tMOVEM.L %s,-(SP)\n", reglist);
    else if(count == 1)
        print("\tMOVE.L %s,-(SP)\n", reglist);

    /* save floating point regs */
    for(i=FP4;i<=FP7;++i)
        if(usedmask[FREG] & (1<<i)) {
            print("\tFMOVE.D FP%d,-(SP)\n", i);
        }

    /* convert extended to declared format; FP1 is scratch register */
#if 0
    for (i = 0; callee[i]; i++) {
        Symbol p = callee[i];
        if(p->type == floattype) {
        print("\tFMOVE.X %d(A5),FP1\n", p->x.offset);
        print("\tFMOVE.S FP1,%d(A5)\n", p->x.offset);
        }
        else if(p->type == doubletype) {
        print("\tFMOVE.X %d(A5),FP1\n", p->x.offset);
        print("\tFMOVE.D FP1,%d(A5)\n", p->x.offset);
        }
    }
#endif

    emitcode();
    
    for(i=FP7;i>=FP4;--i)
        if(usedmask[FREG] & (1<<i)) {
            /* pop saved float regs */
            print("\tFMOVE.D (SP)+,FP%d\n", i);
        }
    if(count > 1)
        print("\tMOVEM.L (SP)+,%s\n", reglist);
    else if(count == 1)
        print("\tMOVE.L (SP)+,%s\n", reglist);

    print("\tUNLK A5\n");
    print("\tRTS\n");
}

/* called by the front end when a symbol is defined, so that the Xsymbol
 * field can be initialized (p. 89)
 *
 * JOOP: added cfunc->name to label construction, to aid debugging
 *       27-12-95: found a horrible bug and fixed it!
 */
static void defsymbol(p) Symbol p; {
    if (p->scope >= LOCAL && p->sclass == STATIC)
        p->x.name = stringf("%s_L.%d", cfunc->name, genlabel(1));
    else if (p->generated)
		if(cfunc)
	        p->x.name = stringf("%s_L.%s", cfunc->name, p->name);
		else
	        p->x.name = stringf("L.%s", p->name);
    else if (p->scope == GLOBAL || p->sclass == EXTERN)
        p->x.name = stringf("_%s", p->name);
    else if (p->scope == CONSTANTS
    && (isint(p->type) || isptr(p->type))
    && p->name[0] == '0' && p->name[1] == 'x')
        p->x.name = stringf("$%s", &p->name[2]); /* hex */
    else
        p->x.name = p->name;
}

static void address(q, p, n) Symbol q, p; int n; {
    if (p->scope == GLOBAL
    || p->sclass == STATIC || p->sclass == EXTERN)
        q->x.name = stringf("%s%s%d",
            p->x.name, n >= 0 ? "+" : "", n);
    else {
        q->x.offset = p->x.offset + n;
        q->x.name = stringd(q->x.offset);
    }
}
static void defconst(ty, v) Value v; {
    switch (ty) {
        case C: print("\tDC.B %d\n",    v.uc); return;
        case S: print("\tDC.W %d\n",    v.ss); return;
        case I: print("\tDC.L %d\n",   v.i ); return;
        case U: print("\tDC.L $%x\n", v.u ); return;
        case P: print("\tDC.L $%x\n", v.p ); return;
        case F:
            print("\tDC.L $%x\n", *(unsigned *)&v.f);
            return;
        case D: {
            unsigned *p = (unsigned *)&v.d;
	    print("\tDC.L $%x\n", p[swap]);
	    print("\tDC.L $%x\n", p[1 - swap]);
            return;
            }
    }
    assert(0);
}
static void defaddress(p) Symbol p; {
  print( "\tdc.l\t%s\t; defaddress\n", p->x.name ) ;
  }

static void defstring(n, str) int n; char *str; {
  char *s; int count = 0, instr = 0 ;

  print( "*\tdefstring\n" ) ;
  print( "\tdc.b\t" ) ;
  for (s = str; s < str + n; s++) {
    int c = (*s) & 0377 ;
    if( count == 40 ) {
      print( instr ? "'\n\tdc.b\t" : "\n\tdc.b\t" ) ; instr = count = 0 ;
      }
    if( isprint(c) && c != '\'' && c != '\\' && c!= '"') {
      if( !instr && count > 0 ) print( "," ) ;
      print( instr ? "%c" : "'%c", c ) ; instr = 1 ;
      }
    else {
      if( instr ) print( "'" ) ;
      if( count > 0 ) print( "," ) ;
      print( "%d", c ) ;
      instr = 0 ;
      }
    count++ ;
    }
  print( instr ? "'\n" : "\n" ) ;
  }

static void export(p) Symbol p; {
  print( "\txdef\t%s\n", p->x.name ) ;
  }
static void import(p) Symbol p; {
  if( p->ref > 0 ) 
    print( "\txref\t%s\n", p->x.name ) ;
  }
static void global(p) Symbol p; {
  if( p->type->align > 1 )
    print( "\tcnop\t0,%d\n", p->type->align ) ;
  print( "%s:\n", p->x.name ) ;
  }

static void space(n) {
#if 0
  int i ;

  print( "*\tspace(%d)\n", n ) ;
  while( n >= 16 ) {
    print( "\tdc.b\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n" ) ;
    n -= 16 ;
    }

  if( n == 0 ) return ;
  print( "\tdc.b\t0" ) ; n-- ;
  while( n > 0 )
    { print( ",0" ) ; n-- ; }
  print( "\n" ) ;
#else
  print( "*\tspace(%d)\n", n ) ;
  print( "\tDS.B %d\n", n);
#endif
  }

Interface m68kIR = {
    1, 1, 0,    /* char */
    2, 2, 0,    /* short */
    4, 2, 0,    /* int */
    4, 2, 1,    /* float */
    8, 2, 1,    /* double */
    4, 2, 0,    /* T * */
    0, 2, 0,    /* struct so that ARGB keeps stack aligned */
    0,      /* little_endian */
    0,      /* mulops_calls */
    0,      /* wants_callb */
    1,      /* wants_argb */
    0,      /* left_to_right */
    0,      /* wants_dag */
    address,
    blockbeg,
    blockend,
    defaddress,
    defconst,
    defstring,
    defsymbol,
    emit,
    export,
    function,
    gen,
    global,
    import,
    local,
    progbeg,
    progend,
    segment,
    space,
    0,
    stabend,
    0,
    0,
    stabline,
    0,
    0,
    {1, blkfetch, blkstore, blkloop,
        _label,
        _rule,
        _nts,
        _kids,
        _opname,
        _arity,
        _string,
        _templates,
        _isinstruction,
        _ntname,
        emit2,
        doarg,
        target,
        clobber,
         }
};

/* symname - print prefix, p's name, declaration source coordinate, suffix */
static void symname(p) Symbol p; {
	if (p)
		print("%s@%w.%d", p->name, &p->src, p->src.x);
	else
		print("0");
}

/* stabend - finalize stab output */
/* JOOP: currently not needed ??? */
static void stabend(cp, p, cpp, sp, stab) Coordinate *cp, **cpp; Symbol p, *sp, *stab; {
#if 0
	int i;

	symname(p);
	print("\n");
	if (cpp && sp)
		for (i = 0; cpp[i] && sp[i]; i++) {
			print("%w.%d: ", cpp[i], cpp[i]->x);
			symname(sp[i]);
			print("\n");
		}
#endif
}

/* stabline - emit line number information for source coordinate *cp */
/* JOOP: example output this generates when '-g' is used
 *       ;mod.c:14.1:		printf("second case %d\n",c%b);
 *       Suggestions whether or not the line info should stay are welcome
 *
 *       Source level debugging now works! with Bdebug from Barfly atleast
 *       If only -g is specified then only source level debug is active
 *       if you specify -g9 then the C-source will also be printed to the
 *       assembler file.
 */
static void stabline(cp) Coordinate *cp; {
	if(glevel == 1 && annotate == 1)
		print(";%s\n",cp->source_line);
	else if (glevel>1 && annotate) {
		print("\tDEBUG\t%d\n",cp->y);
		print(";%s\n",cp->source_line);
	}
	else 
		print("\tDEBUG\t%d\n",cp->y);
}

char *input_file = "";

static void progbeg(argc, argv) char *argv[]; {
    int i;

    {
        union {
            char c;
            int i;
        } u;
        u.i = 0;
        u.c = 1;
        swap = (u.i == 1) != IR->little_endian;
    }
    parseflags(argc, argv);

    for(i=0;i<argc;++i) {
    }

    for (i = 0; i < 8; i++)
        ireg[i] = mkreg("D%d", i, 1, IREG);
    for (i = A0; i < A7; i++)
        areg[i+8] = mkreg("A%d", i, 0x100, IREG);
    for (i = 0; i < 8; i++)
        freg[i] = mkreg("FP%d", i, 1, FREG);
        
    rmap[C] = rmap[S] = rmap[B] = rmap[U] = rmap[I] = mkwildcard(dreg);
    rmap[P] = mkwildcard(areg);
    rmap[F] = rmap[D] = mkwildcard(freg);
     
    tmask[IREG] =   (1<<D0) | (1<<D1) | (1<<D2) | (1<<D3) |
                    (1<<D4) | (1<<D5) | (1<<D6) | (1<<D7) | /* D0-D7/A0-A4 */
                    (1<<A0+8) | (1<<A1+8) | (1<<A2+8) | (1<<A3+8) | (1<<A4+8);
    /*vmask[IREG] =   (1<<D3) | (1<<D4) | (1<<D5) | 
                    (1<<A2+8) | (1<<A3+8) | (1<<A4+8); */
    tmask[FREG] = (1<<FP0) | (1<<FP1) | (1<<FP2) | (1<<FP3);
    /* vmask[FREG] = (1<<FP4) | (1<<FP5) | (1<<FP6) | (1<<FP7); */
    
    print("\tMACHINE\t68030\n");
    print("\tFPU\n") ;
    if (!firstfile) {
      firstfile = input_file;
    }
    print("\tIDNT\t%s\n", FILEPART(firstfile));

    if (glevel > 1) {
#ifdef AMIGA

	BPTR fh_lock;
	char namebuffer[256]; /* FILENAME_MAX=4096 in stdio.h, way too big ? */

	fh_lock=Lock((unsigned char *)firstfile, ACCESS_READ);
	if(fh_lock)    /* got the lock, now get the complete path/filename */
	{              /* should never fail but better safe then sorry     */
		NameFromLock(fh_lock, (unsigned char *)namebuffer,
			     sizeof(namebuffer));
	    print("\tDSOURCE\t%s\n", namebuffer);
		UnLock(fh_lock);
	}
    else /* in case it fails, use the file name currently being compiled */
#endif	/* AMIGA */
	    print("\tDSOURCE\t%s\n", firstfile);
    }
    cseg = 0;
}
