Browse Source

Archival checkin (semi-working code).

dtrg 16 years ago
parent
commit
4dd1ff6d80

+ 6 - 0
mach/powerpc/as/.distr

@@ -0,0 +1,6 @@
+mach0.c
+mach1.c
+mach2.c
+mach3.c
+mach4.c
+mach5.c

+ 31 - 0
mach/powerpc/as/mach0.c

@@ -0,0 +1,31 @@
+/*
+ * $Source$
+ * $State$
+ */
+
+#define	THREE_PASS          /* branch and offset optimization */
+#define BYTES_REVERSED      /* high order byte has lowest address */
+#define WORDS_REVERSED      /* high order word has lowest address */
+#define LISTING             /* enable listing facilities */
+#define RELOCATION          /* generate relocatable code */
+#define DEBUG 0
+
+#undef valu_t
+#define valu_t long
+
+#undef ADDR_T
+#define ADDR_T long
+
+#undef word_t
+#define word_t long
+
+#undef ALIGNWORD
+#define ALIGNWORD	4
+
+#undef ALIGNSECT
+#define ALIGNSECT	4
+
+#undef VALWIDTH
+#define VALWIDTH	8
+
+#define FIXUPFLAGS (RELBR | RELWR)

+ 5 - 0
mach/powerpc/as/mach1.c

@@ -0,0 +1,5 @@
+/*
+ * $Source$
+ * $State$
+ */
+

+ 89 - 0
mach/powerpc/as/mach2.c

@@ -0,0 +1,89 @@
+/*
+ * $Source$
+ * $State$
+ */
+
+%token <y_word> GPR
+%token <y_word> SPR
+%token <y_word> FPR
+%token <y_word> CR
+%token <y_word> C
+
+%token <y_word> OP
+%token <y_word> OP_BF
+%token <y_word> OP_BF_BFA
+%token <y_word> OP_BF_FRA_FRB
+%token <y_word> OP_BF_L_RA_RB
+%token <y_word> OP_BF_L_RA_SI
+%token <y_word> OP_BF_L_RA_UI
+%token <y_word> OP_BF_U_C
+%token <y_word> OP_BO_BI_BDA
+%token <y_word> OP_BO_BI_BDL
+%token <y_word> OP_BO_BI_BH
+%token <y_word> OP_BT_C
+%token <y_word> OP_BT_BA_BB
+%token <y_word> OP_FLM_FRB_C
+%token <y_word> OP_FRS_RA_D
+%token <y_word> OP_FRS_RA_RB
+%token <y_word> OP_FRT_C
+%token <y_word> OP_FRT_FRA_FRB_C
+%token <y_word> OP_FRT_FRA_FRC_FRB_C
+%token <y_word> OP_FRT_FRA_FRC_C
+%token <y_word> OP_FRT_FRB_C
+%token <y_word> OP_FRT_RA_D
+%token <y_word> OP_FRT_RA_RB
+%token <y_word> OP_L
+%token <y_word> OP_LEV
+%token <y_word> OP_LIA
+%token <y_word> OP_LIL
+%token <y_word> OP_L_RB
+%token <y_word> OP_RA_RB
+%token <y_word> OP_RB
+%token <y_word> OP_RS
+%token <y_word> OP_RS_FXM
+%token <y_word> OP_RS_L
+%token <y_word> OP_RS_RA
+%token <y_word> OP_RS_RA_C
+%token <y_word> OP_RS_RA_D
+%token <y_word> OP_RS_RA_DS
+%token <y_word> OP_RS_RA_NB
+%token <y_word> OP_RS_RA_RB
+%token <y_word> OP_RS_RA_RB_C
+%token <y_word> OP_RS_RA_RB_MB5_ME5_C
+%token <y_word> OP_RS_RA_RB_MB6_C
+%token <y_word> OP_RS_RA_RB_ME6_C
+%token <y_word> OP_RS_RA_SH_MB5_ME5_C
+%token <y_word> OP_RS_RA_SH_MB6_SH_C
+%token <y_word> OP_RS_RA_SH_ME6_SH_C
+%token <y_word> OP_RS_RA_SH5_C
+%token <y_word> OP_RS_RA_SH6_C
+%token <y_word> OP_RS_RA_UI
+%token <y_word> OP_RS_RA_UI_CC
+%token <y_word> OP_RS_RB
+%token <y_word> OP_RS_SPR
+%token <y_word> OP_RS_SR
+%token <y_word> OP_RT
+%token <y_word> OP_RT_FXM
+%token <y_word> OP_RT_RA_C
+%token <y_word> OP_RT_RA_D
+%token <y_word> OP_RT_RA_DS
+%token <y_word> OP_RT_RA_NB
+%token <y_word> OP_RT_RA_RB
+%token <y_word> OP_RT_RA_RB_C
+%token <y_word> OP_RT_RA_SI
+%token <y_word> OP_RT_RA_SI_addic
+%token <y_word> OP_RT_RB
+%token <y_word> OP_RT_SPR
+%token <y_word> OP_RT_SR
+%token <y_word> OP_RT_TBR
+%token <y_word> OP_TH_RA_RB
+%token <y_word> OP_TO_RA_RB
+%token <y_word> OP_TO_RA_SI
+
+%token <y_word> OP_la
+
+/* Other token types */
+
+%type <y_word> c
+%type <y_word> e16 u8 u7 u6 u5 u4 u2 u1
+%type <y_word> nb ds bda bdl lia lil

+ 358 - 0
mach/powerpc/as/mach3.c

@@ -0,0 +1,358 @@
+/*
+ * $Source$
+ * $State$
+ */
+
+/* Integer registers */
+
+0,     GPR,        0,          "r0",
+0,     GPR,        1,          "r1",
+0,     GPR,        1,          "sp",
+0,     GPR,        2,          "r2",
+0,     GPR,        2,          "fp",
+0,     GPR,        3,          "r3",
+0,     GPR,        4,          "r4",
+0,     GPR,        5,          "r5",
+0,     GPR,        6,          "r6",
+0,     GPR,        7,          "r7",
+0,     GPR,        8,          "r8",
+0,     GPR,        9,          "r9",
+0,     GPR,        10,         "r10",
+0,     GPR,        11,         "r11",
+0,     GPR,        12,         "r12",
+0,     GPR,        13,         "r13",
+0,     GPR,        14,         "r14",
+0,     GPR,        15,         "r15",
+0,     GPR,        16,         "r16",
+0,     GPR,        17,         "r17",
+0,     GPR,        18,         "r18",
+0,     GPR,        19,         "r19",
+0,     GPR,        20,         "r20",
+0,     GPR,        21,         "r21",
+0,     GPR,        22,         "r22",
+0,     GPR,        23,         "r23",
+0,     GPR,        24,         "r24",
+0,     GPR,        25,         "r25",
+0,     GPR,        26,         "r26",
+0,     GPR,        27,         "r27",
+0,     GPR,        28,         "r28",
+0,     GPR,        29,         "r29",
+0,     GPR,        30,         "r30",
+0,     GPR,        31,         "r31",
+
+/* Floating-point registers */
+
+0,     FPR,        0,          "f0",
+0,     FPR,        1,          "f1",
+0,     FPR,        2,          "f2",
+0,     FPR,        3,          "f3",
+0,     FPR,        4,          "f4",
+0,     FPR,        5,          "f5",
+0,     FPR,        6,          "f6",
+0,     FPR,        7,          "f7",
+0,     FPR,        8,          "f8",
+0,     FPR,        9,          "f9",
+0,     FPR,        10,         "f10",
+0,     FPR,        11,         "f11",
+0,     FPR,        12,         "f12",
+0,     FPR,        13,         "f13",
+0,     FPR,        14,         "f14",
+0,     FPR,        15,         "f15",
+0,     FPR,        16,         "f16",
+0,     FPR,        17,         "f17",
+0,     FPR,        18,         "f18",
+0,     FPR,        19,         "f19",
+0,     FPR,        20,         "f20",
+0,     FPR,        21,         "f21",
+0,     FPR,        22,         "f22",
+0,     FPR,        23,         "f23",
+0,     FPR,        24,         "f24",
+0,     FPR,        25,         "f25",
+0,     FPR,        26,         "f26",
+0,     FPR,        27,         "f27",
+0,     FPR,        28,         "f28",
+0,     FPR,        29,         "f29",
+0,     FPR,        30,         "f30",
+0,     FPR,        31,         "f31",
+
+/* Special registers */
+
+0,     SPR,        32,         "xer",
+0,     SPR,        256,        "lr",
+0,     SPR,        288,        "ctr",
+
+/* Condition registers */
+
+0,     CR,         0,          "cr0",
+0,     CR,         1,          "cr1",
+0,     CR,         2,          "cr2",
+0,     CR,         3,          "cr3",
+0,     CR,         4,          "cr4",
+0,     CR,         5,          "cr5",
+0,     CR,         6,          "cr6",
+0,     CR,         7,          "cr7",
+
+/* Condition code flag */
+
+0,     C,          0,          ".",
+
+/* Special instructions */
+
+0,     OP_la,                 0,                                       "la",
+
+/* Branch processor instructions (page 20) */
+
+0,     OP_LIL,                18<<26 | 0<<1 | 0<<0,                    "b",
+0,     OP_LIA,                18<<26 | 1<<1 | 0<<0,                    "ba",
+0,     OP_LIL,                18<<26 | 0<<1 | 1<<0,                    "bl",
+0,     OP_LIA,                18<<26 | 1<<1 | 1<<0,                    "bla",
+0,     OP_BO_BI_BDL,          16<<26 | 0<<1 | 0<<0,                    "bc",
+0,     OP_BO_BI_BDA,          16<<26 | 1<<1 | 0<<0,                    "bca",
+0,     OP_BO_BI_BDL,          16<<26 | 0<<1 | 1<<0,                    "bcl",
+0,     OP_BO_BI_BDA,          16<<26 | 1<<1 | 1<<0,                    "bcla",
+0,     OP_BO_BI_BH,           19<<26 | 16<<1 | 0<<0,                   "bclr",
+0,     OP_BO_BI_BH,           19<<26 | 16<<1 | 1<<0,                   "bclrl",
+0,     OP_BO_BI_BH,           19<<26 | 528<<1 | 0<<0,                  "bcctr",
+0,     OP_BO_BI_BH,           19<<26 | 528<<1 | 1<<0,                  "bcctrl",
+0,     OP_LEV,                17<<26 | 1<<1,                           "sc",
+0,     OP_BT_BA_BB,           19<<26 | 257<<1,                         "crand",
+0,     OP_BT_BA_BB,           19<<26 | 449<<1,                         "cror",
+0,     OP_BT_BA_BB,           19<<26 | 193<<1,                         "crxor",
+0,     OP_BT_BA_BB,           19<<26 | 225<<1,                         "crnand",
+0,     OP_BT_BA_BB,           19<<26 | 33<<1,                          "crnor",
+0,     OP_BT_BA_BB,           19<<26 | 289<<1,                         "crneqv",
+0,     OP_BT_BA_BB,           19<<26 | 129<<1,                         "crandc",
+0,     OP_BT_BA_BB,           19<<26 | 417<<1,                         "crorc",
+0,     OP_BF_BFA,             19<<26 | 0<<1,                           "mcrf",
+
+/* Fixed point instructions (page 29) */
+
+0,     OP_RT_RA_D,            34<<26,                                  "lbz",
+0,     OP_RT_RA_RB,           31<<26 | 87<<1,                          "lbzx",
+0,     OP_RT_RA_D,            35<<26,                                  "lbzu",
+0,     OP_RT_RA_RB,           31<<26 | 119<<1,                         "lbzux",
+0,     OP_RT_RA_D,            40<<26,                                  "lhz",
+0,     OP_RT_RA_RB,           31<<26 | 279<<1,                         "lhzx",
+0,     OP_RT_RA_D,            41<<26,                                  "lhzu",
+0,     OP_RT_RA_RB,           31<<26 | 311<<1,                         "lhzux",
+0,     OP_RT_RA_D,            42<<26,                                  "lha",
+0,     OP_RT_RA_RB,           31<<26 | 343<<1,                         "lhax",
+0,     OP_RT_RA_D,            43<<26,                                  "lhau",
+0,     OP_RT_RA_RB,           31<<26 | 375<<1,                         "lhaux",
+0,     OP_RT_RA_D,            32<<26,                                  "lwz",
+0,     OP_RT_RA_RB,           31<<26 | 23<<1,                          "lwzx",
+0,     OP_RT_RA_D,            33<<26,                                  "lwzu",
+0,     OP_RT_RA_RB,           31<<26 | 55<<1,                          "lwzux",
+0,     OP_RT_RA_DS,           58<<26 | 2<<0,                           "lwa",
+0,     OP_RT_RA_RB,           31<<26 | 341<<1,                         "lwax",
+0,     OP_RT_RA_RB,           31<<26 | 363<<1,                         "lwaux",
+0,     OP_RT_RA_DS,           58<<26,                                  "ld",
+0,     OP_RT_RA_RB,           31<<26 | 21<<1,                          "ldx",
+0,     OP_RT_RA_DS,           58<<26 | 1<<0,                           "ldu",
+0,     OP_RT_RA_RB,           31<<26 | 53<<1,                          "ldux",
+
+0,     OP_RS_RA_D,            38<<26,                                  "stb",
+0,     OP_RS_RA_RB,           31<<26 | 215<<1,                         "stbx",
+0,     OP_RS_RA_D,            39<<26,                                  "stbu",
+0,     OP_RS_RA_RB,           31<<26 | 247<<1,                         "stbux",
+0,     OP_RS_RA_D,            44<<26,                                  "sth",
+0,     OP_RS_RA_RB,           31<<26 | 407<<1,                         "sthx",
+0,     OP_RS_RA_D,            45<<26,                                  "sthu",
+0,     OP_RS_RA_RB,           31<<26 | 439<<1,                         "sthux",
+0,     OP_RS_RA_D,            36<<26,                                  "stw",
+0,     OP_RS_RA_RB,           31<<26 | 151<<1,                         "stwx",
+0,     OP_RS_RA_D,            37<<26,                                  "stwu",
+0,     OP_RS_RA_RB,           31<<26 | 183<<1,                         "stwux",
+0,     OP_RS_RA_DS,           62<<26,                                  "std",
+0,     OP_RS_RA_RB,           31<<26 | 149<<1,                         "stdx",
+0,     OP_RS_RA_DS,           62<<26 | 1<<0,                           "stdu",
+0,     OP_RS_RA_RB,           31<<26 | 181<<1,                         "stdux",
+
+/* page 42  */
+0,     OP_RT_RA_RB,           31<<26 | 790<<1,                         "lhbrx",
+0,     OP_RT_RA_RB,           31<<26 | 534<<1,                         "lwbrx",
+0,     OP_RS_RA_RB,           31<<26 | 918<<1,                         "sthbrx",
+0,     OP_RS_RA_RB,           31<<26 | 662<<1,                         "stwbrx",
+
+/* page 44 */
+0,     OP_RT_RA_D,            46<<26,                                  "lmw",
+0,     OP_RS_RA_D,            47<<26,                                  "stmw",
+
+/* page 45 */
+0,     OP_RT_RA_NB,           31<<26 | 597<<1,                         "lswi",
+0,     OP_RT_RA_RB,           31<<26 | 533<<1,                         "lswx",
+0,     OP_RS_RA_NB,           31<<26 | 725<<1,                         "stswi",
+0,     OP_RS_RA_RB,           31<<26 | 661<<1,                         "stswx",
+
+/* page 49 */
+0,     OP_RT_RA_SI,           14<<26,                                  "addi",
+0,     OP_RT_RA_SI,           15<<26,                                  "addis",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 266<<1,                 "add",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 266<<1,                 "addo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 40<<1,                  "subf",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 40<<1,                  "subfo",
+0,     OP_RT_RA_SI_addic,     12<<26,                                  "addic", /* special case C */
+0,     OP_RT_RA_SI,           8<<26,                                   "subfic",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 138<<1,                 "adde",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 138<<1,                 "addeo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 136<<1,                 "subfe",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 136<<1,                 "subfeo",
+0,     OP_RT_RA_C,            31<<26 | 0<<10 | 234<<1,                 "addme",
+0,     OP_RT_RA_C,            31<<26 | 1<<10 | 234<<1,                 "addmeo",
+0,     OP_RT_RA_C,            31<<26 | 0<<10 | 232<<1,                 "subfme",
+0,     OP_RT_RA_C,            31<<26 | 1<<10 | 232<<1,                 "subfmeo",
+0,     OP_RT_RA_C,            31<<26 | 0<<10 | 202<<1,                 "addze",
+0,     OP_RT_RA_C,            31<<26 | 1<<10 | 202<<1,                 "addzeo",
+0,     OP_RT_RA_C,            31<<26 | 0<<10 | 200<<1,                 "subfze",
+0,     OP_RT_RA_C,            31<<26 | 1<<10 | 200<<1,                 "subfzeo",
+0,     OP_RT_RA_C,            31<<26 | 0<<10 | 104<<1,                 "neg",
+0,     OP_RT_RA_C,            31<<26 | 1<<10 | 104<<1,                 "nego",
+
+/* page 54 */
+0,     OP_RT_RA_SI,           7<<26,                                   "mulli",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 233<<1,                 "mulld",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 233<<1,                 "mulldo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 235<<1,                 "mullw",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 235<<1,                 "mullwo",
+0,     OP_RT_RA_RB_C,         31<<26 | 73<<1,                          "mulhd",
+0,     OP_RT_RA_RB_C,         31<<26 | 75<<1,                          "mulhw",
+0,     OP_RT_RA_RB_C,         31<<26 | 9<<1,                           "mulhdu",
+0,     OP_RT_RA_RB_C,         31<<26 | 11<<1,                          "mulhwu",
+
+/* page 56 */
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 489<<1,                 "divd",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 489<<1,                 "divdo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 491<<1,                 "divw",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 491<<1,                 "divwo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 457<<1,                 "divdu",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 457<<1,                 "divduo",
+0,     OP_RT_RA_RB_C,         31<<26 | 0<<10 | 459<<1,                 "divwu",
+0,     OP_RT_RA_RB_C,         31<<26 | 1<<10 | 459<<1,                 "divwuo",
+
+/* page 58 */
+0,     OP_BF_L_RA_SI,         11<<26,                                  "cmpi",
+0,     OP_BF_L_RA_RB,         31<<26 | 0<<1,                           "cmp",
+0,     OP_BF_L_RA_UI,         10<<26,                                  "cmpli",
+0,     OP_BF_L_RA_RB,         31<<26 | 32<<1,                          "cmpl",
+
+/* page 60 */
+0,     OP_TO_RA_SI,           2<<26,                                   "tdi",
+0,     OP_TO_RA_SI,           3<<26,                                   "twi",
+0,     OP_TO_RA_RB,           31<<26 | 68<<1,                          "td",
+0,     OP_TO_RA_RB,           31<<26 | 4<<1,                           "tw",
+
+/* page 62 */
+0,     OP_RS_RA_UI_CC,        28<<26,                                  "andi", /* C compulsory */
+0,     OP_RS_RA_UI_CC,        29<<26,                                  "andis", /* C compulsory */
+0,     OP_RS_RA_UI,           24<<26,                                  "ori",
+0,     OP_RS_RA_UI,           25<<26,                                  "oris",
+0,     OP_RS_RA_UI,           26<<26,                                  "xori",
+0,     OP_RS_RA_UI,           27<<26,                                  "xoris",
+0,     OP_RS_RA_RB_C,         31<<26 | 28<<1,                          "and",
+0,     OP_RS_RA_RB_C,         31<<26 | 444<<1,                         "or",
+0,     OP_RS_RA_RB_C,         31<<26 | 316<<1,                         "xor",
+0,     OP_RS_RA_RB_C,         31<<26 | 476<<1,                         "nand",
+0,     OP_RS_RA_RB_C,         31<<26 | 124<<1,                         "nor",
+0,     OP_RS_RA_RB_C,         31<<26 | 284<<1,                         "eqv",
+0,     OP_RS_RA_RB_C,         31<<26 | 60<<1,                          "andc",
+0,     OP_RS_RA_RB_C,         31<<26 | 412<<1,                         "orc",
+0,     OP_RS_RA_C,            31<<26 | 954<<1,                         "extsb",
+0,     OP_RS_RA_C,            31<<26 | 922<<1,                         "extsh",
+0,     OP_RS_RA_C,            31<<26 | 986<<1,                         "extsw",
+0,     OP_RS_RA_C,            31<<26 | 58<<1,                          "cntlzd",
+0,     OP_RS_RA_C,            31<<26 | 26<<1,                          "cntlzw",
+
+/* page 69 */
+0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 0<<2,                           "rldicl",
+0,     OP_RS_RA_SH_ME6_SH_C,  30<<26 | 1<<2,                           "rldicr",
+0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 2<<2,                           "rldic",
+0,     OP_RS_RA_SH_MB5_ME5_C, 21<<26,                                  "rlwinm",
+0,     OP_RS_RA_RB_MB6_C,     30<<26 | 8<<1,                           "rldcl", 
+0,     OP_RS_RA_RB_ME6_C,     30<<26 | 9<<1,                           "rldcr",
+0,     OP_RS_RA_RB_MB5_ME5_C, 23<<26,                                  "rlwnm",
+0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 3<<2,                           "rldimi",
+0,     OP_RS_RA_SH_MB5_ME5_C, 20<<26,                                  "rlwimi",
+
+/* page 74 */
+0,     OP_RS_RA_RB_C,         31<<26 | 27<<1,                          "sld",
+0,     OP_RS_RA_RB_C,         31<<26 | 24<<1,                          "slw",
+0,     OP_RS_RA_RB_C,         31<<26 | 539<<1,                         "srd",
+0,     OP_RS_RA_RB_C,         31<<26 | 536<<1,                         "srw",
+0,     OP_RS_RA_SH6_C,        31<<26 | 413<<2,                         "sradi",
+0,     OP_RS_RA_SH5_C,        31<<26 | 824<<1,                         "srawi",
+0,     OP_RS_RA_RB_C,         31<<26 | 794<<1,                         "srad",
+0,     OP_RS_RA_RB_C,         31<<26 | 792<<1,                         "sraw",
+
+/* page 78 */
+0,     OP_RS_SPR,             31<<26 | 467<<1,                         "mtspr",
+0,     OP_RT_SPR,             31<<26 | 339<<1,                         "mfspr",
+0,     OP_RS_FXM,             31<<26 | 0<<21 | 144<<1,                 "mtcrf",
+0,     OP_RT,                 31<<26 | 0<<21 | 19<<1,                  "mfcr",
+
+/* Floating point instructions (page 83) */
+
+0,     OP_FRT_RA_D,           48<<26,                                  "lfs",
+0,     OP_FRT_RA_RB,          31<<26 | 535<<1,                         "lfsx",
+0,     OP_FRT_RA_D,           49<<26,                                  "lfsu",
+0,     OP_FRT_RA_RB,          31<<26 | 567<<1,                         "lfsux",
+0,     OP_FRT_RA_D,           50<<26,                                  "lfd",
+0,     OP_FRT_RA_RB,          31<<26 | 599<<1,                         "lfdx",
+0,     OP_FRT_RA_D,           51<<26,                                  "lfdu",
+0,     OP_FRT_RA_RB,          31<<26 | 631<<1,                         "lfdux",
+0,     OP_FRS_RA_D,           52<<26,                                  "stfs",
+0,     OP_FRS_RA_RB,          31<<26 | 663<<1,                         "stfsx",
+0,     OP_FRS_RA_D,           53<<26,                                  "stfsu",
+0,     OP_FRS_RA_RB,          31<<26 | 695<<1,                         "stfsux",
+0,     OP_FRS_RA_D,           54<<26,                                  "stfd",
+0,     OP_FRS_RA_RB,          31<<26 | 727<<1,                         "stfdx",
+0,     OP_FRS_RA_D,           55<<26,                                  "stfdu",
+0,     OP_FRS_RA_RB,          31<<26 | 759<<1,                         "stfdux",
+0,     OP_FRS_RA_RB,          31<<26 | 983<<1,                         "stfiwx",
+
+0,     OP_FRT_FRB_C,          63<<26 | 72<<1,                          "fmr",
+0,     OP_FRT_FRB_C,          63<<26 | 40<<1,                          "fneg",
+0,     OP_FRT_FRB_C,          63<<26 | 264<<1,                         "fabs",
+0,     OP_FRT_FRB_C,          63<<26 | 136<<1,                         "fnabs",
+
+0,     OP_FRT_FRA_FRB_C,      63<<26 | 21<<1,                          "fadd",
+0,     OP_FRT_FRA_FRB_C,      59<<26 | 21<<1,                          "fadds",
+0,     OP_FRT_FRA_FRB_C,      63<<26 | 20<<1,                          "fsub",
+0,     OP_FRT_FRA_FRB_C,      59<<26 | 20<<1,                          "fsubs",
+0,     OP_FRT_FRA_FRC_C,      63<<26 | 25<<1,                          "fmul",
+0,     OP_FRT_FRA_FRC_C,      59<<26 | 25<<1,                          "fmuls",
+0,     OP_FRT_FRA_FRB_C,      63<<26 | 18<<1,                          "fdiv",
+0,     OP_FRT_FRA_FRB_C,      59<<26 | 18<<1,                          "fdivs",
+
+0,     OP_FRT_FRA_FRC_FRB_C,  63<<26 | 29<<1,                          "fmadd",
+0,     OP_FRT_FRA_FRC_FRB_C,  59<<26 | 29<<1,                          "fmadds",
+0,     OP_FRT_FRA_FRC_FRB_C,  63<<26 | 28<<1,                          "fmsub",
+0,     OP_FRT_FRA_FRC_FRB_C,  59<<26 | 28<<1,                          "fmsubs",
+0,     OP_FRT_FRA_FRC_FRB_C,  63<<26 | 31<<1,                          "fnmadd",
+0,     OP_FRT_FRA_FRC_FRB_C,  59<<26 | 31<<1,                          "fnmadds",
+0,     OP_FRT_FRA_FRC_FRB_C,  63<<26 | 30<<1,                          "fnmsub",
+0,     OP_FRT_FRA_FRC_FRB_C,  59<<26 | 30<<1,                          "fnmsubs",
+
+0,     OP_FRT_FRB_C,          63<<26 | 12<<1,                          "frsp",
+0,     OP_FRT_FRB_C,          63<<26 | 814<<1,                         "fctid",
+0,     OP_FRT_FRB_C,          63<<26 | 815<<1,                         "fctidz",
+0,     OP_FRT_FRB_C,          63<<26 | 14<<1,                          "fctiw",
+0,     OP_FRT_FRB_C,          63<<26 | 15<<1,                          "fctiwz",
+0,     OP_FRT_FRB_C,          63<<26 | 846<<1,                         "fcfid",
+
+0,     OP_BF_FRA_FRB,         63<<26 | 0<<1,                           "fcmpu",
+0,     OP_BF_FRA_FRB,         63<<26 | 32<<1,                          "fcmpo",
+
+0,     OP_FRT_C,              63<<26 | 583<<1,                         "mffs",
+0,     OP_BF_BFA,             63<<26 | 64<<1,                          "mcrfs",
+0,     OP_BF_U_C,             63<<26 | 134<<1,                         "mtfsfi",
+0,     OP_FLM_FRB_C,          63<<26 | 711<<1,                         "mtfsf",
+0,     OP_BT_C,               63<<26 | 70<<1,                          "mtfsb0",
+0,     OP_BT_C,               63<<26 | 38<<1,                          "mtfsb1",
+
+0,     OP_FRT_FRB_C,          63<<26 | 22<<1,                          "fsqrt",
+0,     OP_FRT_FRB_C,          59<<26 | 22<<1,                          "fsqrts",
+0,     OP_FRT_FRB_C,          59<<26 | 24<<1,                          "fres",
+0,     OP_FRT_FRB_C,          63<<26 | 26<<1,                          "frsqrte",
+0,     OP_FRT_FRA_FRC_FRB_C,  63<<26 | 23<<1,                          "fsel",
+
+/* page 98 */

+ 236 - 0
mach/powerpc/as/mach4.c

@@ -0,0 +1,236 @@
+/*
+ * $Source$
+ * $State$
+ */
+
+operation
+	: OP_BF_BFA            CR ',' CR                  { emit4($1 | ($2<<23) | ($4<<18)); }
+	| OP_BF_FRA_FRB        CR ',' FPR ',' FPR         { emit4($1 | ($2<<23) | ($4<<16) | ($6<<11)); }
+	| OP_BF_L_RA_RB        CR ',' u1 ',' GPR ',' GPR  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | ($8<<11)); }
+	| OP_BF_L_RA_SI        CR ',' u1 ',' GPR ',' e16  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+	| OP_BF_L_RA_UI        CR ',' u1 ',' GPR ',' e16  { emit4($1 | ($2<<23) | ($4<<21) | ($6<<16) | $8); }
+	| OP_BF_U_C            c CR ',' u4                { emit4($1 | $2 | ($3<<23) | ($5<<12)); }
+	| OP_BO_BI_BDA         u5 ',' u5 ',' bda          { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_BO_BI_BDL         u5 ',' u5 ',' bdl          { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_BO_BI_BH          u5 ',' u5 ',' u2           { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_BT_BA_BB          u5 ',' u5 ',' u5           { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_BT_C              c u5                       { emit4($1 | $2 | ($3<<21)); }
+	| OP_FLM_FRB_C         c u8 ',' FPR               { emit4($1 | $2 | ($3<<17) | ($5<<11)); }
+	| OP_FRS_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_FRS_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_FRT_FRA_FRB_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
+	| OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } 
+	| OP_FRT_FRA_FRC_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
+	| OP_FRT_FRB_C         c FPR ',' FPR              { emit4($1 | $2 | ($3<<21) | ($5<<11)); } 
+	| OP_FRT_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_FRT_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_FRT_C             c FPR                      { emit4($1 | $2 | ($3<<21)); }
+	| OP_RT                GPR                        { emit4($1 | ($2<<21)); }
+	| OP_RT_RA_C           c GPR ',' GPR              { emit4($1 | $2 | ($3<<21) | ($5<<16)); }
+	| OP_RT_RA_D           GPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RT_RA_DS          GPR ',' ds '(' GPR ')'     { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RT_RA_NB          GPR ',' GPR ',' nb         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_RT_RA_RB          GPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+    | OP_RT_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
+	| OP_RT_RA_SI          GPR ',' GPR ',' e16        { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_RT_RA_SI_addic    c GPR ',' GPR ',' e16      { emit4($1 | ($2<<26) | ($3<<21) | ($5<<16) | $7); }
+	| OP_RT_SPR            GPR ',' SPR                { emit4($1 | ($2<<21) | ($4<<11)); }
+	| OP_RS_FXM            u7 ',' GPR                 { emit4($1 | ($4<<21) | ($2<<12)); }
+	| OP_RS_RA_C           c GPR ',' GPR              { emit4($1 | $2 | ($5<<21) | ($3<<16)); }
+	| OP_RS_RA_D           GPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RS_RA_DS          GPR ',' ds '(' GPR ')'     { emit4($1 | ($2<<21) | ($6<<16) | $4); }
+	| OP_RS_RA_NB          GPR ',' GPR ',' nb         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_RS_RA_UI          GPR ',' GPR ',' e16        { emit4($1 | ($4<<21) | ($2<<16) | $6); } 
+	| OP_RS_RA_UI_CC       C GPR ',' GPR ',' e16      { emit4($1 | ($5<<21) | ($3<<16) | $7); } 
+	| OP_RS_RA_RB          GPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_RS_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
+	| OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
+	| OP_RS_RA_RB_MB6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
+	| OP_RS_RA_RB_ME6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
+	| OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
+	| OP_RS_RA_SH_MB6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
+	| OP_RS_RA_SH_ME6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
+	| OP_RS_RA_SH5_C       c GPR ',' GPR ',' u5       { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
+	| OP_RS_RA_SH6_C       c GPR ',' GPR ',' u6       { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | (($7&0x20)>>4)); }
+	| OP_RS_SPR            SPR ',' GPR                { emit4($1 | ($4<<21) | ($2<<11)); }
+	| OP_TO_RA_RB          u5 ',' GPR ',' GPR         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
+	| OP_TO_RA_SI          u5 ',' GPR ',' e16         { emit4($1 | ($2<<21) | ($4<<16) | $6); }
+	| OP_LEV               u7                         { emit4($1 | ($2<<5)); }
+	| OP_LIA               lia                        { emit4($1 | $2); }
+	| OP_LIL               lil                        { emit4($1 | $2); }
+	;
+
+c
+	: /* nothing */                          { $$ = 0; }
+	| C                                      { $$ = 1; }
+	;
+	
+e16
+	: '<' expr
+	{
+		DOTVAL += 2;
+		newrelo($2.typ, RELOH2 | FIXUPFLAGS);
+		DOTVAL -= 2;
+		$$ = ($2.val >> 16) & 0xFFFF;
+	}
+	| '>' expr
+	{
+		DOTVAL += 2;
+		newrelo($2.typ, RELO2 | FIXUPFLAGS);
+		DOTVAL -= 2;
+		$$ = $2.val & 0xFFFF;
+	}
+	| expr
+	{
+		DOTVAL += 2;
+		newrelo($1.typ, RELO2 | FIXUPFLAGS);
+		DOTVAL -= 2;
+		$$ = $1.val & 0xFFFF;
+	}
+	;
+		
+u8
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0xFF))
+			serror("8-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u7
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0x7F))
+			serror("7-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u6
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0x3F))
+			serror("6-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u5
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0x1F))
+			serror("5-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u4
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0xF))
+			serror("4-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u1
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 1))
+			serror("1-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+u2
+	: absexp
+	{
+		if (($1 < 0) || ($1 > 0x3))
+			serror("2-bit unsigned value out of range");
+		$$ = $1;
+	}
+	;
+	
+ds
+	: e16
+	{
+		if ($1 & 3)
+			serror("value must be 4-aligned");
+		$$ = $1;
+	}
+	;
+	
+nb
+	: absexp
+	{
+		if (($1 < 1) || ($1 > 32))
+			serror("register count must be in the range 1..32");
+	
+		if ($1 == 32)
+			$$ = 0;
+		else
+			$$ = $1;	
+	}
+	;
+	
+bdl
+	: expr
+	{
+		int dist = $1.val - DOTVAL;
+		fit(fitx(dist, 25));
+		
+		if (dist & 0x3)
+			serror("jump targets must be 4-aligned");
+
+		DOTVAL += 2;
+		newrelo($1.typ, RELO2 | RELPC | FIXUPFLAGS);
+		DOTVAL -= 2;
+		$$ = dist & 0xFFFD;
+	}
+	;
+
+bda
+	: expr
+	{
+		int target = $1.val;
+		fit(fitx(target, 16));
+		
+		if (target & 0x3)
+			serror("jump targets must be 4-aligned");
+
+		DOTVAL += 2;
+		newrelo($1.typ, RELO2 | FIXUPFLAGS);
+		DOTVAL -= 2;
+		$$ = target & 0xFFFD;
+	}
+	;
+	
+lil
+	: expr
+	{
+		int dist = $1.val - DOTVAL;
+		fit(fitx(dist, 26));
+		
+		if (dist & 0x3)
+			serror("jump targets must be 4-aligned");
+
+		newrelo($1.typ, RELOPPC | RELPC | FIXUPFLAGS);
+		$$ = dist & 0x03FFFFFD;
+	}
+	;
+	
+lia
+	: expr
+	{
+		int target = $1.val;
+		fit(fitx(target, 26));
+		
+		if (target & 0x3)
+			serror("jump targets must be 4-aligned");
+
+		newrelo($1.typ, RELOPPC | FIXUPFLAGS);
+		$$ = target & 0x03FFFFFD;
+	}
+	;
+	

+ 5 - 0
mach/powerpc/as/mach5.c

@@ -0,0 +1,5 @@
+/*
+ * $Source$
+ * $State$
+ */
+

+ 2 - 0
mach/powerpc/libem/.distr

@@ -0,0 +1,2 @@
+LIST
+libem_s.a

+ 35 - 0
mach/powerpc/libem/aar4.s

@@ -0,0 +1,35 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+
+.sect .text
+	
+! Index into a bounds-checked array.
+!
+! On entry:
+!    r3 = ptr to descriptor
+!    r4 = index
+!    r5 = address of array
+
+.define .aar4
+.aar4:
+	addis r0, r0, <.trap_earray
+	ori r0, r0, >.trap_earray
+	mtspr ctr, r0            ! load CTR with trap address
+
+	lwz r0, 0(r3)
+	subf. r4, r0, r4         ! adjust range
+	bcctr IFTRUE, LT, 0      ! check lower bound
+	
+	lwz r0, 4(r3)
+	cmpl cr0, 0, r4, r3
+	bcctr IFFALSE, LT, 0     ! check upper bound
+	
+	lwz r0, 8(r3)
+	mullw r4, r4, r0         ! scale index
+	add r3, r4, r5           ! calculate element address
+	
+	bclr ALWAYS, 0, 0

+ 20 - 0
mach/powerpc/libem/cfi8.s

@@ -0,0 +1,20 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! Converts a 64-bit double into a 32-bit integer.
+!
+! Stack: ( double -- int )
+
+.define .cfi8
+.cfi8:
+	lfd f0, 0(sp)
+	fctiwz f0, f0
+	stfd f0, 0(sp)
+	addi sp, sp, 4
+	bclr ALWAYS, 0, 0        ! ...and return 

+ 44 - 0
mach/powerpc/libem/cfu8.s

@@ -0,0 +1,44 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+
+.sect .text
+
+! Converts a 64-bit double into a 32-bit unsigned integer.
+!
+! Stack: ( double -- uint )
+
+.define .cfu8
+.cfu8:
+	la(r3, .fd_00000000)
+	lfd f0, 0(r3)            ! f0 = 0.0
+	
+	lfd f1, 0(sp)            ! value to be converted
+
+	la(r3, .fd_FFFFFFFF)
+	lfd f3, 0(r3)            ! f3 = 0xFFFFFFFF	
+
+	la(r3, .fd_80000000)
+	lfd f4, 0(r3)            ! f4 = 0x80000000 	
+	
+	fsel f2, f1, f1, f0
+	fsub f5, f3, f1
+	fsel f2, f5, f2, f3
+	fsub f5, f2, f4
+	fcmpu cr0, f2, f4
+	fsel f2, f5, f5, f2
+	fctiwz f2, f2
+	
+	stfd f2, 0(sp)
+	addi sp, sp, 4
+	
+	bclr IFTRUE, LT, 0
+	
+	lwz r3, 0(sp)
+	xoris r3, r3, 0x8000
+	stw r3, 0(sp)
+
+	bclr ALWAYS, 0, 0 

+ 37 - 0
mach/powerpc/libem/cif8.s

@@ -0,0 +1,37 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+
+.sect .text
+
+! Converts a 32-bit integer into a 64-bit double.
+!
+! Stack: ( int -- double )
+
+.define .cif8
+.cif8:
+	addi sp, sp, -4          ! make space for the double
+	
+	lwz r3, 4(sp)
+	xoris r3, r3, 0x8000
+	stw r3, 4(sp)            ! flip sign of integer value
+	
+	addis r3, r0, 0x4330
+	stw r3, 0(sp)            ! set high word to construct a double
+	
+	lfd f0, 0(sp)            ! load value
+
+	la (r3, pivot)
+	lfd f1, 0(r3)            ! load pivot value
+	fsub f0, f0, f1          ! adjust
+	                         
+	stfd f0, 0(sp)           ! save value again...
+	bclr ALWAYS, 0, 0        ! ...and return 
+
+.sect .rom
+pivot:
+	.data4 0x43300000
+	.data4 0x80000000

+ 44 - 0
mach/powerpc/libem/csa.s

@@ -0,0 +1,44 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! this is not a subroutine, but just a
+! piece of code that computes the jump-
+! address and jumps to it.
+! traps if resulting address is zero
+!
+! On entry: r3 = address of CSA table
+!           r4 = value
+
+.define .csa
+.csa:
+	lwz r5, 0(r3)            ! load default
+	mtspr ctr, r5
+	
+	lwz r5, 4(r3)            ! fetch lower bound
+	subf. r4, r5, r4         ! adjust value
+	bcctr IFTRUE, LT, 0      ! jump to default if out of range
+	
+	lwz r5, 8(r3)            ! fetch range
+	cmp cr0, 0, r4, r5
+	bcctr IFTRUE, GT, 0      ! jump to default if out of range
+	
+	addi r3, r3, 12          ! skip header
+	rlwinm r4, r4, 2, 0, 31-2 ! scale value (<<2)
+	b 1f
+1:
+	lwzx r5, r3, r4          ! load target
+	b 1f
+1:
+	mtspr ctr, r5
+	 
+	or. r5, r5, r5           ! test it
+	b 1f
+1:
+	bcctr IFFALSE, EQ, 0     ! jump to target if non-zero
+	b .trap_ecase            ! otherwise trap

+ 39 - 0
mach/powerpc/libem/csb.s

@@ -0,0 +1,39 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! this is not a subroutine, but just a
+! piece of code that computes the jump-
+! address and jumps to it.
+! traps if resulting address is zero
+!
+! On entry: r3 = address of CSB table
+!           r4 = value
+
+.define .csb
+.csb:
+	lwz r5, 0(r3)            ! load default
+	mtspr ctr, r5
+	
+	lwz r6, 4(r3)            ! fetch count
+	
+1:
+	or. r6, r6, r6           ! test count
+	bcctr IFTRUE, EQ, 0      ! exit if zero
+	addi r6, r6, -1          ! otherwise decrement
+	
+	lwzu r7, 8(r3)           ! fetch target index, increment pointer
+	cmp cr0, 0, r4, r7       ! compare with value
+	bc IFFALSE, EQ, 1b       ! if not equal, go again
+	
+	lwz r7, 4(r3)            ! fetch target address
+	mtspr ctr, r7
+	
+	or. r7, r7, r7           ! test it
+	bcctr IFFALSE, EQ, 0     ! jump to target if non-zero
+	b .trap_ecase            ! otherwise trap

+ 33 - 0
mach/powerpc/libem/cuf8.s

@@ -0,0 +1,33 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! Converts a 32-bit unsigned integer into a 64-bit double.
+!
+! Stack: ( uint -- double )
+
+.define .cuf8
+.cuf8:
+	addi sp, sp, -4          ! make space for the double
+	
+	addis r3, r0, 0x4330
+	stw r3, 0(sp)            ! set high word to construct a double
+	
+	lfd f0, 0(sp)            ! load value
+	
+	la (r3, pivot)
+	lfd f1, 0(r3)            ! load pivot value
+	fsub f0, f0, f1          ! adjust
+	                         
+	stfd f0, 0(sp)           ! save value again...
+	bclr ALWAYS, 0, 0        ! ...and return 
+
+.sect .rom
+pivot:
+	.data4 0x43300000
+	.data4 0x00000000

+ 17 - 0
mach/powerpc/libem/fd_00000000.s

@@ -0,0 +1,17 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .rom
+
+! Contains a handy double-precision zero. (Also works as a single-precision
+! zero.)
+
+.define .fd_00000000, .fs_00000000
+.fd_00000000:
+.fs_00000000:
+	.data4 0x00000000
+	.data4 0x00000000

+ 15 - 0
mach/powerpc/libem/fd_80000000.s

@@ -0,0 +1,15 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .rom
+
+! Contains a handy double-precision 0x80000000.
+
+.define .fd_80000000
+.fd_80000000:
+	!float 2.147483648e+9 sz 8
+	.data1 0101,0340,00,00,00,00,00,00

+ 15 - 0
mach/powerpc/libem/fd_FFFFFFFF.s

@@ -0,0 +1,15 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .rom
+
+! Contains a handy double-precision 0xFFFFFFFF.
+
+.define .fd_FFFFFFFF
+.fd_FFFFFFFF:	
+	!float 4.294967295e+9 sz 8
+	.data1 0101,0357,0377,0377,0377,0340,00,00

+ 46 - 0
mach/powerpc/libem/fef8.c

@@ -0,0 +1,46 @@
+/*
+ * $Source$
+ * $State$
+ * $Revision$
+ */
+
+/* no headers allowed! */
+
+/* Given a double, calculates the mantissa and exponent.
+ * 
+ * This function is intended to be called internally by the code generator,
+ * so the calling convention is odd.
+ */
+
+int __fef8(double* fp)
+{
+	double f = *fp;
+	int exponent, sign;
+
+	if (f == 0.0)
+		return 0;
+		
+	if (f < 0.0)
+	{
+		sign = -1;
+		f = -f;
+	}
+	else
+		sign = 0;
+	
+	exponent = 0;
+	while (f >= 1.0)
+	{
+		f /= 2.0;
+		exponent++;
+	}
+	
+	while (f < 0.5)
+	{
+		f *= 2.0;
+		exponent--;
+	}
+	
+	*fp = (sign) ? -f : f;
+	return exponent;
+}

+ 38 - 0
mach/powerpc/libem/fif8.s

@@ -0,0 +1,38 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! Multiplies two floats, and returns the fraction and integer.
+
+.define .fif8
+.fif8:
+	lfd f0, 8(sp)
+	lfd f1, 0(sp)
+	fmul f0, f0, f1
+	fabs f1, f0              ! f0 = result
+	
+	! The following chunk does f1 = floor(f1). See page 158 of the book.
+	
+	mtfsfi cr7, 3              ! set rounding mode to -inf.
+	mtfsb0 23
+	fctid f2, f1
+	fcfid f2, f2
+	mcrfs cr7, cr5
+	bc IFFALSE, 31, toobig
+	fmr f1, f2
+toobig:
+
+	fabs f2, f1              ! f2 = fabs(f1)
+	fsub f2, f2, f1
+	stfd f2, 8(sp)
+	
+	fneg f2, f1
+	fsel f2, f0, f1, f2
+	stfd f2, 0(sp)
+	
+	bclr ALWAYS, 0, 0

+ 54 - 0
mach/powerpc/libem/los.s

@@ -0,0 +1,54 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! Loads a variable-sized structure onto the stack.
+!
+!     r3 = size
+!     r4 = address
+
+.define .los
+.los:
+	! These sizes are handled specially.
+	
+	cmpi cr0, 0, r3, 1
+	bc IFFALSE, GT, size1
+	
+	cmpi cr0, 0, r3, 2
+	bc IFFALSE, GT, size2
+	
+	cmpi cr0, 0, r3, 4
+	bc IFFALSE, GT, size4
+	
+	! Variable-sized structure.
+	
+	addi r3, r3, 3
+	andi. r3, r3, ~3         ! align size
+	
+	add r4, r4, r3           ! adjust address to top of block
+
+	srawi r3, r3, 2          ! convert size to the number of words
+	mtspr ctr, r3
+	
+1:
+	lwzu r5, -4(r4)
+	stwu r5, -4(sp)
+	bc DNZ, 0, 1b            ! decrement CTR, jump if non-zero
+	bclr ALWAYS, 0, 0
+	
+size1:
+	lbz r3, 0(r4)
+	b 1f
+size2:
+	lhz r3, 0(r4)
+	b 1f
+size4:
+	lwz r3, 0(r4)
+1:
+	stwu r3, -4(sp)
+	bclr ALWAYS, 0, 0

+ 30 - 0
mach/powerpc/libem/pmfile

@@ -0,0 +1,30 @@
+-- $Source$
+-- $State$
+-- $Revision$
+
+local d = ROOTDIR.."mach/powerpc/libem/"
+
+libem_powerpc = acklibrary {
+	outputs = {"%U%/libem-%PLATFORM%.a"},
+
+	ACKINCLUDES = {PARENT, d},
+	
+	ackfile (d.."ret.s"),
+	ackfile (d.."tge.s"),
+	ackfile (d.."csa.s"),
+	ackfile (d.."csb.s"),
+	ackfile (d.."los.s"),
+	ackfile (d.."sts.s"),
+	ackfile (d.."aar4.s"),
+	ackfile (d.."fef8.c"),
+	ackfile (d.."fif8.s"),
+	ackfile (d.."cif8.s"),
+	ackfile (d.."cuf8.s"),
+	ackfile (d.."cfi8.s"),
+	ackfile (d.."cfu8.s"),
+	ackfile (d.."fd_00000000.s"),
+	ackfile (d.."fd_80000000.s"),
+	ackfile (d.."fd_FFFFFFFF.s"),
+
+	install = pm.install("%BINDIR%lib/%PLATFORM%/libem.a"),
+}

+ 23 - 0
mach/powerpc/libem/powerpc.h

@@ -0,0 +1,23 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+#define IFFALSE 4
+#define IFTRUE 12
+#define ALWAYS 20
+#define DNZ 16
+
+#define LT 0
+#define GT 1
+#define EQ 2
+#define OV 3
+	
+#define la(reg, val) addis reg, r0, <val; ori reg, reg, >val

+ 19 - 0
mach/powerpc/libem/ret.s

@@ -0,0 +1,19 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+
+.sect .text
+	
+! Standard boilerplate for returning from functions.
+
+.define .ret
+.ret:
+	lwz r0, 4(fp)
+	mtspr lr, r0
+	lwz r0, 0(fp)            ! our stack frame becomes invalid as soon as...
+	addi sp, fp, 8           ! ...we change sp
+	or fp, r0, r0
+	bclr ALWAYS, 0, 0

+ 57 - 0
mach/powerpc/libem/sts.s

@@ -0,0 +1,57 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+	
+.sect .text
+
+! Stores a variable-sized structure from the stack.
+!
+!     r3 = size
+!     r4 = address
+
+.define .sts
+.sts:
+	! These sizes are handled specially.
+	
+	lwz r5, 0(sp)
+
+	cmpi cr0, 0, r3, 1
+	bc IFFALSE, GT, size1
+	
+	cmpi cr0, 0, r3, 2
+	bc IFFALSE, GT, size2
+	
+	cmpi cr0, 0, r3, 4
+	bc IFFALSE, GT, size4
+	
+	! Variable-sized structure.
+	
+	addi r3, r3, 3
+	andi. r3, r3, ~3         ! align size
+	
+	srawi r3, r3, 2          ! convert size to the number of words
+	mtspr ctr, r3
+	
+1:
+	lwz r5, 0(sp)
+	addi sp, sp, 4
+	stw r5, 0(r4)
+	addi r4, r4, 4
+
+	bc DNZ, 0, 1b            ! decrement CTR, jump if non-zero
+	bclr ALWAYS, 0, 0
+	
+size1:
+	stb r5, 0(r4)
+	b 1f
+size2:
+	sth r5, 0(r4)
+	b 1f
+size4:
+	stw r5, 0(r4)
+1:
+	addi sp, sp, 4
+	bclr ALWAYS, 0, 0

+ 46 - 0
mach/powerpc/libem/tge.s

@@ -0,0 +1,46 @@
+#
+! $Source$
+! $State$
+! $Revision$
+
+#include "powerpc.h"
+
+.sect .rom
+
+! Lookup table for tge.
+
+.define .teq_table
+.teq_table:
+	.data4 1       ! . .
+	.data4 0       ! . G
+	.data4 0       ! L .
+
+.define .tne_table
+.tne_table:
+	.data4 0       ! . .
+	.data4 1       ! . G
+	.data4 1       ! L .
+
+.define .tgt_table
+.tgt_table:
+	.data4 0       ! . .
+	.data4 1       ! . G
+	.data4 0       ! L .
+
+.define .tge_table
+.tge_table:
+	.data4 1       ! . .
+	.data4 1       ! . G
+	.data4 0       ! L .
+
+.define .tlt_table
+.tlt_table:
+	.data4 0       ! . .
+	.data4 0       ! . G
+	.data4 1       ! L .
+
+.define .tle_table
+.tle_table:
+	.data4 1       ! . .
+	.data4 0       ! . G
+	.data4 1       ! L .

+ 5 - 0
mach/powerpc/libend/.distr

@@ -0,0 +1,5 @@
+pmfile
+edata.s
+em_end.s
+end.s
+etext.s

+ 5 - 0
mach/powerpc/libend/LIST

@@ -0,0 +1,5 @@
+end_s.a
+edata.s
+em_end.s
+end.s
+etext.s

+ 9 - 0
mach/powerpc/libend/edata.s

@@ -0,0 +1,9 @@
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define	_edata
+.sect .data
+	.align 4
+	.sect .data
+_edata:

+ 24 - 0
mach/powerpc/libend/em_end.s

@@ -0,0 +1,24 @@
+! $Source$
+! $State$
+! $Revision$
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.sect .end ! only for declaration of _end, __end and endbss.
+.define	endtext, endrom, enddata, endbss, __end
+
+	.sect .text
+	.align 4
+endtext:
+	.sect .rom
+	.align 4
+endrom:
+	.sect .data
+	.align 4
+enddata:
+	.sect .end
+	.align 4
+__end:
+endbss:

+ 7 - 0
mach/powerpc/libend/end.s

@@ -0,0 +1,7 @@
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define	_end
+.sect .end ! only for declaration of _end, __end and endbss.
+_end:

+ 9 - 0
mach/powerpc/libend/etext.s

@@ -0,0 +1,9 @@
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define	_etext
+.sect .text
+	.align 4
+	.sect .text
+_etext:

+ 16 - 0
mach/powerpc/libend/pmfile

@@ -0,0 +1,16 @@
+-- $Source$
+-- $State$
+-- $Revision$
+
+local d = ROOTDIR.."mach/powerpc/libend/"
+
+libend_powerpc = acklibrary {
+	outputs = {"%U%/libend-%PLATFORM%.a"},
+
+	ackfile (d.."edata.s"),
+	ackfile (d.."em_end.s"),
+	ackfile (d.."end.s"),
+	ackfile (d.."etext.s"),
+
+	install = pm.install("%BINDIR%lib/%PLATFORM%/libend.a"),
+}

+ 3 - 0
mach/powerpc/ncg/.distr

@@ -0,0 +1,3 @@
+mach.c
+mach.h
+table

+ 209 - 0
mach/powerpc/ncg/mach.c

@@ -0,0 +1,209 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ *
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+
+#ifndef NORCSID
+static char rcsid[]=	"$Id$" ;
+#endif
+
+int framesize;
+
+/*
+ * machine dependent back end routines for the Zilog Z80.
+ */
+
+con_part(int sz, word w)
+{
+	while (part_size % sz)
+		part_size++;
+	if (part_size == TEM_WSIZE)
+		part_flush();
+	if (sz == 1) {
+		w &= 0xFF;
+		w <<= 8*(3-part_size);
+		part_word |= w;
+	} else if (sz == 2) {
+		w &= 0xFFFF;
+		if (part_size == 0) {
+			/* Shift 8 for m68k2, 16 otherwise */
+			w <<= 4 * TEM_WSIZE;
+		}
+		part_word |= w;
+	} else {
+		assert(sz == TEM_WSIZE);
+		part_word = w;
+	}
+	part_size += sz;
+}
+
+con_mult(word sz)
+{
+
+	if (argval != 4)
+		fatal("bad icon/ucon size");
+	fprintf(codefile,".data4 %s\n", str);
+}
+
+#define CODE_GENERATOR  
+#define IEEEFLOAT  
+#define FL_MSL_AT_LOW_ADDRESS	1
+#define FL_MSW_AT_LOW_ADDRESS	1
+#define FL_MSB_AT_LOW_ADDRESS	1
+#include <con_float>
+
+prolog(full nlocals)
+{
+	int ss = nlocals + 8;
+	fprintf(codefile, "addi sp, sp, %d\n", -ss);
+	fprintf(codefile, "stw fp, %d(sp)\n", nlocals);
+	fprintf(codefile, "mfspr r0, lr\n"
+	                  "stw r0, %d(sp)\n", nlocals+4);
+	fprintf(codefile, "addi fp, sp, %d\n", nlocals);
+	
+	framesize = nlocals;
+}
+
+mes(word type)
+{
+	int argt ;
+
+	switch ( (int)type ) {
+	case ms_ext :
+		for (;;) {
+			switch ( argt=getarg(
+			    ptyp(sp_cend)|ptyp(sp_pnam)|sym_ptyp) ) {
+			case sp_cend :
+				return ;
+			default:
+				strarg(argt) ;
+				fprintf(codefile,".define %s\n",argstr) ;
+				break ;
+			}
+		}
+	default :
+		while ( getarg(any_ptyp) != sp_cend ) ;
+		break ;
+	}
+}
+
+char *segname[] = {
+	".sect .text",
+	".sect .data",
+	".sect .rom",
+	".sect .bss"
+};
+
+#ifdef REGVARS
+
+static int savedregsi[32];
+static int numsaved;
+
+/* Initialise regvar system for one function. */
+
+i_regsave()
+{
+	int i;
+	
+	fprintf(codefile, "! i_regsave()\n");
+	for (i=0; i<32; i++)
+		savedregsi[i] = INT_MAX;
+	numsaved = 0;
+}
+
+/* Mark a register as being saved. */
+
+regsave(const char* regname, full offset, int size)
+{
+	int regnum = atoi(regname+1);
+	savedregsi[regnum] = offset;
+	numsaved++;
+	
+	fprintf(codefile, "! %d is saved in %s\n", offset, regname);
+#if 0
+	fprintf(codefile, "stwu %s, -4(sp)\n", regname);
+	if (offset >= 0)
+		fprintf(codefile, "lwz %s, %d(fp)\n", regname, offset);
+#endif
+}
+
+/* Finish saving ragisters. */
+
+void saveloadregs(const char* ops, const char* opm)
+{
+	int offset = -(framesize + numsaved*4);
+	int reg = 32;
+	
+	/* Check for the possibility of a multiple. */
+	
+	do
+	{
+		reg--;
+	}
+	while ((reg > 0) && (savedregsi[reg] != INT_MAX));
+	if (reg < 31)
+	{
+		fprintf(codefile, "%s r%d, %d(fp)\n", opm, reg+1, offset);
+		offset += (31-reg)*4;
+	}
+	
+	/* Saved everything else singly. */
+	
+	while (reg > 0)
+	{
+		if (savedregsi[reg] != INT_MAX)
+		{
+			fprintf(codefile, "%s r%d, %d(fp)\n", ops, reg, offset);
+			offset += 4;
+		}
+		reg--;
+	}
+}
+
+f_regsave()
+{
+	int i;
+	fprintf(codefile, "! f_regsave()\n");
+	fprintf(codefile, "addi sp, sp, %d\n", -numsaved*4);
+	
+	saveloadregs("stw", "stmw");
+	
+	for (i=0; i<32; i++)
+		if ((savedregsi[i] != INT_MAX) && (savedregsi[i] > 0))
+			fprintf(codefile, "lwz r%d, %d(fp)\n", i, savedregsi[i]);
+}
+
+/* Restore all saved registers. */
+
+regreturn()
+{
+	fprintf(codefile, "! regreturn()\n");
+	saveloadregs("lwz", "lmw");
+}
+
+/* Calculate the score of a given register. */
+
+int regscore(full offset, int size, int type, int frequency, int totype)
+{
+	int score;
+	
+	fprintf(codefile, "! regscore(%ld, %d, %d, %d, %d)\n", offset, size, type, frequency, totype);
+	
+	if (size != 4)
+		return -1;
+	
+	/* Per use: 6 bytes (on average)
+	 * Overhead in prologue: 4 bytes, plus 4 if a parameter
+	 * Overhead in epilogue: 0 bytes
+	 */
+	 
+	score = frequency*6 - 4 - ((offset>=0) ? 4 : 0);
+	fprintf(codefile, "! local at offset %d has regvar score %d\n", offset, score);
+	return score;
+}
+
+#endif

+ 30 - 0
mach/powerpc/ncg/mach.h

@@ -0,0 +1,30 @@
+/*
+ * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ * See the copyright notice in the ACK home directory, in the file "Copyright".
+ */
+/* $Id$ */
+#define ex_ap(y)        fprintf(codefile,".extern %s\n",y)
+#define in_ap(y)        /* nothing */
+
+#define newilb(x)       fprintf(codefile,"%s:\n",x)
+#define newdlb(x)       fprintf(codefile,"%s:\n",x)
+#define dlbdlb(x,y)     fprintf(codefile,"%s = %s\n",x,y)
+#define newlbss(l,x)       fprintf(codefile,".comm %s,%u\n",l,x);
+
+#define cst_fmt         "%d"
+#define off_fmt         "%d"
+#define ilb_fmt         "I%x_%x"
+#define dlb_fmt         "_%d"
+#define hol_fmt         "hol%d"
+
+#define hol_off         "%ld+hol%d"
+
+#define con_cst(x)      fprintf(codefile,".data4\t%ld\n",x)
+#define con_ilb(x)      fprintf(codefile,".data4\t%s\n",x)
+#define con_dlb(x)      fprintf(codefile,".data4\t%s\n",x)
+
+#define fmt_id(sf, st)	sprintf(st,"_%s",sf)
+
+#define modhead	".sect .text; .sect .rom; .sect .data; .sect .bss\n"
+
+#define BSS_INIT        0

+ 2161 - 0
mach/powerpc/ncg/table

@@ -0,0 +1,2161 @@
+EM_WSIZE = 4
+EM_PSIZE = 4
+EM_BSIZE = 8    /* two words saved in call frame */
+
+INT8 = 1        /* Size of values */
+INT16 = 2
+INT32 = 4
+INT64 = 8
+
+FP_OFFSET = 0   /* Offset of saved FP relative to our FP */
+PC_OFFSET = 4   /* Offset of saved PC relative to our FP */
+
+#define COMMENT(n) /* noop */
+
+
+#define nicesize(x) ((x)==INT8 || (x)==INT16 || (x)==INT32 || (x)==INT64)
+
+#define smalls(n) sfit(n, 16)
+#define smallu(n) ufit(n, 16)
+
+#define lo(n) (n & 0xFFFF)
+#define hi(n) ((n>>16) & 0xFFFF)
+
+/* Use these for instructions that treat the low half as signed --- his()
+ * includes a modifier to produce the correct value when the low half gets
+ * sign extended. Er, do make sure you load the low half second. */
+#define los(n) (n & 0xFFFF)
+#define his(n) ((hi(n) - (lo(n)>>15)) & 0xFFFF)
+
+#define IFFALSE {CONST, 4}
+#define IFTRUE {CONST, 12}
+#define ALWAYS {CONST, 20}
+#define DCTRZ {CONST, 34}
+
+#define LT {CONST, 0}
+#define GT {CONST, 1}
+#define EQ {CONST, 2}
+
+
+
+PROPERTIES
+
+	GPR             /* any GPR */
+	REG             /* any allocatable GPR */
+	FPR             /* any FPR */
+	FREG            /* any allocatable FPR */
+	SPR             /* any SPR */
+	CR              /* any CR */
+	
+	GPR0  GPRSP GPRFP GPR3  GPR4  GPR5  GPR6  GPR7
+	GPR8  GPR9  GPR10 GPR11 GPR12 GPR13 GPR14 GPR15
+	GPR16 GPR17 GPR18 GPR19 GPR20 GPR21 GPR22 GPR23
+	GPR24 GPR25 GPR26 GPR27 GPR28 GPR29 GPR30 GPR31
+	
+	CR0   CR1
+	
+	FPR0  FPR1  FPR2  FPR3  FPR4  FPR5  FPR6  FPR7
+	FPR8  FPR9  FPR10 FPR11 FPR12 FPR13 FPR14 FPR15
+	FPR16 FPR17 FPR18 FPR19 FPR20 FPR21 FPR22 FPR23
+	FPR24 FPR25 FPR26 FPR27 FPR28 FPR29 FPR30 FPR31
+	
+REGISTERS
+
+	/* Reverse order to encourage ncg to allocate them from r31 down */
+	
+	R31("r31")         : GPR, REG, GPR31 regvar.
+	R30("r30")         : GPR, REG, GPR30 regvar.
+	R29("r29")         : GPR, REG, GPR29 regvar.
+	R28("r28")         : GPR, REG, GPR28 regvar.
+	R27("r27")         : GPR, REG, GPR27 regvar.
+	R26("r26")         : GPR, REG, GPR26 regvar.
+	R25("r25")         : GPR, REG, GPR25 regvar.
+	R24("r24")         : GPR, REG, GPR24 regvar.
+	R23("r23")         : GPR, REG, GPR23 regvar.
+	R22("r22")         : GPR, REG, GPR22 regvar.
+	R21("r21")         : GPR, REG, GPR21 regvar.
+	R20("r20")         : GPR, REG, GPR20 regvar.
+	R19("r19")         : GPR, REG, GPR19 regvar.
+	R18("r18")         : GPR, REG, GPR18 regvar.
+	R17("r17")         : GPR, REG, GPR17 regvar.
+	R16("r16")         : GPR, REG, GPR16 regvar.
+	R15("r15")         : GPR, REG, GPR15 regvar.
+	R14("r14")         : GPR, REG, GPR14 regvar.
+	R13("r13")         : GPR, REG, GPR13 regvar.
+	R12("r12")         : GPR, REG, GPR12.
+	R11("r11")         : GPR, GPR11.
+	R10("r10")         : GPR, REG, GPR10.
+	R9("r9")           : GPR, REG, GPR9.
+	R8("r8")           : GPR, REG, GPR8.
+	R7("r7")           : GPR, REG, GPR7.
+	R6("r6")           : GPR, REG, GPR6.
+	R5("r5")           : GPR, REG, GPR5.
+	R4("r4")           : GPR, REG, GPR4.
+	R3("r3")           : GPR, REG, GPR3.
+	FP("fp")           : GPR, GPRFP.
+	SP("sp")           : GPR, GPRSP.
+	R0("r0")           : GPR, GPR0.
+	
+	F31("f31")         : FPR, FREG, FPR31.
+	F30("f30")         : FPR, FREG, FPR30.
+	F29("f29")         : FPR, FREG, FPR29.
+	F28("f28")         : FPR, FREG, FPR28.
+	F27("f27")         : FPR, FREG, FPR27.
+	F26("f26")         : FPR, FREG, FPR26.
+	F25("f25")         : FPR, FREG, FPR25.
+	F24("f24")         : FPR, FREG, FPR24.
+	F23("f23")         : FPR, FREG, FPR23.
+	F22("f22")         : FPR, FREG, FPR22.
+	F21("f21")         : FPR, FREG, FPR21.
+	F20("f20")         : FPR, FREG, FPR20.
+	F19("f19")         : FPR, FREG, FPR19.
+	F18("f18")         : FPR, FREG, FPR18.
+	F17("f17")         : FPR, FREG, FPR17.
+	F16("f16")         : FPR, FREG, FPR16.
+	F15("f15")         : FPR, FREG, FPR15.
+	F14("f14")         : FPR, FREG, FPR14.
+	F13("f13")         : FPR, FREG, FPR13.
+	F12("f12")         : FPR, FREG, FPR12.
+	F11("f11")         : FPR, FREG, FPR11.
+	F10("f10")         : FPR, FREG, FPR10.
+	F9("f9")           : FPR, FREG, FPR9.
+	F8("f8")           : FPR, FREG, FPR8.
+	F7("f7")           : FPR, FREG, FPR7.
+	F6("f6")           : FPR, FREG, FPR6.
+	F5("f5")           : FPR, FREG, FPR5.
+	F4("f4")           : FPR, FREG, FPR4.
+	F3("f3")           : FPR, FREG, FPR3.
+	F2("f2")           : FPR, FREG, FPR2.
+	F1("f1")           : FPR, FREG, FPR1.
+	F0("f0")           : FPR, FREG, FPR0.
+
+	LR("lr")           : SPR.
+	CTR("ctr")         : SPR.
+	C0("cr0")          : CR, CR0.
+
+#define SCRATCH R11
+#define FSCRATCH F0
+
+
+TOKENS
+
+/* Used only in instruction descriptions (to generate the correct syntax). */
+
+	GPRINDIRECT        = { GPR reg; INT off; }    4    off "(" reg ")".
+	GPRINDIRECTLO      = { GPR reg; ADDR adr; }   4    ">" adr "(" reg ")". /* Warning! Do not use on labels. */
+	HILABEL            = { ADDR adr; }            4    "<" adr.
+	LOLABEL            = { ADDR adr; }            4    ">" adr.
+
+/* Primitives */
+
+	LABEL              = { ADDR adr; }            4    adr.
+	CONST              = { INT val; }             4    val.
+	LOCAL              = { INT off; }             4.
+
+/* Allows us to use regvar() to refer to registers */
+
+	GPRE               = { GPR reg; }             4    reg.
+
+/* Expression partial results */
+	
+	SUM_RC             = { GPR reg; INT off; }    4.
+	SUM_RR             = { GPR reg1; GPR reg2; }  4.
+	
+	TRISTATE_RC_S      = { GPR reg; INT val; }    4.
+	TRISTATE_RC_U      = { GPR reg; INT val; }    4.
+	TRISTATE_RR_S      = { GPR reg1; GPR reg2; }  4.
+	TRISTATE_RR_U      = { GPR reg1; GPR reg2; }  4.
+	
+	TRISTATE_FF        = { FPR reg1; FPR reg2; }  4.
+	
+	SEX_B              = { GPR reg; }             4.
+	SEX_H              = { GPR reg; }             4.
+	
+	IND_RC_B           = { GPR reg; INT off; }    4.
+	IND_RC_H           = { GPR reg; INT off; }    4.
+	IND_RC_H_S         = { GPR reg; INT off; }    4.
+	IND_RC_W           = { GPR reg; INT off; }    4.
+	IND_RR_W           = { GPR reg1; GPR reg2; }  4.
+	IND_LABEL_W        = { ADDR adr; }            4.
+	IND_RC_D           = { GPR reg; INT off; }    8.
+	IND_RR_D           = { GPR reg1; GPR reg2; }  8.
+	IND_LABEL_D        = { ADDR adr; }            8.
+	
+	NOT_R              = { GPR reg; }             4.
+	
+	AND_RR             = { GPR reg1; GPR reg2; }  4.
+	AND_RC             = { GPR reg; INT val; }  4.
+	OR_RR              = { GPR reg1; GPR reg2; }  4.
+	OR_RC              = { GPR reg; INT val; }  4.
+	XOR_RR             = { GPR reg1; GPR reg2; }  4.
+	XOR_RC             = { GPR reg; INT val; }  4.
+
+/* Floats */
+
+    FD                 = { FPR reg; }             8 reg.
+    FS                 = { FPR reg; }             4 reg.
+    
+/* Comments */
+
+	LABELI             = { ADDR msg; INT num; }   4    msg " " num.
+
+
+
+
+SETS
+
+	TOKEN              = LABEL + CONST + LOCAL.
+	GPRI               = GPR + GPRE.
+	
+	SUM_ALL            = SUM_RC + SUM_RR.
+	
+	TRISTATE_ALL       = TRISTATE_RC_S + TRISTATE_RC_U + TRISTATE_RR_S +
+	                     TRISTATE_RR_U + TRISTATE_FF.
+	
+	SEX_ALL            = SEX_B + SEX_H.
+	
+	LOGICAL_ALL        = NOT_R + AND_RR + AND_RC + OR_RR + OR_RC + XOR_RR +
+	                     XOR_RC.
+	
+	IND_ALL_W          = IND_RC_W + IND_RR_W + IND_LABEL_W.
+
+	IND_ALL_D          = IND_RC_D + IND_RR_D + IND_LABEL_D.
+	
+	OP_ALL_W           = SUM_ALL + TRISTATE_ALL + SEX_ALL + LOGICAL_ALL +
+	                     IND_ALL_W.
+
+
+INSTRUCTIONS
+
+  add             GPRI:wo, GPRI:ro, GPRI:ro.
+  addX "add."     GPRI:wo, GPRI:ro, GPRI:ro.
+  addi            GPRI:wo, GPRI:ro, CONST:ro.
+  addis           GPRI:wo, GPRI:ro, CONST+HILABEL:ro.
+  and             GPRI:wo, GPRI:ro, GPRI:ro.
+  andc            GPRI:wo, GPRI:ro, GPRI:ro.
+  andiX  "andi."  GPRI:wo, GPRI:ro, CONST:ro kills :cc.
+  andisX "andis." GPRI:wo, GPRI:ro, CONST:ro kills :cc.
+  b               LABEL:ro.
+  bc              CONST:ro, CONST:ro, LABEL:ro.
+  bcctr           CONST:ro, CONST:ro, CONST:ro.
+  bcctrl          CONST:ro, CONST:ro, CONST:ro.
+  bclr            CONST:ro, CONST:ro, CONST:ro.
+  bl              LABEL:ro.
+  cmp             CR:ro, CONST:ro, GPRI:ro, GPR:ro kills :cc.
+  cmpi            CR:ro, CONST:ro, GPRI:ro, CONST:ro kills :cc.
+  cmpl            CR:ro, CONST:ro, GPRI:ro, GPR:ro kills :cc.
+  cmpli           CR:ro, CONST:ro, GPRI:ro, CONST:ro kills :cc.
+  divw            GPRI:wo, GPRI:ro, GPRI:ro.
+  divwu           GPRI:wo, GPRI:ro, GPRI:ro.
+  eqv             GPRI:wo, GPRI:ro, GPRI:ro.
+  extsb           GPRI:wo, GPRI:ro.
+  extsh           GPRI:wo, GPRI:ro.
+  fadd            FD:wo, FD:ro, FD:ro.
+  fadds           FS:wo, FS:ro, FS:ro.
+  fcmpo           CR:wo, FD:ro, FD:ro.
+  fdiv            FD:wo, FD:ro, FD:ro.
+  fdivs           FS:wo, FS:ro, FS:ro.
+  fneg            FS+FD:wo, FS+FD:ro.
+  fmul            FD:wo, FD:ro, FD:ro.
+  fmuls           FS:wo, FS:ro, FS:ro.
+  frsp            FS:wo, FD:ro.
+  fsub            FD:wo, FD:ro, FD:ro.
+  fsubs           FS:wo, FS:ro, FS:ro.
+  fmr             FS+FD:wo, FS+FD:ro.
+  lbzx            GPRI:wo, GPR:ro, GPR:ro.
+  lbz             GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lfd             FD:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lfdu            FD:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lfdx            FD:wo, GPR:ro, GPR:ro.
+  lfs             FS:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lfsu            FS:wo, GPRINDIRECT+GPRINDIRECTLO:rw.
+  lfsx            FS:wo, GPR:ro, GPR:ro.
+  lhzx            GPRI:wo, GPR:ro, GPR:ro.
+  lhax            GPRI:wo, GPR:ro, GPR:ro.
+  lha             GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lhz             GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lwzu            GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  lwzx            GPRI:wo, GPR:ro, GPR:ro.
+  lwz             GPRI:wo, GPRINDIRECT+GPRINDIRECTLO:ro.
+  nand            GPRI:wo, GPRI:ro, GPRI:ro.
+  neg             GPRI:wo, GPRI:ro.
+  nor             GPRI:wo, GPRI:ro, GPRI:ro.
+  mfcr            GPRI:wo.
+  mullw           GPRI:wo, GPRI:ro, GPRI:ro.
+  mfspr           GPRI:wo, SPR:ro.
+  mtspr           SPR:wo, GPRI:ro.
+  or              GPRI:wo, GPRI:ro, GPRI:ro.
+  orc             GPRI:wo, GPRI:ro, GPRI:ro.
+  ori             GPRI:wo, GPRI:ro, CONST+LOLABEL:ro.
+  orX "or."       GPRI:wo, GPRI:ro, GPRI:ro kills :cc.
+  rlwinm          GPRI:wo, GPRI:ro, CONST:ro, CONST:ro, CONST:ro.
+  slw             GPRI:wo, GPRI:ro, GPRI:ro.
+  subf            GPRI:wo, GPRI:ro, GPRI:ro.
+  sraw            GPRI:wo, GPRI:ro, GPRI:ro.
+  srawi           GPRI:wo, GPRI:ro, CONST:ro.
+  srw             GPRI:wo, GPRI:ro, GPRI:ro.
+  stb             GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stbx            GPRI:ro, GPR:ro, GPR:ro.
+  stfd            FD:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stfdu           FD:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stfdx           FD:ro, GPR:ro, GPR:ro.
+  stfs            FS:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stfsu           FS:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stfsx           FS:ro, GPR:ro, GPR:ro.
+  sth             GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  sthx            GPRI:ro, GPR:ro, GPR:ro.
+  stw             GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  stwx            GPRI:ro, GPR:ro, GPR:ro.
+  stwu            GPRI:ro, GPRINDIRECT+GPRINDIRECTLO:rw.
+  xor             GPRI:wo, GPRI:ro, GPRI:ro.
+  xori            GPRI:wo, GPRI:ro, CONST:ro.
+
+  gpr_gpr_gpr     GPRI:wo, GPRI:ro, GPRI:ro.
+  gpr_gpr_si      GPRI:wo, GPRI:ro, CONST:ro.
+  gpr_ro_gprindirect GPRI:ro, GPRINDIRECT:rw.
+  gpr_ro_gpr_gpr  GPRI:ro, GPRI:ro, GPRI:ro.
+  gpr_wo_gprindirect GPRI:wo, GPRINDIRECT:ro.
+  gpr_wo_gpr_gpr  GPRI:wo, GPRI:ro, GPRI:ro.
+  
+  invalid "invalid".
+  comment "!" LABEL+LABELI:ro.
+
+
+  
+MOVES
+
+	from GPR to GPR
+		gen
+			COMMENT("move GPR->GPR")
+			or %2, %1, %1
+
+/* GPRE exists solely to allow us to use regvar() (which can only be used in
+   an expression) as a register constant. */
+   
+	from GPR to GPRE
+		gen
+			COMMENT("move GPR->GPRE")
+			or %2, %1, %1
+		
+/* Constants */
+
+	from CONST smalls(%val) to GPR
+		gen
+			COMMENT("move CONST->GPRE")
+			addi %2, R0, {CONST, lo(%1.val)}
+		
+	from CONST to GPR
+		gen
+			COMMENT("move CONST->GPRE")
+			addis %2, R0, {CONST, hi(%1.val)}
+			ori %2, %2, {CONST, lo(%1.val)}
+		
+	from LABEL to GPR
+		gen
+			COMMENT("move LABEL->GPR")
+			addis %2, R0, {HILABEL, %1.adr}
+			ori %2, %2, {LOLABEL, %1.adr}
+	
+/* Sign extension */
+
+	from SEX_B to GPR
+		gen
+			COMMENT("move SEX_B->GPR")
+			extsb %2, %1.reg
+			
+	from SEX_H to GPR
+		gen
+			COMMENT("move SEX_H->GPR")
+			extsh %2, %1.reg
+					
+/* Register + something */
+
+	from SUM_RC smalls(%off) to GPR
+		gen	
+			COMMENT("move SUM_RC->GPR smalls")
+			addi %2, %1.reg, {CONST, lo(%1.off)}
+	
+	from SUM_RC to GPR
+		gen	
+			COMMENT("move SUM_RC->GPR large")
+			addi %2, %1.reg, {CONST, los(%1.off)}
+			addis %2, %2, {CONST, his(%1.off)}
+			
+	from SUM_RR to GPR
+		gen
+			COMMENT("move SUM_RR->GPR")
+			add %2, %1.reg1, %1.reg2
+		
+	from SUM_RR to GPR
+		gen
+			COMMENT("move SUM_RR->GPRE")
+			add %2, %1.reg1, %1.reg2
+		
+/* Read/write byte */
+
+	from IND_RC_B smalls(%off) to GPR
+		gen
+			COMMENT("move IND_RC_B->GPR small")
+			lbz %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_B to GPR
+		gen
+			COMMENT("move IND_RC_B->GPR large")
+			addis SCRATCH, %1.reg, {CONST, his(%1.off)}
+			lbz %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
+	
+	from GPR to IND_RC_B smalls(%off)
+		gen
+			COMMENT("move GPR->IND_RC_B small")
+			stb %1, {GPRINDIRECT, %2.reg, %2.off}
+	
+	from GPR to IND_RC_B
+		gen
+			COMMENT("move GPR->IND_RC_B large")
+			addis SCRATCH, %2.reg, {CONST, his(%2.off)}
+			stb %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
+	
+/* Read/write short */
+
+	from IND_RC_H smalls(%off) to GPR
+		gen
+			COMMENT("move IND_RC_H->GPR small")
+			lhz %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_H to GPR
+		gen
+			COMMENT("move IND_RC_H->GPR large")
+			addis SCRATCH, %1.reg, {CONST, his(%1.off)}
+			lhz %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
+	
+	from IND_RC_H_S smalls(%off) to GPR
+		gen
+			COMMENT("move IND_RC_H_S->GPR small")
+			lha %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_H_S to GPR
+		gen
+			COMMENT("move IND_RC_H_S->GPR large")
+			addis SCRATCH, %1.reg, {CONST, his(%1.off)}
+			lha %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
+	
+	from GPR to IND_RC_H smalls(%off)
+		gen
+			COMMENT("move GPR->IND_RC_H small")
+			sth %1, {GPRINDIRECT, %2.reg, %2.off}
+	
+	from GPR to IND_RC_H
+		gen
+			COMMENT("move GPR->IND_RC_H large")
+			addis SCRATCH, %2.reg, {CONST, his(%2.off)}
+			sth %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
+	
+/* Read word */
+
+	from IND_RC_W smalls(%off) to GPR
+		gen
+			COMMENT("move IND_RC_W->GPR small")
+			lwz %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_W to GPR
+		gen
+			COMMENT("move IND_RC_W->GPR large")
+			addis %2, %1.reg, {CONST, his(%1.off)}
+			lwz %2, {GPRINDIRECT, %2, los(%1.off)}
+
+	from IND_RR_W to GPR
+		gen
+			COMMENT("move IND_RR_W->GPR")
+			lwzx %2, %1.reg1, %1.reg2
+			
+	from IND_LABEL_W to GPR
+		gen
+			COMMENT("move IND_LABEL_W->GPR")
+			move {LABEL, %1.adr}, SCRATCH
+			lwz %2, {GPRINDIRECT, SCRATCH, 0}
+		
+	from IND_RC_W smalls(%off) to FS
+		gen
+			COMMENT("move IND_RC_W->FS small")
+			lfs %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_W to FS
+		gen
+			COMMENT("move IND_RC_W->FS large")
+			addis SCRATCH, %1.reg, {CONST, his(%1.off)}
+			lfs %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
+
+	from IND_RR_W to FS
+		gen
+			COMMENT("move IND_RR_W->FS")
+			lfsx %2, %1.reg1, %1.reg2
+			
+	from IND_LABEL_W to FS
+		gen
+			COMMENT("move IND_LABEL_W->FS")
+			move {LABEL, %1.adr}, SCRATCH
+			lfs %2, {GPRINDIRECT, SCRATCH, 0}
+		
+/* Write word */
+
+	from GPR to IND_RC_W smalls(%off)
+		gen
+			COMMENT("move GPR->IND_RC_W small")
+			stw %1, {GPRINDIRECT, %2.reg, %2.off}
+	
+	from GPR to IND_RC_W
+		gen
+			COMMENT("move GPR->IND_RC_W large")
+			addis SCRATCH, %2.reg, {CONST, his(%2.off)}
+			stw %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
+
+	from GPR to IND_RR_W
+		gen
+			COMMENT("move GPR->IND_RR_W")
+			stwx %1, %2.reg1, %2.reg2
+			
+	from GPR to IND_LABEL_W
+		gen
+			COMMENT("move GPR->IND_LABEL_D")
+			move {LABEL, %2.adr}, SCRATCH
+			stw %1, {GPRINDIRECT, SCRATCH, 0}
+			
+	from FS to IND_RC_W smalls(%off)
+		gen
+			COMMENT("move FS->IND_RC_W small")
+			stfs %1, {GPRINDIRECT, %2.reg, %2.off}
+	
+	from FS to IND_RC_W
+		gen
+			COMMENT("move FS->IND_RC_W large")
+			addis SCRATCH, %2.reg, {CONST, his(%2.off)}
+			stfs %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
+
+	from FS to IND_RR_W
+		gen
+			COMMENT("move FS->IND_RR_W")
+			stfsx %1, %2.reg1, %2.reg2
+
+	from FS to IND_LABEL_W
+		gen
+			COMMENT("move FS->IND_LABEL_D")
+			move {LABEL, %2.adr}, SCRATCH
+			stfs %1, {GPRINDIRECT, SCRATCH, 0}
+			
+/* Read double */
+
+	from IND_RC_D smalls(%off) to FD
+		gen
+			COMMENT("move IND_RC_D->FD small")
+			lfd %2, {GPRINDIRECT, %1.reg, %1.off}
+	
+	from IND_RC_D to FD
+		gen
+			COMMENT("move IND_RC_D->FD large")
+			addis SCRATCH, %1.reg, {CONST, his(%1.off)}
+			lfd %2, {GPRINDIRECT, SCRATCH, los(%1.off)}
+			
+	from IND_RR_D to FD
+		gen
+			COMMENT("move IND_RR_D->FD")
+			lfdx %2, %1.reg1, %1.reg2
+
+	from IND_LABEL_D to FD
+		gen
+			COMMENT("move IND_LABEL_D->FD")
+			move {LABEL, %1.adr}, SCRATCH
+			lfd %2, {GPRINDIRECT, SCRATCH, 0}
+		
+/* Write double */
+
+	from FD to IND_RC_D smalls(%off)
+		gen
+			COMMENT("move FD->IND_RC_D small")
+			stfd %1, {GPRINDIRECT, %2.reg, %2.off}
+	
+	from FD to IND_RC_D
+		gen
+			COMMENT("move FD->IND_RC_D large")
+			addis SCRATCH, %2.reg, {CONST, his(%2.off)}
+			stfd %1, {GPRINDIRECT, SCRATCH, los(%2.off)}
+
+	from FD to IND_RR_D
+		gen
+			COMMENT("move FD->IND_RR_W")
+			stfdx %1, %2.reg1, %2.reg2
+			
+	from FD to IND_LABEL_D
+		gen
+			COMMENT("move FD->IND_LABEL_D")
+			move {LABEL, %2.adr}, SCRATCH
+			stfd %1, {GPRINDIRECT, SCRATCH, 0}
+			
+/* Extract condition code field (actually produces (CC&3)<<2) */
+
+	from CR0 to GPR
+		gen
+			COMMENT("move CR0->GPR")
+			mfcr %2
+			rlwinm %2, %2, {CONST, 4}, {CONST, 32-4}, {CONST, 31-2}
+
+/* Comparisons */
+
+	from TRISTATE_RR_S to CR0
+		gen
+			cmp %2, {CONST, 0}, %1.reg1, %1.reg2
+			
+	from TRISTATE_RR_U to CR0
+		gen
+			cmpl %2, {CONST, 0}, %1.reg1, %1.reg2
+		
+	from TRISTATE_RC_S to CR0
+		gen
+			COMMENT("move TRISTATE_RC_S->CR0 large")
+			move {CONST, %1.val}, SCRATCH
+			cmp %2, {CONST, 0}, %1.reg, SCRATCH
+			
+	from TRISTATE_RC_U smallu(%val) to CR0
+		gen
+			COMMENT("move TRISTATE_RC_U->CR0 small")
+			cmpli %2, {CONST, 0}, %1.reg, {CONST, %1.val}
+		
+	from TRISTATE_RC_U to CR0
+		gen
+			COMMENT("move TRISTATE_RC_U->CR0")
+			move {CONST, %1.val}, SCRATCH
+			cmpl %2, {CONST, 0}, %1.reg, SCRATCH
+		
+	from TRISTATE_FF to CR0
+		gen
+			COMMENT("move TRISTATE_FF->CR0")
+			fcmpo %2, {FD, %1.reg1}, {FD, %1.reg2}
+			
+	from GPR to CR0
+		gen
+			COMMENT("move GPR->CR0")
+			orX SCRATCH, %1, %1 /* alas, can't call test */
+			
+	from TRISTATE_RR_S + TRISTATE_RC_S + TRISTATE_FF to GPR
+		gen
+			COMMENT("move TRISTATE_R*_S->GPR")
+			move %1, C0
+			move C0, SCRATCH
+			move {LABEL, ".tristate_s_table"}, %2
+			lwzx %2, %2, SCRATCH				
+
+	from TRISTATE_RR_U + TRISTATE_RC_U to GPR
+		gen
+			COMMENT("move TRISTATE_R*_U->GPR")
+			move %1, C0
+			move C0, SCRATCH
+			move {LABEL, ".tristate_u_table"}, %2
+			lwzx %2, %2, SCRATCH				
+
+/* Logicals */
+
+	from NOT_R to GPR
+		gen
+			COMMENT("move NOT_R->GPR")
+			nor %2, %1.reg, %1.reg
+
+	from AND_RR to GPR
+		gen
+			COMMENT("move AND_RR->GPR")
+			and %2, %1.reg1, %1.reg2
+
+	from AND_RC smallu(%val) to GPR
+		gen
+			COMMENT("move AND_RC->GPR small")
+			andiX %2, %1.reg, {CONST, %1.val}
+
+	from AND_RC to GPR
+		gen
+			COMMENT("move AND_RC->GPR")
+			move {CONST, %1.val}, SCRATCH
+			and %2, %1.reg, SCRATCH
+
+	from OR_RR to GPR
+		gen
+			COMMENT("move OR_RR->GPR")
+			or %2, %1.reg1, %1.reg2
+
+	from OR_RC smallu(%val) to GPR
+		gen
+			COMMENT("move OR_RC->GPR small")
+			ori %2, %1.reg, {CONST, %1.val}
+
+	from OR_RC to GPR
+		gen
+			COMMENT("move OR_RC->GPR")
+			move {CONST, %1.val}, SCRATCH
+			or %2, %1.reg, SCRATCH
+
+	from XOR_RR to GPR
+		gen
+			COMMENT("move XOR_RR->GPR")
+			xor %2, %1.reg1, %1.reg2
+
+	from XOR_RC smallu(%val) to GPR
+		gen
+			COMMENT("move XOR_RC->GPR small")
+			xori %2, %1.reg, {CONST, %1.val}
+
+	from XOR_RC to GPR
+		gen
+			COMMENT("move XOR_RC->GPR")
+			move {CONST, %1.val}, SCRATCH
+			xor %2, %1.reg, SCRATCH
+
+/* Miscellaneous */
+
+	from OP_ALL_W + LABEL + CONST to GPRE
+		gen
+			move %1, %2.reg
+
+		
+TESTS
+	
+	to test GPR
+		gen
+			orX SCRATCH, %1, %1
+
+
+
+STACKINGRULES
+	
+	from GPR to STACK
+		gen
+			COMMENT("stack GPR")
+			stwu %1, {GPRINDIRECT, SP, 0-4}
+	
+	from CONST to STACK
+		uses REG
+		gen
+			COMMENT("stack CONST")
+			move %1, %a
+			stwu %a, {GPRINDIRECT, SP, 0-4}
+			
+	from LABEL to STACK
+		uses REG
+		gen
+			COMMENT("stack LABEL")
+			move %1, {GPRE, %a}
+			stwu %a, {GPRINDIRECT, SP, 0-4}
+			
+	from SEX_B to STACK
+		gen
+			COMMENT("stack SEX_B")
+			extsb SCRATCH, %1.reg
+			stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
+			
+	from SEX_H to STACK
+		gen
+			COMMENT("stack SEX_H")
+			extsh SCRATCH, %1.reg
+			stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
+			
+	from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL to STACK
+		gen
+			move %1, {GPRE, SCRATCH}
+			stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
+			
+	from IND_ALL_W to STACK
+		gen
+			move %1, SCRATCH
+			stwu SCRATCH, {GPRINDIRECT, SP, 0-4}
+			
+	from IND_ALL_D to STACK
+		gen
+			move %1, {FD, FSCRATCH}
+			stfdu {FD, FSCRATCH}, {GPRINDIRECT, SP, 0-8}
+			
+	from FD to STACK
+		gen
+			COMMENT("stack FD")
+			stfdu %1, {GPRINDIRECT, SP, 0-8}
+			
+	from FS to STACK
+		gen
+			COMMENT("stack FS")
+			stfsu %1, {GPRINDIRECT, SP, 0-4}
+			
+	from TOKEN to STACK
+		gen
+			invalid.
+			
+		
+		
+COERCIONS
+
+	from REG
+		uses REG
+		gen
+			COMMENT("coerce REG->REG")
+			move %1, %a
+		yields %a
+		
+	from CONST
+		uses REG
+		gen
+			COMMENT("coerce CONST->REG")
+			move %1, %a
+		yields %a
+		
+	from LABEL
+		uses REG
+		gen
+			COMMENT("coerce LABEL->REG")
+			move %1, {GPRE, %a}
+		yields %a
+		
+	from STACK
+		uses REG
+		gen
+			COMMENT("coerce STACK->REG")
+			lwz %a, {GPRINDIRECT, SP, 0}
+			addi SP, SP, {CONST, 4}
+		yields %a
+	
+	from SEX_B
+		uses REG
+		gen
+			COMMENT("coerce SEX_B->REG")
+			extsb %a, %1.reg
+		yields %a
+		
+	from SEX_H
+		uses REG
+		gen
+			COMMENT("coerce SEX_H->REG")
+			extsh %a, %1.reg
+		yields %a
+	
+	from SUM_ALL + TRISTATE_ALL + LOGICAL_ALL
+		uses REG
+		gen
+			move %1, {GPRE, %a}
+		yields %a
+	
+	from FS
+		uses FREG
+		gen
+			fmr {FS, %a}, %1
+		yields {FS, %a}
+		
+	from FD
+		uses FREG
+		gen
+			fmr {FD, %a}, %1
+		yields {FD, %a}
+		
+	from STACK
+		uses FREG
+		gen
+			COMMENT("coerce STACK->FD")
+			lfd {FD, %a}, {GPRINDIRECT, SP, 0}
+			addi SP, SP, {CONST, 8}
+		yields {FD, %a}
+
+	from STACK
+		uses FREG
+		gen
+			COMMENT("coerce STACK->FS")
+			lfs {FS, %a}, {GPRINDIRECT, SP, 0}
+			addi SP, SP, {CONST, 4}
+		yields {FS, %a}
+		
+	from IND_ALL_W
+		uses REG
+		gen
+			move %1, %a
+		yields %a
+		
+	from IND_ALL_W
+		uses FREG
+		gen
+			move %1, {FS, %a}
+		yields {FS, %a}
+		
+	from IND_ALL_D
+		uses FREG
+		gen
+			move %1, {FD, %a}
+		yields {FD, %a}
+		
+	
+
+
+PATTERNS
+
+/* Intrinsics */
+
+	pat loc                            /* Load constant */
+		yields {CONST, $1}
+
+	pat dup $1==INT32                  /* Duplicate word on top of stack */
+		with GPR
+			yields %1 %1
+								
+	pat dup $1==INT64                  /* Duplicate double-word on top of stack */
+		with GPR GPR
+			yields %2 %1 %2 %1
+								
+	pat exg $1==INT32                  /* Exchange top two words on stack */
+		with GPR GPR
+			yields %1 %2
+		
+	pat stl lol $1==$2                 /* Store then load local */
+		leaving
+			dup 4
+			stl $1
+			
+	pat lal sti lal loi $1==$3 && $2==$4 /* Store then load local, of a different size */
+		leaving
+			dup INT32
+			lal $1
+			sti $2
+			
+	pat ste loe $1==$2                 /* Store then load external */
+		leaving
+			dup 4
+			ste $1
+		
+		
+/* Type conversions */
+
+	pat loc loc cii loc loc cii $1==$4 && $2==$5 /* madness, generated by the C compiler */
+		leaving
+			loc $1
+			loc $2
+			cii
+			
+	pat loc loc cii loc loc cii $2==INT32 && $5==INT32 && $4<$2 /* madness, generated by the C compiler */
+		leaving
+			loc $4
+			loc $5
+			cii
+			
+	pat loc loc ciu                    /* signed X -> unsigned X */
+		leaving
+			loc $1
+			loc $2
+			cuu
+			
+	pat loc loc cuu $1==$2             /* unsigned X -> unsigned X */
+		/* nop */
+
+	pat loc loc cii $1==$2             /* signed X -> signed X */
+		/* nop */
+
+	pat loc loc cui $1==$2             /* unsigned X -> signed X */
+		/* nop */
+		
+	pat loc loc cui $1==INT8 && $2==INT32 /* unsigned char -> signed int */
+		/* nop */
+	
+	pat loc loc cui $1==INT16 && $2==INT32 /* unsigned short -> signed int */
+		/* nop */
+	
+	pat loc loc cii $1==INT8 && $2==INT32 /* signed char -> signed int */
+		with GPR
+			yields {SEX_B, %1}
+	
+	pat loc loc cii $1==2 && $2==4     /* signed char -> signed short */
+		with GPR
+			yields {SEX_H, %1}
+	
+
+		
+	
+		
+/* Local variables */
+
+	pat lal                            /* Load address of local */
+		yields {SUM_RC, FP, $1}
+
+	pat lol inreg($1)>0                /* Load from local */
+		yields {LOCAL, $1}
+		
+	pat lol                            /* Load from local */
+		leaving
+			lal $1
+			loi INT32
+
+	pat ldl                            /* Load double-word from local */
+		leaving
+			lal $1
+			loi INT32*2
+			
+	pat stl inreg($1)>0                /* Store to local */
+		with CONST + LABEL + GPR + OP_ALL_W
+			kills regvar($1), LOCAL %off==$1
+			gen
+				move %1, {GPRE, regvar($1)}
+		
+	pat stl                            /* Store to local */
+		leaving
+			lal $1
+			sti INT32
+		
+	pat sdl                            /* Store double-word to local */
+		leaving
+			lal $1
+			sti INT32*2
+			
+	pat lil inreg($1)>0                /* Load from indirected local */
+		uses REG
+		gen
+			lwz %a, {GPRINDIRECT, regvar($1), 0}
+		yields %a
+		
+	pat lil                            /* Load from indirected local */
+		leaving
+			lol $1
+			loi INT32
+			
+	pat sil                            /* Save to indirected local */
+		leaving
+			lol $1
+			sti INT32
+			
+	pat stl lol $1==$2                 /* Save then load (generated by C compiler) */
+		leaving
+			dup 4
+			stl $1
+			
+	pat zrl                             /* Zero local */
+		leaving
+			loc 0
+			stl $1
+	
+	pat inl                             /* Increment local */
+		leaving
+			lol $1
+			loc 1
+			adi 4
+			stl $1
+					
+	pat del                             /* Decrement local */
+		leaving
+			lol $1
+			loc 1
+			sbi 4
+			stl $1
+
+
+/* Global variables */
+		
+	pat lpi                            /* Load address of external function */
+		leaving
+			lae $1
+				
+	pat lae                            /* Load address of external */
+		yields {LABEL, $1}
+		
+	pat loe                            /* Load word external */
+		leaving
+			lae $1
+			loi INT32
+
+	pat ste                            /* Store word external */
+		leaving
+			lae $1
+			sti INT32
+			
+	pat lde                            /* Load double-word external */
+		leaving
+			lae $1
+			loi INT64
+			
+	pat sde                            /* Store double-word external */
+		leaving
+			lae $1
+			sti INT64
+			
+	pat zre                             /* Zero external */
+		leaving
+			loc 0
+			ste $1
+	
+	pat ine                             /* Increment external */
+		uses REG={LABEL, $1}, REG
+			gen
+				lwz %b, {GPRINDIRECT, %a, 0}
+				addi %b, %b, {CONST, 1}
+				stw %b, {GPRINDIRECT, %a, 0}
+					
+	pat dee                             /* Decrement external */
+		uses REG={LABEL, $1}, REG
+			gen
+				lwz %b, {GPRINDIRECT, %a, 0}
+				addi %b, %b, {CONST, 0-1}
+				stw %b, {GPRINDIRECT, %a, 0}
+					
+
+
+/* Structures */
+
+	pat lof                            /* Load word offsetted */
+		leaving
+			adp $1
+			loi INT32
+			
+	pat ldf                            /* Load double-word offsetted */
+		leaving
+			adp $1
+			loi INT64
+			
+	pat stf                            /* Store word offsetted */
+		leaving
+			adp $1
+			sti INT32
+			
+	pat sdf                            /* Store double-word offsetted */
+		leaving
+			adp $1
+			sti INT64
+			
+
+
+/* Loads and stores */
+
+	pat loi $1==INT8                   /* Load byte indirect */
+		with GPR
+			uses REG
+			gen
+				lbz %a, {GPRINDIRECT, %1, 0}
+			yields %a
+		with SUM_RR
+			uses reusing %1, REG
+			gen
+				lbzx %a, %1.reg1, %1.reg2
+			yields %a
+		with SUM_RC
+			uses REG
+			gen
+				move {IND_RC_B, %1.reg, %1.off}, %a
+			yields %a
+		
+	pat loi loc loc cii $1==INT16 && $2==INT16 && $3==INT32 /* Load half-word indirect and sign extend */
+		with GPR
+			uses REG
+			gen
+				lha %a, {GPRINDIRECT, %1, 0}
+			yields %a
+		with SUM_RR
+			uses reusing %1, REG
+			gen
+				lhax %a, %1.reg1, %1.reg2
+			yields %a
+		with SUM_RC
+			uses REG
+			gen
+				move {IND_RC_H_S, %1.reg, %1.off}, %a
+			yields %a
+		
+	pat loi $1==INT16                  /* Load half-word indirect */
+		with GPR
+			uses REG
+			gen
+				lhz %a, {GPRINDIRECT, %1, 0}
+			yields %a
+		with SUM_RR
+			uses reusing %1, REG
+			gen
+				lhzx %a, %1.reg1, %1.reg2
+			yields %a
+		with SUM_RC
+			uses REG
+			gen
+				move {IND_RC_H, %1.reg, %1.off}, %a
+			yields %a
+		
+	pat loi $1==INT32                  /* Load word indirect */
+		with GPR
+			yields {IND_RC_W, %1, 0}
+		with SUM_RC
+			yields {IND_RC_W, %1.reg, %1.off}
+		with SUM_RR
+			yields {IND_RR_W, %1.reg1, %1.reg2}
+		with LABEL
+			yields {IND_LABEL_W, %1.adr}
+
+	pat loi $1==INT64                  /* Load double-word indirect */
+		with GPR
+			yields {IND_RC_D, %1, 0}
+		with SUM_RC
+			yields {IND_RC_D, %1.reg, %1.off}
+		with SUM_RR
+			yields {IND_RR_D, %1.reg1, %1.reg2}
+		with LABEL
+			yields {IND_LABEL_D, %1.adr}
+
+	pat loi                            /* Load arbitrary size */
+		leaving
+			loc $1
+			los INT32
+					
+	pat los                            /* Load arbitrary size */
+		with GPR3 GPR4 STACK
+			kills ALL
+			gen
+				bl {LABEL, ".los"}
+				
+	pat sti $1==INT8                   /* Store byte indirect */
+		with GPR GPR
+			gen
+				stb %2, {GPRINDIRECT, %1, 0}
+		with SUM_RR GPR
+			gen
+				stbx %2, %1.reg1, %1.reg2
+		with SUM_RC GPR
+			gen
+				move %2, {IND_RC_B, %1.reg, %1.off}
+		with GPR SEX_B
+			gen
+				stb %2.reg, {GPRINDIRECT, %1, 0}
+		with SUM_RR SEX_B
+			gen
+				stbx %2.reg, %1.reg1, %1.reg2
+		with SUM_RC SEX_B
+			gen
+				move %2.reg, {IND_RC_B, %1.reg, %1.off}
+
+	pat sti $1==INT16                  /* Store half-word indirect */
+		with GPR GPR
+			gen
+				sth %2, {GPRINDIRECT, %1, 0}
+		with SUM_RR GPR
+			gen
+				sthx %2, %1.reg1, %1.reg2
+		with SUM_RC GPR
+			gen
+				move %2, {IND_RC_H, %1.reg, %1.off}
+		with GPR SEX_H
+			gen
+				sth %2.reg, {GPRINDIRECT, %1, 0}
+		with SUM_RR SEX_H
+			gen
+				sthx %2.reg, %1.reg1, %1.reg2
+		with SUM_RC SEX_H
+			gen
+				move %2.reg, {IND_RC_H, %1.reg, %1.off}
+
+	pat sti $1==INT32                  /* Store word indirect */
+		with GPR GPR+FS
+			gen
+				move %2, {IND_RC_W, %1, 0}
+		with SUM_RR GPR+FS
+			gen
+				move %2, {IND_RR_W, %1.reg1, %1.reg2}
+		with SUM_RC GPR+FS
+			gen
+				move %2, {IND_RC_W, %1.reg, %1.off}
+		with LABEL GPR+FS
+			gen
+				move %2, {IND_LABEL_W, %1.adr}
+
+	pat sti $1==INT64                  /* Store double-word indirect */
+		with GPR FD
+			gen
+				move %2, {IND_RC_D, %1, 0}
+		with SUM_RR FD
+			gen
+				move %2, {IND_RR_D, %1.reg1, %1.reg2}
+		with SUM_RC FD
+			gen
+				move %2, {IND_RC_D, %1.reg, %1.off}
+		with GPR GPR GPR
+			gen
+				stw %2, {GPRINDIRECT, %1, 0}
+				stw %3, {GPRINDIRECT, %1, 4}
+		with SUM_RC GPR GPR
+			gen
+				move %2, {IND_RC_W, %1.reg, %1.off}
+				move %3, {IND_RC_W, %1.reg, %1.off+4}
+		with LABEL FD
+			gen
+				move %2, {IND_LABEL_D, %1.adr}
+				
+
+	pat sti                            /* Store arbitrary size */
+		leaving
+			loc $1
+			sts INT32
+					
+	pat sts                            /* Load arbitrary size */
+		with GPR3 GPR4 STACK
+			kills ALL
+			gen
+				bl {LABEL, ".sts"}
+				
+
+
+/* Arithmetic wrappers */
+
+	pat ads $1==4                      /* Add var to pointer */
+		leaving adi $1
+	
+	pat sbs $1==4                      /* Subtract var from pointer */
+		leaving sbi $1
+		
+	pat adp                            /* Add constant to pointer */
+		leaving
+			loc $1
+			adi 4
+
+	pat adu                            /* Add unsigned */
+		leaving
+			adi $1
+			
+	pat sbu                            /* Subtract unsigned */
+		leaving
+			sbi $1
+			
+	pat inc                            /* Add 1 */
+		leaving
+			loc 1
+			adi 4
+			
+	pat dec                            /* Subtract 1 */
+		leaving
+			loc 1
+			sbi 4
+	
+	pat loc mlu $2==2                  /* Unsigned multiply by constant */
+		leaving
+			loc $1
+			mli 4
+			
+	pat mlu                            /* Unsigned multiply by var */
+		leaving
+			mli $1
+			
+	pat loc slu                        /* Shift left unsigned by constant amount */
+		leaving
+			loc $1
+			sli $2
+			
+	pat slu                            /* Shift left unsigned by variable amount */
+		leaving
+			sli $1
+
+			
+			
+/* Word arithmetic */
+
+	pat adi $1==4                      /* Add word (second + top) */
+		with REG REG
+			yields {SUM_RR, %1, %2}
+		with CONST REG
+			yields {SUM_RC, %2, %1.val}
+		with REG CONST
+			yields {SUM_RC, %1, %2.val}
+		with CONST SUM_RC
+			yields {SUM_RC, %2.reg, %2.off+%1.val}
+		with CONST LABEL
+			yields {LABEL, %2.adr+%1.val}
+			
+	pat sbi $1==4                      /* Subtract word (second - top) */
+		with REG REG
+			uses reusing %2, REG
+			gen
+				subf %a, %1, %2
+			yields %a
+		with CONST REG
+			yields {SUM_RC, %2, 0-%1.val}
+		with CONST SUM_RC
+			yields {SUM_RC, %2.reg, %2.off-%1.val}
+		with CONST LABEL
+			yields {LABEL, %2.adr+(0-%1.val)}
+				
+	pat ngi $1==4                      /* Negate word */
+		with REG
+			uses reusing %1, REG
+			gen
+				neg %a, %1
+			yields %a
+		
+	pat mli $1==4                      /* Multiply word (second * top) */
+		with REG REG
+			uses reusing %2, REG
+			gen
+				mullw %a, %2, %1
+			yields %a
+		
+	pat dvi $1==4                      /* Divide word (second / top) */
+		with REG REG
+			uses reusing %2, REG
+			gen
+				divw %a, %2, %1
+			yields %a
+					
+	pat dvu $1==4                      /* Divide unsigned word (second / top) */
+		with REG REG
+			uses reusing %2, REG
+			gen
+				divwu %a, %2, %1
+			yields %a
+
+	pat rmi $1==4                      /* Remainder word (second % top) */
+		with REG REG
+			uses REG
+			gen
+				divw %a, %2, %1
+				mullw %a, %a, %1
+				subf %a, %a, %2
+			yields %a
+								
+	pat rmu $1==4                      /* Remainder unsigned word (second % top) */
+		with REG REG
+			uses REG
+			gen
+				divwu %a, %2, %1
+				mullw %a, %a, %1
+				subf %a, %a, %2
+			yields %a
+
+	pat and $1==4                      /* AND word */
+		with GPR NOT_R
+			uses reusing %1, REG
+			gen
+				andc %a, %1, %2.reg
+			yields %a
+		with NOT_R GPR
+			uses reusing %1, REG
+			gen
+				andc %a, %2, %1.reg
+			yields %a
+		with GPR GPR
+			yields {AND_RR, %1, %2}
+		with GPR CONST
+			yields {AND_RC, %1, %2.val}
+		with CONST GPR
+			yields {AND_RC, %2, %1.val}
+		
+	pat and !defined($1)               /* AND set */
+		with STACK
+			gen
+				bl {LABEL, ".and"}
+				
+	pat ior $1==4                      /* OR word */
+		with GPR NOT_R
+			uses reusing %1, REG
+			gen
+				orc %a, %1, %2.reg
+			yields %a
+		with NOT_R GPR
+			uses reusing %2, REG
+			gen
+				orc %a, %2, %1.reg
+			yields %a
+		with GPR GPR
+			yields {OR_RR, %1, %2}
+		with GPR CONST
+			yields {OR_RC, %1, %2.val}
+		with CONST GPR
+			yields {OR_RC, %2, %1.val}
+		
+	pat ior !defined($1)               /* OR set */
+		with STACK
+			gen
+				bl {LABEL, ".ior"}
+				
+	pat xor $1==4                      /* XOR word */
+		with GPR GPR
+			yields {XOR_RR, %1, %2}
+		with GPR CONST
+			yields {XOR_RC, %1, %2.val}
+		with CONST GPR
+			yields {XOR_RC, %2, %1.val}
+	
+	pat xor !defined($1)               /* XOR set */
+		with STACK
+			gen
+				bl {LABEL, ".xor"}
+				
+	pat com $1==INT32                  /* NOT word */
+		with AND_RR
+			uses REG
+			gen
+				nand %a, %1.reg1, %1.reg2
+			yields %a
+		with OR_RR
+			uses REG
+			gen
+				nor %a, %1.reg1, %1.reg2
+			yields %a
+		with XOR_RR
+			uses REG
+			gen
+				eqv %a, %1.reg1, %1.reg2
+			yields %a
+		with GPR
+			yields {NOT_R, %1}
+				
+	pat com !defined($1)               /* NOT set */
+		with STACK
+			gen
+				bl {LABEL, ".com"}
+				
+	pat sli $1==4                      /* Shift left (second << top) */
+		with CONST GPR
+			uses reusing %2, REG
+			gen
+				rlwinm %a, %2, {CONST, (%1.val & 0x1F)}, {CONST, 0}, {CONST, 31-(%1.val & 0x1F)}
+			yields %a
+		with GPR GPR
+			uses reusing %2, REG
+			gen
+				slw %a, %2, %1
+			yields %a
+			
+	pat sri $1==4                      /* Shift right signed (second >> top) */
+		with CONST GPR
+			uses reusing %2, REG
+			gen
+				srawi %a, %2, {CONST, %1.val & 0x1F}
+			yields %a
+		with GPR GPR
+			uses reusing %2, REG
+			gen
+				sraw %a, %2, %1
+			yields %a
+
+	pat sru $1==4                      /* Shift right unsigned (second >> top) */
+		with CONST GPR
+			uses reusing %2, REG
+			gen
+				rlwinm %a, %2, {CONST, 32-(%1.val & 0x1F)}, {CONST, (%1.val & 0x1F)}, {CONST, 31}
+			yields %a
+		with GPR GPR
+			uses reusing %2, REG
+			gen
+				srw %a, %2, %1
+			yields %a
+			
+
+
+/* Arrays */
+
+	pat aar $1==INT32                  /* Index array */
+		with GPR3 GPR4 GPR5
+			gen
+				bl {LABEL, ".aar4"}
+			yields R3
+			
+	pat lae lar $2==INT32 && nicesize(rom($1, 3)) /* Load array */
+		leaving
+			lae $1
+			aar INT32
+			loi rom($1, 3)
+			
+	pat lar $1==INT32                  /* Load array */
+		with GPR3 GPR4 GPR5 STACK
+			kills ALL
+			gen
+				bl {LABEL, ".lar4"}
+			
+	pat lae sar $2==INT32 && nicesize(rom($1, 3)) /* Store array */
+		leaving
+			lae $1
+			aar INT32
+			sti rom($1, 3)
+
+	pat sar $1==INT32                  /* Store array */
+		with GPR3 GPR4 GPR5 STACK
+			kills ALL
+			gen
+				bl {LABEL, ".sar4"}
+			
+
+
+			
+/* Sets */
+
+	pat set defined($1)                /* Create word with set bit */
+		leaving
+			loc 1
+			exg INT32
+			sli INT32
+			
+	pat set !defined($1)               /* Create structure with set bit (variable) */
+		with GPR3 GPR4 STACK
+			gen
+				bl {LABEL, ".set"}
+			
+	pat inn defined($1)                /* Test for set bit */
+		leaving
+			set INT32
+			and INT32
+			
+	pat inn !defined($1)               /* Test for set bit (variable) */
+		with GPR3 STACK
+			gen
+				bl {LABEL, ".inn"}
+			
+			
+			
+/* Boolean resolutions */
+
+	pat teq                            /* top = (top == 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".teq_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+				
+	pat tne                            /* top = (top != 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".tne_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+				
+	pat tlt                            /* top = (top < 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".tlt_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+				
+	pat tle                            /* top = (top <= 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".tle_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+				
+	pat tgt                            /* top = (top > 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".tgt_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+
+	pat tge                            /* top = (top >= 0) */
+		with TRISTATE_ALL + GPR
+			uses reusing %1, REG
+			gen
+				move %1, C0
+				move C0, SCRATCH
+				move {LABEL, ".tge_table"}, %a
+				lwzx %a, %a, SCRATCH
+			yields %a
+				
+
+
+
+/* Simple branches */
+
+	pat zeq                            /* Branch if signed top == 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFTRUE, EQ, {LABEL, $1}
+
+	pat beq
+		leaving
+			cmi INT32
+			zeq $1
+			
+	pat zne                            /* Branch if signed top != 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFFALSE, EQ, {LABEL, $1}
+
+	pat bne
+		leaving
+			cmi INT32
+			zne $1
+			
+	pat zgt                            /* Branch if signed top > 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFTRUE, GT, {LABEL, $1}
+
+	pat bgt
+		leaving
+			cmi INT32
+			zgt $1
+			
+	pat zge                            /* Branch if signed top >= 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFFALSE, LT, {LABEL, $1}
+
+	pat bge
+		leaving
+			cmi INT32
+			zge $1
+			
+	pat zlt                            /* Branch if signed top < 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFTRUE, LT, {LABEL, $1}
+
+	pat blt
+		leaving
+			cmi INT32
+			zlt $1
+			
+	pat zle                            /* Branch if signed top >= 0 */
+		with TRISTATE_ALL+GPR STACK
+			gen
+				move %1, C0
+				bc IFFALSE, GT, {LABEL, $1}
+
+	pat ble
+		leaving
+			cmi INT32
+			zle $1
+			
+
+/* Compare and jump */
+
+	pat cmi                            /* Signed tristate compare */
+		with CONST GPR
+			yields {TRISTATE_RC_S, %2, %1.val}
+		with GPR GPR
+			yields {TRISTATE_RR_S, %2, %1}
+			
+	pat cmu                            /* Unsigned tristate compare */
+		with CONST GPR
+			yields {TRISTATE_RC_U, %2, %1.val}
+		with GPR GPR
+			yields {TRISTATE_RR_U, %2, %1}
+						
+	pat cmp                            /* Compare pointers */
+		leaving
+			cmu INT32
+			
+	pat cms $1==INT32                  /* Compare blocks (word sized) */
+		leaving
+			cmi INT32
+			
+			
+			
+
+/* Other branching and labelling */
+
+	pat lab topeltsize($1)==4 && !fallthrough($1)
+		gen
+			labeldef $1
+			yields R3
+			
+	pat lab topeltsize($1)==4 && fallthrough($1)
+		with GPR3
+		gen
+			labeldef $1
+		yields %1
+			
+	pat lab topeltsize($1)!=4
+		with STACK
+		kills ALL
+		gen
+			labeldef $1
+			
+	pat bra topeltsize($1)==4          /* Unconditional jump with TOS GPRister */
+		with GPR3 STACK
+		gen
+			b {LABEL, $1}
+			
+	pat bra topeltsize($1)!=4          /* Unconditional jump without TOS GPRister */
+		with STACK
+		gen
+			b {LABEL, $1}
+			
+				
+						
+/* Miscellaneous */
+
+	pat cal                            /* Call procedure */
+		with STACK
+			kills ALL
+			gen
+				bl {LABEL, $1}
+
+	pat cai                            /* Call procedure indirect */
+		with GPR STACK
+			kills ALL
+			gen
+				mtspr CTR, %1
+				bcctrl ALWAYS, {CONST, 0}, {CONST, 0}
+				
+	pat lfr $1==INT32                  /* Load function result, word */
+		yields R3
+		
+	pat lfr $1==INT64                  /* Load function result, double-word */
+		yields R4 R3
+		
+	pat ret $1==0                      /* Return from procedure */
+		gen
+			return
+			b {LABEL, ".ret"}
+			
+	pat ret $1==INT32                  /* Return from procedure, word */
+		with GPR3
+		gen
+			return
+			b {LABEL, ".ret"}
+
+	pat ret $1==INT64                  /* Return from procedure, double-word */
+		with GPR3 GPR4
+		gen
+			return
+			b {LABEL, ".ret"}
+
+	pat blm                            /* Block move constant length */
+		with GPR GPR STACK
+			uses REG
+			gen
+				move {CONST, $1}, %a
+				stwu %a, {GPRINDIRECT, SP, 0-4}
+				stwu %2, {GPRINDIRECT, SP, 0-4}
+				stwu %1, {GPRINDIRECT, SP, 0-4}
+				bl {LABEL, "_memmove"}
+				addi SP, SP, {CONST, 12}
+				
+	pat bls                            /* Block move variable length */
+		with GPR GPR GPR STACK
+			gen
+				stwu %1, {GPRINDIRECT, SP, 0-4}
+				stwu %3, {GPRINDIRECT, SP, 0-4}
+				stwu %2, {GPRINDIRECT, SP, 0-4}
+				bl {LABEL, "_memmove"}
+				addi SP, SP, {CONST, 12}
+				
+	pat csa                            /* Array-lookup switch */
+		with GPR3 GPR4 STACK
+			gen
+				b {LABEL, ".csa"}
+				
+	pat csb                            /* Table-lookup switch */
+		with GPR3 GPR4 STACK
+			gen
+				b {LABEL, ".csb"}
+
+				
+
+/* EM specials */
+
+	pat fil                            /* Set current filename */
+		leaving
+			lae $1
+			ste ".filename"
+			
+	pat lin                            /* Set current line number */
+		leaving
+			loc $1
+			ste ".linenumber"
+
+	pat lni                            /* Increment line number */
+		leaving
+			ine ".linenumber"			
+			
+	pat lim                            /* Load EM trap ignore mask */
+		leaving
+			lde ".ignmask"
+			
+	pat sim                            /* Store EM trap ignore mask */
+		leaving
+			ste ".ignmask"
+			
+	pat trp                            /* Raise EM trap */
+		with GPR3
+			gen
+				bl {LABEL, ".trap"}
+				
+	pat sig                            /* Set trap handler */
+		leaving
+			ste ".trppc"
+			
+	pat rtt                            /* Return from trap */
+		leaving
+			ret 0
+			
+	pat lxl $1==0                      /* Load FP */
+		leaving
+			lor 0
+		
+	pat lxl $1==1                      /* Load caller's FP */
+		leaving
+			lxl 0
+			dch
+			
+	pat dch                            /* FP -> caller FP */
+		with GPR
+			uses reusing %1, REG
+			gen
+				lwz %a, {GPRINDIRECT, %1, FP_OFFSET}
+			yields %a
+
+	pat lpb                            /* Convert FP to argument address */
+		leaving
+			adp EM_BSIZE
+			
+	pat lxa                            /* Load caller's SP */
+		leaving
+			lxl $1
+			lpb
+			
+	pat gto                            /* longjmp */
+		uses REG
+		gen
+			move {LABEL, $1}, %a
+			move {IND_RC_W, %a, 8}, FP
+			move {IND_RC_W, %a, 4}, SP
+			move {IND_RC_W, %a, 0}, %a
+			mtspr CTR, %a
+			bcctr ALWAYS, {CONST, 0}, {CONST, 0}
+				
+#if 0
+			
+	pat gto                            /* longjmp */
+		with STACK
+			gen
+				ld {LABEL, $1+2}
+				wspec {CONST, 1}
+				ld {LABEL, $1+4}
+				wspec {CONST, 0}
+				ld {LABEL, $1+0}
+				wspec {CONST, 2}
+			
+	pat str $1==1                      /* Store special GPRister */
+		with GPR0
+			gen
+				wspec {CONST, $1}
+				
+#endif
+
+	pat lor $1==0                      /* Load FP */
+		uses REG
+		gen
+			move FP, %a
+		yields %a
+		
+	pat lor $1==1                      /* Load SP */
+		uses REG
+		gen
+			move SP, %a
+		yields %a
+		
+	pat lor $1==2                      /* Load HP */
+		leaving
+			loe ".reghp"
+			
+	pat str $1==0                      /* Store FP */
+		with GPR
+			gen
+				move %1, FP
+				
+	pat str $1==1                      /* Store SP */
+		with GPR
+			gen
+				move %1, SP
+			
+	pat str $1==2                      /* Store HP */
+		leaving
+			ste ".reghp"
+				
+	pat ass                            /* Adjust stack by variable amount */
+		with CONST
+			gen
+				move {SUM_RC, SP, %1.val}, {GPRE, SP}
+		with GPR
+			gen
+				move {SUM_RR, SP, %1}, {GPRE, SP}
+				
+	pat asp                            /* Adjust stack by constant amount */
+		leaving
+			loc $1
+			ass
+			
+			
+			
+/* Floating point support */
+
+	/* All very cheap and nasty --- this needs to be properly integrated into
+	 * the code generator. ncg doesn't like having separate FPU registers. */
+	 
+	/* Single-precision */
+	
+	pat zrf $1==INT32                  /* Push zero */
+		leaving
+			loe ".fs_00000000"
+		
+	pat adf $1==INT32                  /* Add single */
+		with FS FS
+			uses reusing %1, FREG
+			gen
+				fadds {FS, %a}, %2, %1
+			yields {FS, %a}
+				
+	pat sbf $1==INT32                  /* Subtract single */
+		with FS FS
+			uses reusing %1, FREG
+			gen
+				fsubs {FS, %a}, %2, %1
+			yields {FS, %a}
+				
+	pat mlf $1==INT32                  /* Multiply single */
+		with FS FS
+			uses reusing %1, FREG
+			gen
+				fmuls {FS, %a}, %2, %1
+			yields {FS, %a}
+
+	pat dvf $1==INT32                  /* Divide single */
+		with FS FS
+			uses reusing %1, FREG
+			gen
+				fdivs {FS, %a}, %2, %1
+			yields {FS, %a}
+
+	pat ngf $1==INT32                  /* Negate single */
+		with FS
+			uses reusing %1, FREG
+			gen
+				fneg {FS, %a}, %1
+			yields {FS, %a}
+
+	pat cmf $1==INT32                  /* Compare single */
+		with FS FS
+			yields {TRISTATE_FF, %2.reg, %1.reg}
+			
+	pat loc loc cff $1==INT32 && $2==INT64 /* Convert single to double */
+		with FS
+			yields {FD, %1.reg}
+					
+	pat loc loc cfu $1==INT32 && $2==INT32 /* Convert single to unsigned int */
+		with STACK
+			gen
+				bl {LABEL, ".cfu4"}
+				
+	pat loc loc cfi $1==INT32 && $2==INT32 /* Convert single to signed int */
+		with STACK
+			gen
+				bl {LABEL, ".cfi4"}
+				
+	pat loc loc cif $1==INT32 && $2==INT32 /* Convert integer to single */
+		with STACK
+			gen
+				bl {LABEL, ".cif4"}
+				
+	pat loc loc cuf $1==INT32 && $2==INT32 /* Convert unsigned int to single */
+		with STACK
+			gen
+				bl {LABEL, ".cuf4"}
+				
+	pat fef $1==INT32                  /* Split single */
+		with STACK
+			gen
+				bl {LABEL, ".fef4"}
+				
+	/* Double-precision */
+	
+	pat zrf $1==INT64                  /* Push zero */
+		leaving
+			lde ".fd_00000000"
+		
+	pat adf $1==INT64                  /* Add double */
+		with FD FD
+			uses FREG
+			gen
+				fadd {FD, %a}, %2, %1
+			yields {FD, %a}
+				
+	pat sbf $1==INT64                  /* Subtract double */
+		with FD FD
+			uses FREG
+			gen
+				fsub {FD, %a}, %2, %1
+			yields {FD, %a}
+				
+	pat mlf $1==INT64                  /* Multiply double */
+		with FD FD
+			uses reusing %1, FREG
+			gen
+				fmul {FD, %a}, %2, %1
+			yields {FD, %a}
+
+	pat dvf $1==INT64                  /* Divide double */
+		with FD FD
+			uses reusing %1, FREG
+			gen
+				fdiv {FD, %a}, %2, %1
+			yields {FD, %a}
+
+	pat ngf $1==INT64                  /* Negate double */
+		with FD
+			uses reusing %1, FREG
+			gen
+				fneg {FD, %a}, %1
+			yields {FD, %a}
+
+	pat cmf $1==INT64                  /* Compare double */
+		with FD FD
+			yields {TRISTATE_FF, %2.reg, %1.reg}
+				
+	pat loc loc cff $1==INT64 && $2==INT32 /* Convert double to single */
+		with FD
+			uses reusing %1, FREG
+			gen
+				frsp {FS, %a}, %1
+			yields {FS, %a}
+					
+	pat loc loc cfu $1==INT64 && $2==INT32 /* Convert double to unsigned int */
+		with STACK
+			gen
+				bl {LABEL, ".cfu8"}
+				
+	pat loc loc cfi $1==INT64 && $2==INT32 /* Convert double to signed int */
+		with STACK
+			gen
+				bl {LABEL, ".cfi8"}
+				
+	pat loc loc cif $1==INT32 && $2==INT64 /* Convert integer to double */
+		with STACK
+			kills ALL
+			gen
+				bl {LABEL, ".cif8"}
+		
+	pat loc loc cuf $1==INT32 && $2==INT64 /* Convert unsigned int to double */
+		with STACK
+			gen
+				bl {LABEL, ".cuf8"}
+				
+	pat fef $1==INT64                  /* Split double */
+		with FD
+			gen
+				addi SP, SP, {CONST, 0-8}
+				stfd %1, {GPRINDIRECT, SP, 0}
+				stwu SP, {GPRINDIRECT, SP, 0-4}
+				bl {LABEL, "___fef8"}
+				stw R3, {GPRINDIRECT, SP, 0}
+				
+	pat fif $1==INT64                  /* Multiply and split double (?) */
+		with STACK
+			gen
+				bl {LABEL, ".fif8"}
+				
+		

+ 23 - 0
mach/powerpc/pmfile

@@ -0,0 +1,23 @@
+-- $Source$
+-- $State$
+
+local d = ROOTDIR.."mach/powerpc/"
+
+include (d.."libem/pmfile")
+include (d.."libend/pmfile")
+
+mach_powerpc = group {
+	ARCH = "powerpc",
+	
+	proto_as,
+	proto_ncg { ARCHDIR = "powerpc" },
+	proto_top,
+--	ego_descr,
+}
+
+support_powerpc = group {
+	OPTIMISATION = "-O",
+
+	libem_powerpc,
+	libend_powerpc,
+}

+ 1 - 0
mach/powerpc/top/.distr

@@ -0,0 +1 @@
+table

+ 20 - 0
mach/powerpc/top/table

@@ -0,0 +1,20 @@
+
+/* 68020 desciptor table for ACK target optimizer */
+
+MAXOP 3;
+
+%%;
+
+P, Q, R             { TRUE };
+X, Y, Z             { TRUE };
+
+%%;
+
+/* Whitespace is significant here! */
+
+addi  X, X, 0                -> ;
+addis X, X, 0                -> ;
+
+or X, Y, Z : or. X, X, X     -> or. X, Y, Z ;
+
+%%;