Skeleton of VideoCore IV support for the Raspberry Pi.
authorDavid Given <dg@cowlark.com>
Thu, 16 May 2013 23:03:38 +0000 (00:03 +0100)
committerDavid Given <dg@cowlark.com>
Thu, 16 May 2013 23:03:38 +0000 (00:03 +0100)
--HG--
branch : dtrg-videocore
rename : mach/powerpc/as/.distr => mach/vc4/as/.distr
rename : mach/powerpc/as/mach0.c => mach/vc4/as/mach0.c
rename : mach/powerpc/as/mach1.c => mach/vc4/as/mach1.c
rename : mach/powerpc/as/mach2.c => mach/vc4/as/mach2.c
rename : mach/powerpc/as/mach3.c => mach/vc4/as/mach3.c
rename : mach/powerpc/as/mach4.c => mach/vc4/as/mach4.c
rename : mach/powerpc/as/mach5.c => mach/vc4/as/mach5.c
rename : mach/i86/build.mk => mach/vc4/build.mk
rename : mach/powerpc/libem/powerpc.h => mach/vc4/libem/videocore.h
rename : mach/i86/libend/.distr => mach/vc4/libend/.distr
rename : mach/i86/libend/edata.s => mach/vc4/libend/edata.s
rename : mach/i86/libend/em_end.s => mach/vc4/libend/em_end.s
rename : mach/i86/libend/end.s => mach/vc4/libend/end.s
rename : mach/i86/libend/etext.s => mach/vc4/libend/etext.s
rename : mach/powerpc/ncg/.distr => mach/vc4/ncg/.distr
rename : mach/powerpc/ncg/mach.c => mach/vc4/ncg/mach.c
rename : mach/powerpc/ncg/mach.h => mach/vc4/ncg/mach.h
rename : mach/powerpc/ncg/table => mach/vc4/ncg/table
rename : plat/pc86/descr => plat/rpi/descr

42 files changed:
mach/vc4/as/.distr [new file with mode: 0644]
mach/vc4/as/binary.h [new file with mode: 0644]
mach/vc4/as/mach0.c [new file with mode: 0644]
mach/vc4/as/mach1.c [new file with mode: 0644]
mach/vc4/as/mach2.c [new file with mode: 0644]
mach/vc4/as/mach3.c [new file with mode: 0644]
mach/vc4/as/mach4.c [new file with mode: 0644]
mach/vc4/as/mach5.c [new file with mode: 0644]
mach/vc4/build.mk [new file with mode: 0644]
mach/vc4/libem/dummy.s [new file with mode: 0644]
mach/vc4/libem/videocore.h [new file with mode: 0644]
mach/vc4/libend/.distr [new file with mode: 0644]
mach/vc4/libend/edata.s [new file with mode: 0644]
mach/vc4/libend/em_end.s [new file with mode: 0644]
mach/vc4/libend/end.s [new file with mode: 0644]
mach/vc4/libend/etext.s [new file with mode: 0644]
mach/vc4/ncg/.distr [new file with mode: 0644]
mach/vc4/ncg/mach.c [new file with mode: 0644]
mach/vc4/ncg/mach.h [new file with mode: 0644]
mach/vc4/ncg/table [new file with mode: 0644]
mach/vc4/test/opcodes.s [new file with mode: 0644]
plat/rpi/build.mk [new file with mode: 0644]
plat/rpi/descr [new file with mode: 0644]
plat/rpi/include/ack/config.h [new file with mode: 0644]
plat/rpi/include/unistd.h [new file with mode: 0644]
plat/rpi/libsys/_hol0.s [new file with mode: 0644]
plat/rpi/libsys/_sys_rawread.s [new file with mode: 0644]
plat/rpi/libsys/_sys_rawwrite.s [new file with mode: 0644]
plat/rpi/libsys/brk.c [new file with mode: 0644]
plat/rpi/libsys/close.c [new file with mode: 0644]
plat/rpi/libsys/creat.c [new file with mode: 0644]
plat/rpi/libsys/errno.s [new file with mode: 0644]
plat/rpi/libsys/getpid.c [new file with mode: 0644]
plat/rpi/libsys/isatty.c [new file with mode: 0644]
plat/rpi/libsys/kill.c [new file with mode: 0644]
plat/rpi/libsys/libsys.h [new file with mode: 0644]
plat/rpi/libsys/lseek.c [new file with mode: 0644]
plat/rpi/libsys/open.c [new file with mode: 0644]
plat/rpi/libsys/read.c [new file with mode: 0644]
plat/rpi/libsys/signal.c [new file with mode: 0644]
plat/rpi/libsys/time.c [new file with mode: 0644]
plat/rpi/libsys/write.c [new file with mode: 0644]

diff --git a/mach/vc4/as/.distr b/mach/vc4/as/.distr
new file mode 100644 (file)
index 0000000..8ebe379
--- /dev/null
@@ -0,0 +1,6 @@
+mach0.c
+mach1.c
+mach2.c
+mach3.c
+mach4.c
+mach5.c
diff --git a/mach/vc4/as/binary.h b/mach/vc4/as/binary.h
new file mode 100644 (file)
index 0000000..c00e735
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#ifndef BINARY_H
+#define BINARY_H
+
+/* This grotesque nonsense allows us to use binary constants from C. */
+
+#define HEX__(n) 0x##n##LU
+#define B8__(x) \
+       ((x&0x0000000FLU)?1:0) \
+       +((x&0x000000F0LU)?2:0) \
+       +((x&0x00000F00LU)?4:0) \
+       +((x&0x0000F000LU)?8:0) \
+       +((x&0x000F0000LU)?16:0) \
+       +((x&0x00F00000LU)?32:0) \
+       +((x&0x0F000000LU)?64:0) \
+       +((x&0xF0000000LU)?128:0)
+
+#define B8(d) \
+       ((unsigned char)B8__(HEX__(d)))
+#define B16(dmsb,dlsb) \
+       (((unsigned short)B8(dmsb)<<8) + B8(dlsb))
+#define B32(dmsb,db2,db3,dlsb) \
+         (((unsigned long)B8(dmsb)<<24) \
+       + ((unsigned long)B8(db2)<<16) \
+       + ((unsigned long)B8(db3)<<8) \
+       + B8(dlsb))
+
+#endif
diff --git a/mach/vc4/as/mach0.c b/mach/vc4/as/mach0.c
new file mode 100644 (file)
index 0000000..b6294ec
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#define        THREE_PASS          /* branch and offset optimization */
+#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)
diff --git a/mach/vc4/as/mach1.c b/mach/vc4/as/mach1.c
new file mode 100644 (file)
index 0000000..96a8a07
--- /dev/null
@@ -0,0 +1,6 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
diff --git a/mach/vc4/as/mach2.c b/mach/vc4/as/mach2.c
new file mode 100644 (file)
index 0000000..c69007d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+%token <y_word> GPR
+
+%token <y_word> OP
+%token <y_word> OP_ONEREG
+%token <y_word> OP_ONELREG
+%token <y_word> OP_ALU
+%token <y_word> OP_MEM
+%token <y_word> OP_BREG
+%token <y_word> OP_STACK
+
+/* 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 */
diff --git a/mach/vc4/as/mach3.c b/mach/vc4/as/mach3.c
new file mode 100644 (file)
index 0000000..b36652d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include "binary.h"
+
+/* Integer registers */
+
+0,     GPR,        0,          "r0",
+0,     GPR,        1,          "r1",
+0,     GPR,        2,          "r2",
+0,     GPR,        3,          "r3",
+0,     GPR,        4,          "r4",
+0,     GPR,        5,          "r5",
+
+0,     GPR,        6,          "r6",
+0,     GPR,        6,          "fp",
+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,        25,         "sp",
+0,     GPR,        26,         "r26",
+0,     GPR,        26,         "lr",
+0,     GPR,        27,         "r27",
+0,     GPR,        28,         "r28",
+0,     GPR,        29,         "r29",
+0,     GPR,        30,         "r30",
+0,     GPR,        30,         "sr",
+0,     GPR,        31,         "r31",
+0,     GPR,        31,         "pc",
+
+/* Special instructions */
+
+0,     OP,                    B16(00000000,00000001),                  "nop",
+0,     OP,                    B16(00000000,00001010),                  "rti",
+
+0,     OP_ONEREG,             B16(00000000,01000000),                  "b",
+0,     OP_ONEREG,             B16(00000000,01100000),                  "bl",
+0,     OP_ONELREG,            B16(00000000,10000000),                  "tbb",
+0,     OP_ONELREG,            B16(00000000,10100000),                  "tbs",
+
+0,     OP_ALU,                B8(00000000),                            "mov",
+0,     OP_ALU,                B8(00000001),                            "cmn",
+0,     OP_ALU,                B8(00000010),                            "add",
+0,     OP_ALU,                B8(00000011),                            "bic",
+0,     OP_ALU,                B8(00000100),                            "mul",
+0,     OP_ALU,                B8(00000101),                            "eor",
+0,     OP_ALU,                B8(00000110),                            "sub",
+0,     OP_ALU,                B8(00000111),                            "and",
+0,     OP_ALU,                B8(00001000),                            "mvn",
+0,     OP_ALU,                B8(00001001),                            "ror",
+0,     OP_ALU,                B8(00001010),                            "cmp",
+0,     OP_ALU,                B8(00001011),                            "rsb",
+0,     OP_ALU,                B8(00001100),                            "btst",
+0,     OP_ALU,                B8(00001101),                            "or",
+0,     OP_ALU,                B8(00001110),                            "extu",
+0,     OP_ALU,                B8(00001111),                            "max",
+0,     OP_ALU,                B8(00010000),                            "bset",
+0,     OP_ALU,                B8(00010001),                            "min",
+0,     OP_ALU,                B8(00010010),                            "bclr",
+0,     OP_ALU,                B8(00010011),                            "adds2",
+0,     OP_ALU,                B8(00010100),                            "bchg",
+0,     OP_ALU,                B8(00010101),                            "adds4",
+0,     OP_ALU,                B8(00010110),                            "adds8",
+0,     OP_ALU,                B8(00010111),                            "adds16",
+0,     OP_ALU,                B8(00011000),                            "exts",
+0,     OP_ALU,                B8(00011001),                            "neg",
+0,     OP_ALU,                B8(00011010),                            "lsr",
+0,     OP_ALU,                B8(00011011),                            "clz",
+0,     OP_ALU,                B8(00011100),                            "lsl",
+0,     OP_ALU,                B8(00011101),                            "brev",
+0,     OP_ALU,                B8(00011110),                            "asr",
+0,     OP_ALU,                B8(00011111),                            "abs",
+
+
diff --git a/mach/vc4/as/mach4.c b/mach/vc4/as/mach4.c
new file mode 100644 (file)
index 0000000..d1320da
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include "binary.h"
+
+operation
+       : OP                                              { emit2($1); }
+
+       | OP_ONEREG GPR
+       {
+               emit2($1 | ($2<<0));
+       }
+
+       | OP_ONELREG GPR
+       {
+               if ($2 >= 0x10)
+                       serror("cannot use r16+ here");
+               emit2($1 | ($2<<0));
+       }
+
+       | OP_ALU GPR ',' GPR
+       {
+               emit2(B16(01000000, 00000000) | ($1<<8) | ($2<<0) | ($4<<4));
+       }
+
+       | OP_ALU GPR ',' '#' u5
+       {
+               if ($1 >= 0x10)
+                       serror("cannot use this ALU operation in 2op form");
+               emit2(B16(01100000, 00000000) | ($1<<9) | ($2<<0) | ($5<<4));
+       }
+       ;
+
+e16
+       : 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;
+       }
+       ;
+
diff --git a/mach/vc4/as/mach5.c b/mach/vc4/as/mach5.c
new file mode 100644 (file)
index 0000000..668f4b7
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * VideoCore IV assembler for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
diff --git a/mach/vc4/build.mk b/mach/vc4/build.mk
new file mode 100644 (file)
index 0000000..06ea3ed
--- /dev/null
@@ -0,0 +1,10 @@
+arch-libem-vc4 := \
+       dummy.s
+
+arch-libend-vc4 = \
+       edata.s \
+       em_end.s \
+       end.s \
+       etext.s
+
+
diff --git a/mach/vc4/libem/dummy.s b/mach/vc4/libem/dummy.s
new file mode 100644 (file)
index 0000000..4edaa03
--- /dev/null
@@ -0,0 +1,9 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include "videocore.h"
diff --git a/mach/vc4/libem/videocore.h b/mach/vc4/libem/videocore.h
new file mode 100644 (file)
index 0000000..3e27a7e
--- /dev/null
@@ -0,0 +1,15 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
diff --git a/mach/vc4/libend/.distr b/mach/vc4/libend/.distr
new file mode 100644 (file)
index 0000000..afa027b
--- /dev/null
@@ -0,0 +1,4 @@
+edata.s
+em_end.s
+end.s
+etext.s
diff --git a/mach/vc4/libend/edata.s b/mach/vc4/libend/edata.s
new file mode 100644 (file)
index 0000000..e706877
--- /dev/null
@@ -0,0 +1,15 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define        _edata
+.sect .data
+_edata:
diff --git a/mach/vc4/libend/em_end.s b/mach/vc4/libend/em_end.s
new file mode 100644 (file)
index 0000000..bae5aaa
--- /dev/null
@@ -0,0 +1,24 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+.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
+endtext:
+       .sect .rom
+endrom:
+       .sect .data
+enddata:
+       .sect .end
+__end:
+endbss:
diff --git a/mach/vc4/libend/end.s b/mach/vc4/libend/end.s
new file mode 100644 (file)
index 0000000..5ce2882
--- /dev/null
@@ -0,0 +1,15 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define        _end
+.sect .end ! only for declaration of _end, __end and endbss.
+_end:
diff --git a/mach/vc4/libend/etext.s b/mach/vc4/libend/etext.s
new file mode 100644 (file)
index 0000000..973ab18
--- /dev/null
@@ -0,0 +1,15 @@
+#
+/*
+ * VideoCore IV support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.define        _etext
+.sect .text
+_etext:
diff --git a/mach/vc4/ncg/.distr b/mach/vc4/ncg/.distr
new file mode 100644 (file)
index 0000000..ccdf9bf
--- /dev/null
@@ -0,0 +1,3 @@
+mach.c
+mach.h
+table
diff --git a/mach/vc4/ncg/mach.c b/mach/vc4/ncg/mach.c
new file mode 100644 (file)
index 0000000..f57a2a0
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * VideoCore IV code generator for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#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
diff --git a/mach/vc4/ncg/mach.h b/mach/vc4/ncg/mach.h
new file mode 100644 (file)
index 0000000..89d2b8a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * VideoCore IV code generator for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#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
diff --git a/mach/vc4/ncg/table b/mach/vc4/ncg/table
new file mode 100644 (file)
index 0000000..f08ec35
--- /dev/null
@@ -0,0 +1,1999 @@
+/*
+ * VideoCore IV code generator for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+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
+                       
diff --git a/mach/vc4/test/opcodes.s b/mach/vc4/test/opcodes.s
new file mode 100644 (file)
index 0000000..894a754
--- /dev/null
@@ -0,0 +1,77 @@
+#
+/*
+ * VideoCore IV assembler test file
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+.sect .text
+
+main:
+       nop
+       rti
+
+       b r0
+       b r31
+       bl r0
+       bl r31
+       tbb r0
+       tbb r15
+       tbs r0
+       tbs r15
+
+       mov r0, r1
+    cmn r0, r1
+    add r0, r1
+       bic r0, r1
+       mul r0, r1
+       eor r0, r1
+       sub r0, r1
+       and r0, r1
+       mvn r0, r1
+       ror r0, r1
+       cmp r0, r1
+       rsb r0, r1
+       btst r0, r1
+       or r0, r1
+       extu r0, r1
+       max r0, r1
+       bset r0, r1
+       min r0, r1
+       bclr r0, r1
+       adds2 r0, r1
+       bchg r0, r1
+       adds4 r0, r1
+       adds8 r0, r1
+       adds16 r0, r1
+       exts r0, r1
+       neg r0, r1
+       lsr r0, r1
+       clz r0, r1
+       lsl r0, r1
+       brev r0, r1
+       asr r0, r1
+       abs r0, r1
+
+       mov r0, #31
+    cmn r0, #31
+    add r0, #31
+       bic r0, #31
+       mul r0, #31
+       eor r0, #31
+       sub r0, #31
+       and r0, #31
+       mvn r0, #31
+       ror r0, #31
+       cmp r0, #31
+       rsb r0, #31
+       btst r0, #31
+       or r0, #31
+       extu r0, #31
+       max r0, #31
+
diff --git a/plat/rpi/build.mk b/plat/rpi/build.mk
new file mode 100644 (file)
index 0000000..20aed87
--- /dev/null
@@ -0,0 +1,47 @@
+# Build script for Raspberry Pi bare-metal executables (using the
+# VideoCore IV processor, not the ARM).
+#
+# © 2013 David Given
+# This file is redistributable under the terms of the 3-clause BSD license.
+# See the file 'Copying' in the root of the distribution for the full text.
+
+ARCH := vc4
+PLATFORM := rpi
+OPTIMISATION := -O
+
+D := plat/rpi/
+
+platform-headers := \
+       ack/config.h
+
+platform-libsys := \
+       _hol0.s \
+
+ifeq (x,y)
+       errno.s \
+       _sys_rawread.s \
+       _sys_rawwrite.s \
+       open.c \
+       creat.c \
+       close.c \
+       read.c \
+       write.c \
+       brk.c \
+       getpid.c \
+       kill.c \
+       isatty.c \
+       lseek.c \
+       time.c \
+       signal.c
+endif
+
+$(eval $(call build-platform))
+
+define build-rpi-boot-impl
+       $(call reset)
+       $(call ackfile, $D/boot.s)
+       $(call installto, $(PLATIND)/$(PLATFORM)/boot.o)
+endef
+
+#(eval $(build-rpi-boot-impl))
+
diff --git a/plat/rpi/descr b/plat/rpi/descr
new file mode 100644 (file)
index 0000000..41dfc40
--- /dev/null
@@ -0,0 +1,69 @@
+# $Source$
+# $State$
+# $Revision$
+
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var ARCH=vc4
+var PLATFORM=rpi
+var PLATFORMDIR={EM}/share/ack/{PLATFORM}
+var CPP_F=-D__unix
+var ALIGN=-a0:1 -a1:1 -a2:1 -a3:1
+var MACHOPT_F=-m8
+
+# Override the setting in fe so that files compiled for this platform can see
+# the platform-specific headers.
+
+var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
+
+name be
+       from .m.g
+       to .s
+       program {EM}/lib/ack/{PLATFORM}/ncg
+       args <
+       stdout
+       need .e
+end
+name as
+       from .s.so
+       to .o
+       program {EM}/lib/ack/{PLATFORM}/as
+       args - -o > <
+       prep cond
+end
+name led
+       from .o.a
+       to .out
+       program {EM}/lib/ack/em_led
+       mapflag -l* LNAME={PLATFORMDIR}/lib*
+       mapflag -i SEPID=-b1:0
+       mapflag -fp FLOATS={EM}/{ILIB}fp
+       args {ALIGN} {SEPID?} \
+           (.e:{HEAD}={PLATFORMDIR}/boot.o) \
+               ({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
+               ({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
+               ({RTS}:.mod={PLATFORMDIR}/modula2.o) \
+               ({RTS}:.p={PLATFORMDIR}/pascal.o) \
+               -o > < \
+               (.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
+               (.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
+               (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
+               (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
+               (.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
+               {FLOATS?} \
+               (.e:{TAIL}={PLATFORMDIR}/libem.a \
+                          {PLATFORMDIR}/libsys.a \
+                          {PLATFORMDIR}/libend.a)
+       linker
+end
+name cv
+       from .out
+       to .img
+       program {EM}/bin/aslod
+       args < >
+       outfile raspberrypi.bin
+end
diff --git a/plat/rpi/include/ack/config.h b/plat/rpi/include/ack/config.h
new file mode 100644 (file)
index 0000000..fd2c48c
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#ifndef _ACK_CONFIG_H
+#define _ACK_CONFIG_H
+
+#endif
diff --git a/plat/rpi/include/unistd.h b/plat/rpi/include/unistd.h
new file mode 100644 (file)
index 0000000..ddd8739
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <stddef.h>
+
+/* Types */
+
+typedef int pid_t;
+typedef int mode_t;
+
+/* Constants for file access (open and friends) */
+
+enum
+{
+       O_ACCMODE = 0x3,
+       
+       O_RDONLY = 0,
+       O_WRONLY = 1,
+       O_RDWR = 2,
+       
+       O_CREAT = 0100,
+       O_TRUNC = 01000,
+       O_APPEND = 02000,
+       O_NONBLOCK = 04000
+};
+
+/* Special variables */
+
+extern char** environ;
+
+/* Implemented system calls */
+
+extern void _exit(int);
+extern pid_t getpid(void);
+extern void* sbrk(intptr_t increment);
+extern int isatty(int d);
+extern off_t lseek(int fildes, off_t offset, int whence);
+extern int close(int d);
+extern int open(const char* path, int access, ...);
+extern int creat(const char* path, mode_t mode);
+extern int read(int fd, void* buffer, size_t count);
+extern int write(int fd, void* buffer, size_t count);
+
+/* Unimplemented system calls (these are just prototypes to let the library
+ * compile). */
+
+extern int fcntl(int fd, int op, ...);
+
+/* Signal handling */
+
+typedef int sig_atomic_t;
+
+#define SIG_ERR ((sighandler_t) -1)           /* Error return.  */
+#define SIG_DFL ((sighandler_t) 0)            /* Default action.  */
+#define SIG_IGN ((sighandler_t) 1)            /* Ignore signal.  */
+
+#define SIGABRT         6       /* Abort (ANSI) */
+#define SIGILL          11      /* Illegal instruction */
+
+#define _NSIG           32      /* Biggest signal number + 1
+                                   (not including real-time signals).  */
+typedef void (*sighandler_t)(int);
+extern sighandler_t signal(int signum, sighandler_t handler);
+extern int raise(int signum);
+
+#endif
diff --git a/plat/rpi/libsys/_hol0.s b/plat/rpi/libsys/_hol0.s
new file mode 100644 (file)
index 0000000..eed0081
--- /dev/null
@@ -0,0 +1,22 @@
+#
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+.sect .bss
+
+! This data block is used to store information about the current line number
+! and file.
+
+.define hol0
+.comm hol0, 8
diff --git a/plat/rpi/libsys/_sys_rawread.s b/plat/rpi/libsys/_sys_rawread.s
new file mode 100644 (file)
index 0000000..02edba2
--- /dev/null
@@ -0,0 +1,26 @@
+#
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+.sect .text
+
+! Reads a single byte.
+
+.define __sys_rawread
+__sys_rawread:
+       xorb ah, ah
+       int 0x16
+       xorb ah, ah
+       ret
+       
\ No newline at end of file
diff --git a/plat/rpi/libsys/_sys_rawwrite.s b/plat/rpi/libsys/_sys_rawwrite.s
new file mode 100644 (file)
index 0000000..a424574
--- /dev/null
@@ -0,0 +1,32 @@
+#
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+.sect .text
+
+! Writes a single byte to the console.
+
+.define __sys_rawwrite
+.extern __sys_rawwrite
+
+__sys_rawwrite:
+       push bp
+       mov bp, sp
+
+       movb al, 4(bp)
+       movb ah, 0x0E
+       mov bx, 0x0007
+       int 0x10
+       jmp .cret
+       
\ No newline at end of file
diff --git a/plat/rpi/libsys/brk.c b/plat/rpi/libsys/brk.c
new file mode 100644 (file)
index 0000000..cff32b9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#define        OUT_OF_MEMORY (void*)(-1)       /* sbrk returns this on failure */
+#define STACK_BUFFER 128 /* number of bytes to leave for stack */
+
+extern char _end[1];
+static char* current = _end;
+
+int brk(void* newend)
+{
+       /* This variable is used to figure out the current stack pointer,
+        * by taking its address. */
+       char dummy;
+       char* p = newend;
+       
+       if ((p > (&dummy - STACK_BUFFER)) ||
+           (p < _end)) 
+               return -1;
+               
+       current = p;
+       return 0;
+}
+
+void* sbrk(intptr_t increment)
+{
+       char* old;
+       
+       if (increment == 0)
+               return current;
+               
+       old = current;
+       if (brk(old + increment) < 0)
+               return OUT_OF_MEMORY;
+               
+       return old;
+}
diff --git a/plat/rpi/libsys/close.c b/plat/rpi/libsys/close.c
new file mode 100644 (file)
index 0000000..60fa0f9
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+int close(int fd)
+{
+       errno = EBADF;
+       return -1;
+}
diff --git a/plat/rpi/libsys/creat.c b/plat/rpi/libsys/creat.c
new file mode 100644 (file)
index 0000000..7c009e6
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libsys.h"
+
+int open(const char* path, int access, ...)
+{
+       errno = EACCES;
+       return -1;
+}
diff --git a/plat/rpi/libsys/errno.s b/plat/rpi/libsys/errno.s
new file mode 100644 (file)
index 0000000..a2e1f8b
--- /dev/null
@@ -0,0 +1,31 @@
+#
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+! Declare segments (the order is important).
+
+.sect .text
+.sect .rom
+.sect .data
+.sect .bss
+
+#define D(e) .define e; e
+
+.sect .data
+
+! Define various ACK error numbers. Note that these are *not* ANSI C
+! errnos, and are used for different purposes.
+
+D(ERANGE)         = 1
+D(ESET)           = 2
+D(EIDIVZ)         = 6
+D(EHEAP)          = 17
+D(EILLINS)        = 18
+D(EODDZ)          = 19
+D(ECASE)          = 20
+D(EBADMON)        = 25
+
diff --git a/plat/rpi/libsys/getpid.c b/plat/rpi/libsys/getpid.c
new file mode 100644 (file)
index 0000000..0ae1f61
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+pid_t getpid(void)
+{
+       return 0;
+}
diff --git a/plat/rpi/libsys/isatty.c b/plat/rpi/libsys/isatty.c
new file mode 100644 (file)
index 0000000..83837ba
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+int isatty(int fd)
+{
+       return 1;
+}
diff --git a/plat/rpi/libsys/kill.c b/plat/rpi/libsys/kill.c
new file mode 100644 (file)
index 0000000..bacc405
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+int kill(pid_t pid, int sig)
+{
+       errno = EINVAL;
+       return -1;
+}
diff --git a/plat/rpi/libsys/libsys.h b/plat/rpi/libsys/libsys.h
new file mode 100644 (file)
index 0000000..e9bff7e
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#ifndef LIBSYS_H
+#define LIBSYS_H
+
+extern void _sys_rawwrite(unsigned char b);
+extern unsigned char _sys_rawread(void);
+
+extern void _sys_write_tty(char c);
+
+/* extern int _sys_ttyflags; */
+
+#endif
diff --git a/plat/rpi/libsys/lseek.c b/plat/rpi/libsys/lseek.c
new file mode 100644 (file)
index 0000000..9a487d7
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+       errno = EINVAL;
+       return -1;
+}
diff --git a/plat/rpi/libsys/open.c b/plat/rpi/libsys/open.c
new file mode 100644 (file)
index 0000000..cbdc30e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libsys.h"
+
+int creat(const char* path, int mode)
+{
+       return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
diff --git a/plat/rpi/libsys/read.c b/plat/rpi/libsys/read.c
new file mode 100644 (file)
index 0000000..4766893
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libsys.h"
+
+int read(int fd, void* buffer, size_t count)
+{
+       char i;
+       
+       /* We're only allowed to read from fd 0, 1 or 2. */
+       
+       if ((fd < 0) || (fd > 2))
+       {
+               errno = EBADF;
+               return -1;
+       }
+       
+       /* Empty buffer? */
+       
+       if (count == 0)
+               return 0;
+       
+       /* Read one byte. */
+       
+       i = _sys_rawread();
+#if 0
+       if ((i == '\r') && !(_sys_ttyflags & RAW)) 
+               i = '\n';
+       if (_sys_ttyflags & ECHO)
+               _sys_write_tty(i);
+#endif
+       if (i == '\r') 
+               i = '\n';
+       _sys_write_tty(i);
+       
+       *(char*)buffer = i;
+       return 1;
+}
diff --git a/plat/rpi/libsys/signal.c b/plat/rpi/libsys/signal.c
new file mode 100644 (file)
index 0000000..10a2ded
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include "libsys.h"
+
+sighandler_t signal(int signum, sighandler_t handler)
+{
+       return SIG_DFL;
+}
diff --git a/plat/rpi/libsys/time.c b/plat/rpi/libsys/time.c
new file mode 100644 (file)
index 0000000..e448a33
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include "libsys.h"
+
+time_t time(time_t* t)
+{
+       if (t)
+               *t = 0;
+       return 0;
+}
diff --git a/plat/rpi/libsys/write.c b/plat/rpi/libsys/write.c
new file mode 100644 (file)
index 0000000..9a765b0
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Raspberry Pi support library for the ACK
+ * © 2013 David Given
+ * This file is redistributable under the terms of the 3-clause BSD license.
+ * See the file 'Copying' in the root of the distribution for the full text.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "libsys.h"
+
+void _sys_write_tty(char c)
+{
+       _sys_rawwrite(c);
+#if 0
+       if ((c == '\n') && !(_sys_ttyflags & RAW))
+               _sys_rawwrite('\r');
+#endif
+       if (c == '\n')
+               _sys_rawwrite('\r');
+}
+
+int write(int fd, void* buffer, size_t count)
+{
+       int i;
+       char* p = buffer;
+       
+       /* We're only allowed to write to fd 0, 1 or 2. */
+       
+       if ((fd < 0) || (fd > 2))
+       {
+               errno = EBADF;
+               return -1;
+       }
+       
+       /* Write all data. */
+       
+       i = 0;
+       while (i < count)
+       {
+               _sys_write_tty(*p++);
+                       
+               i++;
+       }
+       
+       /* No failures. */
+       
+       return count;
+}