%{
/*
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 };
#define realparamsize 12
#include "c.h"
#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)
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 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(A6"  range(a, -32768, 32767)
base:  ADDRLP   "%a(A6"  range(a, -32768, 32767)
base:  basei    "%0"
basei: reg      "(%0"
basei: ADDP(reg,disp8)   "%1(%0"
basei: ADDRFP   "%a(A6"  range(a, -128, 127)
basei: ADDRLP   "%a(A6"  range(a, -128, 127)
basei: ADDRFP   "(%a,A6"  1
basei: ADDRLP   "(%a,A6"  1

addr:  ADDRGP   "%a(A5)"
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) "(%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))  "\tCLR.L %c\n\tMOVE.B %0,%c\n"    2
reg: CVSI(INDIRS(addr))  "\tMOVE.W %0,%c\n\tEXT.L %c\n"    2
reg: CVSU(INDIRS(addr))  "\tCLR.L %c\n\tMOVE.W %0,%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.X %0,%c\n" move(a)
reg: CVFD(reg)  "\tFMOVE.X %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.X %0,%c\n"   move(a)
reg: LOADF(reg)        "\tFMOVE.X %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.X %0,-(SP)\n" 3
stmt: ARGF(reg)        "\tFMOVE.X %0,-(SP)\n" 3
 
reg: ADDD(reg,reg)  "?\tFMOVE.X %0,%c\n\tFADD.X %1,%c\n"
reg: ADDF(reg,reg)  "?\tFMOVE.X %0,%c\n\tFADD.X %1,%c\n"
reg: SUBD(reg,reg)  "?\tFMOVE.X %0,%c\n\tFSUB.X %1,%c\n"
reg: SUBF(reg,reg)  "?\tFMOVE.X %0,%c\n\tFSUB.X %1,%c\n"
reg: MULD(reg,reg)  "?\tFMOVE.X %0,%c\n\tFMUL.X %1,%c\n"
reg: MULF(reg,reg)  "?\tFMOVE.X %0,%c\n\tFMUL.X %1,%c\n"
reg: DIVD(reg,reg)  "?\tFMOVE.X %0,%c\n\tFDIV.X %1,%c\n"
reg: DIVF(reg,reg)  "?\tFMOVE.X %0,%c\n\tFDIV.X %1,%c\n"
 
reg: NEGD(reg)  "\tFNEG.X %c\n"
reg: NEGF(reg)  "\tFNEG.X %c\n"
 
stmt:  JUMPV(acon)    "\tBRA %0\n"
stmt:  JUMPV(pcrel)   "\tJMP (PC,%0)\n"
stmt:  LABELV         "%a:\n"
 
stmt: EQI(ea0,con0)  "\tTST.L %0\n\tBEQ %a\n"   2
stmt: NEI(ea0,con0)  "\tTST.L %0\n\tBNE %a\n"   2

stmt: EQI(reg,ea1)  "\tCMP.L %1,%0\n\tBEQ %a\n"   3
stmt: GEI(reg,ea1)  "\tCMP.L %1,%0\n\tBGE %a\n"   3
stmt: GTI(reg,ea1)  "\tCMP.L %1,%0\n\tBGT %a\n"   3
stmt: LEI(reg,ea1)  "\tCMP.L %1,%0\n\tBLE %a\n"   3
stmt: LTI(reg,ea1)  "\tCMP.L %1,%0\n\tBLT %a\n"   3
stmt: NEI(reg,ea1)  "\tCMP.L %1,%0\n\tBNE %a\n"   3
 
stmt: GEU(reg,ea1)  "\tCMP.L %1,%0\n\tBHS %a\n"   3
stmt: GTU(reg,ea1)  "\tCMP.L %1,%0\n\tBHI %a\n"   3
stmt: LEU(reg,ea1)  "\tCMP.L %1,%0\n\tBLS %a\n"   3
stmt: LTU(reg,ea1)  "\tCMP.L %1,%0\n\tBLO %a\n"   3
 
stmt: EQD(reg,reg)  "\tFCMP.X %1,%0\n\tFBEQ.W %a\n"
stmt: GED(reg,reg)  "\tFCMP.X %1,%0\n\tFBGE.W %a\n"
stmt: GTD(reg,reg)  "\tFCMP.X %1,%0\n\tFBGT.W %a\n"
stmt: LED(reg,reg)  "\tFCMP.X %1,%0\n\tFBLE.W %a\n"
stmt: LTD(reg,reg)  "\tFCMP.X %1,%0\n\tFBLT.W %a\n"
stmt: NED(reg,reg)  "\tFCMP.X %1,%0\n\tFBNE.W %a\n"
 
stmt: EQF(reg,reg)  "\tFCMP.X %1,%0\n\tFBEQ.W %a\n"
stmt: GEF(reg,reg)  "\tFCMP.X %1,%0\n\tFBGE.W %a\n"
stmt: GTF(reg,reg)  "\tFCMP.X %1,%0\n\tFBGT.W %a\n"
stmt: LEF(reg,reg)  "\tFCMP.X %1,%0\n\tFBLE.W %a\n"
stmt: LTF(reg,reg)  "\tFCMP.X %1,%0\n\tFBLT.W %a\n"
stmt: NEF(reg,reg)  "\tFCMP.X %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 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 MC68030\n");
    print("\tMC68881\tCOID=1,PRECISION=D\n");
    print("\tCASE\tON\n");
    print("\tSTRING\tASIS\n");
    
    cseg = 0;
}
static void progend() {}
static void segment(n) {}
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;
    }
}
 
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;
    }
}
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]);
}
 
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;
}

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), lab2 = genlabel(1);
        int rem = getregnum(p), quo = getregnum(p->x.kids[0]);
        int divisor = getregnum(p->x.kids[1]);

        /* use D2 as scratch for testing sign
         use D1 for quotient since dividend gets clobbered */
        print("\tMOVE.L D%d,D%d\n", quo, D1);
        print("\tMOVEQ.L #-1,D%d\n", rem);
        print("\tMOVE.L #31,D%d\n", D2);
        print("\tBTST.L D%d,D%d\n", D2, D1);
        print("\tBNE.S @%d\n", lab1);
        print("\tCLR.L D%d\n", rem);
        print("@%d:\n", lab1);
        print("\tDIVS.L D%d,D%d:D%d\n", divisor, rem, D1);
        break;
        }
    }
}
static void doarg(p) Node p; {
    assert(p && p->syms[0]);
        switch(p->op) {
        case ARGD: case ARGF:
            mkactual(2,realparamsize); /* pass all floats as extended which are 96-bits */
            break;
        default:
        mkactual(2, p->syms[0]->u.c.v.i);
    }
}
static void blkfetch(k, off, reg, tmp) {}
static void blkstore(k, off, reg, tmp) {}
static void blkloop(dreg, doff, sreg, soff, size, tmps)
    int tmps[]; {}
static void local(p) Symbol p; {
    if (askregvar(p, rmap[ttob(p->type)]) == 0)
        mkauto(p);
}
static void function(f, caller, callee, n)
Symbol f, callee[], caller[]; {
    int i, count, acount, inseq;
        char reglist[256];
        char temp[4];

    print("%s\tPROC", f->x.name);
    if(!(f->sclass==STATIC))
        print("\tEXPORT");
    print("\n");
    
    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( p->type == floattype || p->type == doubletype)
            offset += roundup(realparamsize, 2);
        else
            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 A6,#%d\n", -framesize);
    else
        print("\tLINK A6,#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 */
    for (i = 0; callee[i]; i++) {
        Symbol p = callee[i];
        if(p->type == floattype) {
        print("\tFMOVE.X %d(A6),FP1\n", p->x.offset);
        print("\tFMOVE.S FP1,%d(A6)\n", p->x.offset);
        }
        else if(p->type == doubletype) {
        print("\tFMOVE.X %d(A6),FP1\n", p->x.offset);
        print("\tFMOVE.D FP1,%d(A6)\n", p->x.offset);
        }
    }

    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 A6\n");
    print("\tRTS\n");
}
static void defsymbol(p) Symbol p; {
    if (p->scope >= LOCAL && p->sclass == STATIC)
        p->x.name = stringf("L%d", genlabel(1));
    else if (p->generated)
        p->x.name = stringf("L%s", p->name);
    else if (p->scope == GLOBAL || p->sclass == EXTERN)
        p->x.name = stringf("%s", p->name); /* no leading underscore */
    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, $%x\n", p[swap], p[1 - swap]);
            return;
            }
    }
    assert(0);
}
static void defaddress(p) Symbol p; {}
static void export(p) Symbol p; {}
static void import(p) Symbol p; {}
static void global(p) Symbol p; {}
static void space(n) {}

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, 0, 0, 0, 0, 0, 0,
    {1, blkfetch, blkstore, blkloop,
        _label,
        _rule,
        _nts,
        _kids,
        _opname,
        _arity,
        _string,
        _templates,
        _isinstruction,
        _ntname,
        emit2,
        doarg,
        target,
        clobber,
         }
};
