summaryrefslogtreecommitdiff
path: root/os/ipengine
diff options
context:
space:
mode:
Diffstat (limited to 'os/ipengine')
-rw-r--r--os/ipengine/NOTICE4
-rw-r--r--os/ipengine/README40
-rw-r--r--os/ipengine/archipe.c488
-rw-r--r--os/ipengine/archipe.h32
-rw-r--r--os/ipengine/dat.h162
-rw-r--r--os/ipengine/devfpga.c389
-rw-r--r--os/ipengine/flash28f320b3b.c43
-rw-r--r--os/ipengine/fns.h120
-rw-r--r--os/ipengine/io.h1
-rw-r--r--os/ipengine/ipe109
-rw-r--r--os/ipengine/main.c348
-rw-r--r--os/ipengine/mem.h156
-rw-r--r--os/ipengine/mkfile105
-rw-r--r--os/ipengine/mmu.c20
-rw-r--r--os/ipengine/tlb.s21
15 files changed, 2038 insertions, 0 deletions
diff --git a/os/ipengine/NOTICE b/os/ipengine/NOTICE
new file mode 100644
index 00000000..f7d66a0d
--- /dev/null
+++ b/os/ipengine/NOTICE
@@ -0,0 +1,4 @@
+Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved.
+PowerPC support Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net). All rights reserved.
+MPC8xx Inferno PowerPC port Copyright © 1998-2003 Vita Nuova Holdings Limited. All rights reserved.
+ip-Engine1 PowerPC port Copyright © 2000-2003 Vita Nuova Holdings Limited. All rights reserved.
diff --git a/os/ipengine/README b/os/ipengine/README
new file mode 100644
index 00000000..3572de78
--- /dev/null
+++ b/os/ipengine/README
@@ -0,0 +1,40 @@
+The ipEngine-1 is a Motorola MPC8xx-based small computer
+made by Bright Star Engineering (www.brightstareng.com)
+which also provides Linux and their own operating system for it.
+It is an interesting hardware platform to do network-oriented Inferno
+applications.
+
+The ipEngine is unusual in including an FPGA (Altera Flex 6016).
+See fpga(3) and fpgaload(8).
+We are also working on software to help program the thing.
+
+
+Booting the ipEngine
+
+0. serial cable (port 1, 9600 baud), ether, power etc.
+
+1. make appropriate entries for your site in flash
+ using the BSE monitor:
+
+ set netmask 255.255.255.0
+ set nameserver 200.1.1.11
+ set server 200.1.1.11
+ set serverip 200.1.1.11
+ set gateway 200.1.1.50
+ set hostname stella
+ set domain vitanuova.com
+ set myip 200.1.1.96
+
+2. add an entry to do the boot by tftp:
+
+ set bootcmd "load /usr/inferno/os/ipengine/iipe 3000; go 3020"
+
+ contrary to the BSE documentation this loads any
+ binary file at the given address. the -b option
+ doesn't seem to be needed.
+
+3. reset
+ it should load and start the kernel
+
+Vita Nuova
+16 July 2003
diff --git a/os/ipengine/archipe.c b/os/ipengine/archipe.c
new file mode 100644
index 00000000..151f72f7
--- /dev/null
+++ b/os/ipengine/archipe.c
@@ -0,0 +1,488 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include <draw.h>
+#include <memdraw.h>
+#include "screen.h"
+
+#include "../port/netif.h"
+#include "etherif.h"
+#include "../port/flashif.h"
+
+#include "archipe.h"
+
+/*
+ * board-specific support for the Bright Star Engineering ipEngine-1
+ */
+
+enum {
+ /* sccr */
+ COM3= IBIT(1)|IBIT(2), /* clock output disabled */
+ TBS = IBIT(6), /* =0, time base is OSCCLK/{4,16}; =1, time base is GCLK2/16 */
+ RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */
+ RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */
+ CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */
+ PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */
+
+ /* plprcr */
+ CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */
+
+ Showports = 0, /* used to find lightly-documented bits set by bootstrap (eg, PDN) */
+};
+
+static ulong ports[4*4];
+
+/*
+ * called early in main.c, after machinit:
+ * using board and architecture specific registers, initialise
+ * 8xx registers that need it and complete initialisation of the Mach structure.
+ */
+void
+archinit(void)
+{
+ IMM *io;
+ int mf;
+
+ io = m->iomem; /* run by reset code: no need to lock */
+ m->clockgen = 4000000; /* crystal frequency */
+ m->oscclk = m->clockgen/MHz;
+ io->plprcrk = KEEP_ALIVE_KEY;
+ io->plprcr &= ~CSRC; /* general system clock is DFNH */
+ mf = (io->plprcr >> 20)+1; /* use timing set by bootstrap */
+ io->plprcrk = ~KEEP_ALIVE_KEY;
+ io->sccrk = KEEP_ALIVE_KEY;
+ io->sccr |= CRQEN | PRQEN | RTDIV | COM3; /* devfpga.c resets COM3 if needed */
+ io->sccrk = ~KEEP_ALIVE_KEY;
+ m->cpuhz = m->clockgen*mf;
+ m->speed = m->cpuhz/MHz;
+ if((io->memc[CLOCKCS].base & 1) == 0){ /* prom hasn't mapped it */
+ io->memc[CLOCKCS].option = 0xFFFF0F24;
+ io->memc[CLOCKCS].base = 0xFF020001;
+ }
+ if(Showports){
+ ports[0] = io->padat;
+ ports[1] = io->padir;
+ ports[2] = io->papar;
+ ports[3] = io->paodr;
+ ports[4] = io->pbdat;
+ ports[5] = io->pbdir;
+ ports[6] = io->pbpar;
+ ports[7] = io->pbodr;
+ ports[8] = io->pcdat;
+ ports[9] = io->pcdir;
+ ports[10] = io->pcpar;
+ ports[11] = io->pcso;
+ ports[12] = io->pddat;
+ ports[13] = io->pddir;
+ ports[14] = io->pdpar;
+ ports[15] = 0;
+ }
+}
+
+static ulong
+banksize(int x, ulong *pa)
+{
+ IMM *io;
+
+ io = m->iomem;
+ if((io->memc[x].base & 1) == 0)
+ return 0; /* bank not valid */
+ *pa = io->memc[x].base & ~0x7FFF;
+ return -(io->memc[x].option&~0x7FFF);
+}
+
+/*
+ * initialise the kernel's memory configuration:
+ * there are two banks (base0, npage0) and (base1, npage1).
+ * initialise any other values in conf that are board-specific.
+ */
+void
+archconfinit(void)
+{
+ ulong pa, nbytes, ktop;
+
+ conf.nscc = 2;
+ conf.sccuarts = 0; /* no SCC uarts */
+ conf.smcuarts = (1<<0)|(1<<1); /* SMC1 (console) and SMC2 */
+
+ nbytes = banksize(DRAMCS, &pa);
+ if(nbytes == 0){ /* force default */
+ nbytes = 16*1024*1024;
+ pa = 0;
+ }
+ conf.npage0 = nbytes/BY2PG;
+ conf.base0 = pa;
+
+ conf.npage1 = 0;
+
+ /* the following assumes the kernel text and/or data is in bank 0 */
+ ktop = PGROUND((ulong)end);
+ ktop = PADDR(ktop) - conf.base0;
+ conf.npage0 -= ktop/BY2PG;
+ conf.base0 += ktop;
+}
+
+void
+cpuidprint(void)
+{
+ ulong v;
+
+ print("PVR: ");
+ switch(m->cputype){
+ case 0x01: print("MPC601"); break;
+ case 0x03: print("MPC603"); break;
+ case 0x04: print("MPC604"); break;
+ case 0x06: print("MPC603e"); break;
+ case 0x07: print("MPC603e-v7"); break;
+ case 0x50: print("MPC8xx"); break;
+ default: print("PowerPC version #%x", m->cputype); break;
+ }
+ print(", revision #%lux\n", getpvr()&0xffff);
+ print("IMMR: ");
+ v = getimmr() & 0xFFFF;
+ switch(v>>8){
+ case 0x00: print("MPC860/821"); break;
+ case 0x20: print("MPC823"); break;
+ case 0x21: print("MPC823A"); break;
+ default: print("Type #%lux", v>>8); break;
+ }
+ print(", mask #%lux\n", v&0xFF);
+ print("%lud MHz system\n", m->cpuhz/MHz);
+ print("\n");
+
+ if(Showports){
+
+ print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr);
+ print("pipr=%8.8lux\n", m->iomem->pipr);
+
+ print("ports:\n");
+ for(v=0;v<nelem(ports);v++)
+ print("%2ld %8.8lux\n", v, ports[v]);
+
+ /* dump the memory configuration while we're at it */
+ for(v=0; v<nelem(m->iomem->memc); v++)
+ if(m->iomem->memc[v].base & 1)
+ print("%ld %8.8lux %8.8lux\n", v, m->iomem->memc[v].base, m->iomem->memc[v].option);
+ }
+}
+
+/*
+ * fetch parameters from flash, as stored by BSE bootstrap,
+ * compensating for a bug in its fset that produces silly entries.
+ */
+
+static int
+envnameok(char *s)
+{
+ if(*s == '*')
+ s++;
+ if(*s >= '0' && *s <= '9' || *s == 0)
+ return 0;
+ for(; *s; s++)
+ if(*s >= '0' && *s <= '9' ||
+ *s >= 'a' && *s <= 'z' ||
+ *s >= 'A' && *s <= 'Z' ||
+ *s == '.' || *s == '_' || *s == '#'){
+ /* ok */
+ }else
+ return 0;
+ return 1;
+}
+
+int
+archconfval(char **names, char **vals, int limit)
+{
+ uchar *b, *e;
+ char *s;
+ int n, v, l, o;
+ static char bootargs[512];
+
+ /* we assume we can access this space before mmuinit() */
+ b = KADDR(PHYSFLASH+0x4000);
+ if(*b & 1){
+ b += 0x2000; /* try alternative location */
+ if(*b & 1)
+ return 0;
+ }
+ v = (b[2]<<8)|b[3];
+ b += 4;
+ if(v >= 0x2000-4)
+ return 0;
+ n = 0;
+ o = 0;
+ e = b+v;
+ for(; b < e; b += v){
+ v = *b;
+ if(v == 0xFF || n >= limit)
+ break;
+ s = (char*)b+1;
+ if(v >= 0x80){
+ v = ((v&0x7F)<<8) | b[1];
+ s++;
+ }
+ if(envnameok(s)){
+ names[n] = s;
+ s += strlen(s)+1;
+ l = strlen(s)+1;
+ if(o+l > sizeof(bootargs))
+ break;
+ vals[n] = bootargs+o;
+ memmove(vals[n], s, l);
+ o += l;
+ n++;
+ }
+ }
+ return n;
+}
+
+void
+toggleled(int b)
+{
+ int s;
+ s = splhi();
+ m->iomem->pdpar &= ~(0x20<<b);
+ m->iomem->pddir |= 0x20<<b;
+ m->iomem->pddat ^= 0x020<<b;
+ splx(s);
+}
+
+/*
+ * provide value for #r/switch (devrtc.c)
+ */
+int
+archoptionsw(void)
+{
+ return 0;
+}
+
+/*
+ * invoked by clock.c:/^clockintr
+ */
+static void
+twinkle(void)
+{
+ if(m->ticks%MS2TK(1000) == 0 && m->iomem)
+ toggleled(0);
+}
+
+void (*archclocktick)(void) = twinkle;
+
+/*
+ * invoked by ../port/taslock.c:/^ilock:
+ * reset watchdog timer here, if there is one and it is enabled
+ */
+void
+clockcheck(void)
+{
+}
+
+/*
+ * for ../port/devflash.c:/^flashreset
+ * retrieve flash type, virtual base and length and return 0;
+ * return -1 on error (no flash)
+ */
+int
+archflashreset(int bank, Flash *f)
+{
+ if(bank != 0)
+ return -1;
+ f->type = "Intel28F320B3B";
+ f->addr = KADDR(PHYSFLASH);
+ f->size = 4*1024*1024;
+ f->width = 2;
+ return 0;
+}
+
+void
+archflashwp(Flash*, int)
+{
+}
+
+/*
+ * set ether parameters: the contents should be derived from EEPROM or NVRAM
+ */
+int
+archether(int ctlno, Ether *ether)
+{
+ if(isaconfig("ether", ctlno, ether) == 0 && ctlno > 0)
+ return -1;
+ if(ctlno == 0){
+ ether->type = "SCC";
+ ether->port = 2;
+ }
+ memmove(ether->ea, KADDR(PHYSFLASH+0x3FFA), Eaddrlen);
+ return 1;
+}
+
+/*
+ * enable the clocks for the given SCC ether and reveal them to the caller.
+ * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback).
+ */
+int
+archetherenable(int cpmid, int *rcs, int *tcs, int mbps, int fd)
+{
+ IMM *io;
+
+ if(cpmid != CPscc2)
+ return -1;
+ USED(mbps);
+ io = ioplock();
+ io->pcpar &= ~EnetLoopback;
+ io->pcso &= ~EnetLoopback;
+ io->pcdir |= EnetLoopback;
+ io->pcdat &= ~EnetLoopback;
+ if(0){ /* TO CHECK: causes ether errors if used */
+ io->pbpar &= ~EnetFullDuplex;
+ io->pbdir |= EnetFullDuplex;
+ if(fd)
+ io->pbdat |= EnetFullDuplex;
+ else
+ io->pbdat &= ~EnetFullDuplex;
+ }
+ io->pbpar &= ~EnableEnet;
+ io->pbdir |= EnableEnet;
+ io->pbdat |= EnableEnet;
+ io->papar |= SIBIT(7)|SIBIT(6); /* enable CLK1 and CLK2 */
+ io->padir &= ~(SIBIT(7)|SIBIT(6));
+ iopunlock();
+ *rcs = CLK2;
+ *tcs = CLK1;
+ return 0;
+}
+
+/*
+ * do anything extra required to enable the UART on the given CPM port
+ */
+static ulong uartsactive;
+
+void
+archenableuart(int id, int irda)
+{
+ IMM *io;
+
+ USED(id); /* both uarts seem to be controlled by the same bit */
+ USED(irda); /* no IrDA on ipEngine */
+ io = ioplock();
+ if(uartsactive == 0){
+ io->pbpar &= ~EnableRS232;
+ io->pbdir |= EnableRS232;
+ io->pbdat |= EnableRS232;
+ }
+ uartsactive |= 1<<id;
+ iopunlock();
+}
+
+/*
+ * do anything extra required to disable the UART on the given CPM port
+ */
+void
+archdisableuart(int id)
+{
+ IMM *io;
+
+ io = ioplock();
+ uartsactive &= ~(1<<id);
+ if(uartsactive == 0)
+ io->pbdat &= ~EnableRS232;
+ iopunlock();
+}
+
+/*
+ * enable the external USB transceiver
+ * speed is 12MHz if highspeed is non-zero; 1.5MHz if zero
+ * master is non-zero if the node is acting as USB Host and should provide power
+ */
+void
+archenableusb(int highspeed, int master)
+{
+ IMM *io;
+
+ USED(master);
+ io = ioplock();
+ io->pcpar &= ~USBFullSpeed;
+ io->pcso &= ~USBFullSpeed;
+ if(highspeed)
+ io->pcdat |= USBFullSpeed;
+ else
+ io->pcdat &= ~USBFullSpeed;
+ io->pcdir |= USBFullSpeed;
+ iopunlock();
+}
+
+/*
+ * shut down the USB transceiver
+ */
+void
+archdisableusb(void)
+{
+ /* nothing to be done on ipEngine, apparently */
+}
+
+/*
+ * set the external infrared transceiver to the given speed
+ */
+void
+archsetirxcvr(int highspeed)
+{
+ USED(highspeed);
+}
+
+/*
+ * force hardware reset/reboot
+ */
+void
+archreboot(void)
+{
+ IMM *io;
+
+ io = m->iomem;
+ io->plprcrk = KEEP_ALIVE_KEY;
+ io->plprcr |= 1<<7; /* checkstop reset enable */
+ io->plprcrk = ~KEEP_ALIVE_KEY;
+ eieio();
+ io->sdcr = 1;
+ eieio();
+ io->lccr = 0; /* switch LCD off */
+ eieio();
+ firmware(0);
+}
+
+/*
+ * enable/disable the LCD panel's backlight
+ */
+void
+archbacklight(int on)
+{
+ USED(on);
+}
+
+/*
+ * set parameters to describe the screen
+ */
+int
+archlcdmode(Mode *m)
+{
+ /* sample parameters in case a panel is attached to the external pins */
+ m->x = 640;
+ m->y = 480;
+ m->d = 3;
+ m->lcd.freq = 25000000;
+ m->lcd.ac = 0;
+ m->lcd.vpw = 1;
+ m->lcd.wbf = 33;
+ m->lcd.wbl = 228;
+ m->lcd.flags = IsColour | IsTFT | OELow | VsyncLow | ClockLow;
+ return -1; /* there isn't a screen */
+}
+
+/*
+ * there isn't a keyboard port
+ */
+void
+archkbdinit(void)
+{
+}
diff --git a/os/ipengine/archipe.h b/os/ipengine/archipe.h
new file mode 100644
index 00000000..575f7d8d
--- /dev/null
+++ b/os/ipengine/archipe.h
@@ -0,0 +1,32 @@
+/*
+ * values for Brightstar Engineering ipEngine
+ */
+enum {
+ /* CS assignment */
+ BOOTCS = 0, /* flash */
+ FPGACS = 1, /* 8Mb FPGA space */
+ DRAMCS = 2,
+ FPGACONFCS = 3, /* FPGA config */
+ CLOCKCS = 4, /* clock synth reg */
+};
+
+enum {
+ /* port A pins */
+ VCLK= SIBIT(5),
+ BCLK= SIBIT(4),
+
+ /* port B */
+ EnableVCLK= IBIT(30),
+ EnableEnet= IBIT(29),
+ EnableRS232= IBIT(28),
+ EnetFullDuplex= IBIT(16),
+
+ /* port C */
+ nCONFIG = SIBIT(13), /* FPGA configuration */
+ USBFullSpeed= SIBIT(12),
+ PDN= SIBIT(5), /* ? seems to control power to FPGA subsystem? */
+ EnetLoopback= SIBIT(4),
+
+ /* nSTATUS is ip_b1, conf_done is ip_b0 in PIPR (hardware doc wrongly says ip_b2 and ip_b1) */
+
+};
diff --git a/os/ipengine/dat.h b/os/ipengine/dat.h
new file mode 100644
index 00000000..19d7c560
--- /dev/null
+++ b/os/ipengine/dat.h
@@ -0,0 +1,162 @@
+typedef struct Conf Conf;
+typedef struct FPU FPU;
+typedef struct FPenv FPenv;
+typedef struct IMM IMM;
+typedef struct Irqctl Irqctl;
+typedef struct ISAConf ISAConf;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Mach Mach;
+typedef struct Map Map;
+typedef struct Power Power;
+typedef struct RMap RMap;
+typedef struct Ureg Ureg;
+
+typedef ulong Instr;
+
+#define MACHP(n) (n==0? &mach0 : *(Mach**)0)
+
+struct Lock
+{
+ ulong key;
+ ulong pc;
+ ulong sr;
+ int pri;
+};
+
+struct Label
+{
+ ulong sp;
+ ulong pc;
+};
+
+/*
+ * Proc.fpstate
+ */
+enum
+{
+ FPINIT,
+ FPACTIVE,
+ FPINACTIVE,
+};
+
+/*
+ * This structure must agree with FPsave and FPrestore asm routines
+ */
+struct FPenv
+{
+ union {
+ double fpscrd;
+ struct {
+ ulong pad;
+ ulong fpscr;
+ };
+ };
+ int fpistate; /* emulated fp */
+ ulong emreg[32][3]; /* emulated fp */
+};
+/*
+ * This structure must agree with fpsave and fprestore asm routines
+ */
+struct FPU
+{
+ double fpreg[32];
+ FPenv env;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ ulong npage0; /* total physical pages of memory */
+ ulong npage1; /* total physical pages of memory */
+ ulong npage; /* total physical pages of memory */
+ ulong base0; /* base of bank 0 */
+ ulong base1; /* base of bank 1 */
+ ulong ialloc; /* max interrupt time allocation in bytes */
+
+ int nscc; /* number of SCCs implemented */
+ ulong smcuarts; /* bits for SMCs to define as eiaN */
+ ulong sccuarts; /* bits for SCCs to define as eiaN */
+ int nocts2; /* CTS2 and CD2 aren't connected */
+ uchar* nvrambase; /* virtual address of nvram */
+ ulong nvramsize; /* size in bytes */
+};
+
+#include "../port/portdat.h"
+
+/*
+ * machine dependent definitions not used by ../port/dat.h
+ */
+
+struct Mach
+{
+ /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
+ int machno; /* physical id of processor (unused) */
+ ulong splpc; /* pc of last caller to splhi (unused) */
+ int mmask; /* 1<<m->machno (unused) */
+
+ /* ordering from here on irrelevant */
+ ulong ticks; /* of the clock since boot time */
+ Proc *proc; /* current process on this processor */
+ Label sched; /* scheduler wakeup */
+ Lock alarmlock; /* access to alarm list */
+ void *alarm; /* alarms bound to this clock */
+ int nrdy;
+ int speed; /* general system clock in MHz */
+ long oscclk; /* oscillator frequency (MHz) */
+ long cpuhz; /* general system clock (cycles) */
+ long clockgen; /* clock generator frequency (cycles) */
+ int cputype;
+ ulong delayloop;
+ ulong* bcsr;
+ IMM* iomem; /* MPC8xx internal i/o control memory */
+
+ /* MUST BE LAST */
+ int stack[1];
+};
+extern Mach mach0;
+
+
+/*
+ * a parsed .ini line
+ */
+#define NISAOPT 8
+
+struct ISAConf {
+ char* type;
+ ulong port;
+ ulong irq;
+ ulong mem;
+ int dma;
+ ulong size;
+ ulong freq;
+ uchar bus;
+
+ int nopt;
+ char* opt[NISAOPT];
+};
+
+struct Map {
+ int size;
+ ulong addr;
+};
+
+struct RMap {
+ char* name;
+ Map* map;
+ Map* mapend;
+
+ Lock;
+};
+
+struct Power {
+ Dev* dev;
+ int (*powerdown)(Power*);
+ int (*powerup)(Power*);
+ int state;
+ void* arg;
+};
+
+extern register Mach *m;
+extern register Proc *up;
diff --git a/os/ipengine/devfpga.c b/os/ipengine/devfpga.c
new file mode 100644
index 00000000..41d1a445
--- /dev/null
+++ b/os/ipengine/devfpga.c
@@ -0,0 +1,389 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "io.h"
+#include "archipe.h"
+
+enum {
+ FPGASIZE = 8*1024*1024,
+ FPGATMR = 2-1, /* BCLK timer number (mapped to origin 0) */
+ TIMERSH = FPGATMR*4, /* timer field shift */
+
+ COM3= IBIT(1)|IBIT(2), /* sccr: clock output disabled */
+
+ ConfDone = 1<<1,
+ nStatus = 1<<0,
+};
+
+/*
+ * provisional FPGA interface for simple development work;
+ * for more complex things, use this to load the device then have a
+ * purpose-built device driver or module
+ */
+
+enum{
+ Qdir,
+ Qmemb,
+ Qmemw,
+ Qprog,
+ Qctl,
+ Qclk,
+ Qstatus,
+};
+
+static struct {
+ QLock;
+ int clkspeed;
+} fpga;
+
+static void resetfpga(void);
+static void startfpga(int);
+static int endfpga(void);
+static int fpgastatus(void);
+static void powerfpga(int);
+static void vclkenable(int);
+static void vclkset(char*, char*, char*, char*);
+static void memmovew(ushort*, ushort*, long);
+
+static Dirtab fpgadir[]={
+ ".", {Qdir, 0, QTDIR}, 0, 0555,
+ "fpgamemb", {Qmemb, 0}, FPGASIZE, 0666,
+ "fpgamemw", {Qmemw, 0}, FPGASIZE, 0666,
+ "fpgaprog", {Qprog, 0}, 0, 0222,
+ "fpgastatus", {Qstatus, 0}, 0, 0444,
+ "fpgactl", {Qctl, 0}, 0, 0666,
+ "fpgaclk", {Qclk, 0}, 0, 0666,
+};
+
+static char Eodd[] = "odd count or offset";
+
+static void
+fpgareset(void)
+{
+ powerfpga(0);
+}
+
+static Chan*
+fpgaattach(char *spec)
+{
+ return devattach('G', spec);
+}
+
+static Walkqid*
+fpgawalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ return devwalk(c, nc, name, nname, fpgadir, nelem(fpgadir), devgen);
+}
+
+static int
+fpgastat(Chan *c, uchar *dp, int n)
+{
+ return devstat(c, dp, n, fpgadir, nelem(fpgadir), devgen);
+}
+
+static Chan*
+fpgaopen(Chan *c, int omode)
+{
+ return devopen(c, omode, fpgadir, nelem(fpgadir), devgen);
+}
+
+static void
+fpgaclose(Chan*)
+{
+}
+
+static long
+fpgaread(Chan *c, void *buf, long n, vlong offset)
+{
+ int v;
+ char stat[32], *p;
+
+ if(c->qid.type & QTDIR)
+ return devdirread(c, buf, n, fpgadir, nelem(fpgadir), devgen);
+
+ switch((ulong)c->qid.path){
+ case Qmemb:
+ if(offset >= FPGASIZE)
+ return 0;
+ if(offset+n >= FPGASIZE)
+ n = FPGASIZE-offset;
+ memmove(buf, KADDR(FPGAMEM+offset), n);
+ return n;
+ case Qmemw:
+ if((n | offset) & 1)
+ error(Eodd);
+ if(offset >= FPGASIZE)
+ return 0;
+ if(offset+n >= FPGASIZE)
+ n = FPGASIZE-offset;
+ memmovew((ushort*)buf, (ushort*)KADDR(FPGAMEM+offset), n);
+ return n;
+ case Qstatus:
+ v = fpgastatus();
+ p = seprint(stat, stat+sizeof(stat), "%sconfig", v&ConfDone?"":"!");
+ seprint(p, stat+sizeof(stat), " %sstatus\n", v&nStatus?"":"!");
+ return readstr(offset, buf, n, stat);
+ case Qclk:
+ return readnum(offset, buf, n, fpga.clkspeed, NUMSIZE);
+ case Qctl:
+ case Qprog:
+ return 0;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+static long
+fpgawrite(Chan *c, void *buf, long n, vlong offset)
+{
+ int i, j, v;
+ ulong w;
+ Cmdbuf *cb;
+ ulong *cfg;
+ uchar *cp;
+
+ switch((ulong)c->qid.path){
+ case Qmemb:
+ if(offset >= FPGASIZE)
+ return 0;
+ if(offset+n >= FPGASIZE)
+ n = FPGASIZE-offset;
+ memmove(KADDR(FPGAMEM+offset), buf, n);
+ return n;
+ case Qmemw:
+ if((n | offset) & 1)
+ error(Eodd);
+ if(offset >= FPGASIZE)
+ return 0;
+ if(offset+n >= FPGASIZE)
+ n = FPGASIZE-offset;
+ memmovew((ushort*)KADDR(FPGAMEM+offset), (ushort*)buf, n);
+ return n;
+ case Qctl:
+ cb = parsecmd(buf, n);
+ if(waserror()){
+ free(cb);
+ nexterror();
+ }
+ if(cb->nf < 1)
+ error(Ebadarg);
+ if(strcmp(cb->f[0], "reset") == 0)
+ resetfpga();
+ else if(strcmp(cb->f[0], "bclk") == 0){
+ v = 48;
+ if(cb->nf > 1)
+ v = strtoul(cb->f[1], nil, 0);
+ if(v <= 0 || 48%v != 0)
+ error(Ebadarg);
+ startfpga(48/v-1);
+ }else if(strcmp(cb->f[0], "vclk") == 0){
+ if(cb->nf == 5){ /* vclk n m v r */
+ vclkenable(1);
+ vclkset(cb->f[1], cb->f[2], cb->f[3], cb->f[4]);
+ }else
+ vclkenable(cb->nf < 2 || strcmp(cb->f[1], "on") == 0);
+ }else if(strcmp(cb->f[0], "power") == 0)
+ powerfpga(cb->nf < 2 || strcmp(cb->f[1], "off") != 0);
+ else
+ error(Ebadarg);
+ poperror();
+ free(cb);
+ return n;
+ case Qprog:
+ qlock(&fpga);
+ if(waserror()){
+ qunlock(&fpga);
+ nexterror();
+ }
+ powerfpga(1);
+ resetfpga();
+ cfg = KADDR(FPGACR);
+ cp = buf;
+ for(i=0; i<n; i++){
+ w = cp[i];
+ for(j=0; j<8; j++){
+ *cfg = w&1;
+ w >>= 1;
+ }
+ }
+ for(j=0; j<50; j++) /* Altera note says at least 10 clock cycles, but microblaster uses 50 */
+ *cfg = 0;
+ v = fpgastatus();
+ if(v != (nStatus|ConfDone)){
+ snprint(up->genbuf, sizeof(up->genbuf), "error loading fpga: status %d", v);
+ error(up->genbuf);
+ }
+ poperror();
+ qunlock(&fpga);
+ return n;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+/*
+ * PDN seems to control power to the FPGA subsystem
+ * but it is not documented nor is its scope clear (PLL as well?).
+ * It will not run without it.
+ */
+static void
+powerfpga(int on)
+{
+ IMM *io;
+
+ io = ioplock();
+ if(io->sccr & COM3){
+ io->sccrk = KEEP_ALIVE_KEY;
+ io->sccr &= ~ COM3; /* FPGA designs can use the clock */
+ io->sccrk = ~KEEP_ALIVE_KEY;
+ }
+ io->pcpar &= ~PDN;
+ io->pcdir |= PDN;
+ if(on)
+ io->pcdat &= ~PDN;
+ else
+ io->pcdat |= PDN;
+ iopunlock();
+}
+
+static void
+resetfpga(void)
+{
+ IMM *io;
+
+ io = ioplock();
+ io->pcpar &= ~nCONFIG;
+ io->pcdir |= nCONFIG;
+ io->pcdat &= ~nCONFIG;
+ microdelay(200);
+ io->pcdat |= nCONFIG;
+ iopunlock();
+}
+
+static int
+fpgastatus(void)
+{
+ /* isolate status bits IP_B0 and IP_B1 */
+ return (m->iomem->pipr>>14) & (ConfDone|nStatus);
+}
+
+static void
+startfpga(int scale)
+{
+ IMM *io;
+
+ io = ioplock();
+ io->tgcr &= ~(0xF<<TIMERSH);
+ io->tmr2 = ((scale&0xFF)<<8) | 0x2A;
+ io->tcn2 = 0;
+ io->trr2 = 0;
+ io->ter2 = 0xFFFF;
+ io->tgcr |= 0x1<<TIMERSH;
+ io->padir |= BCLK;
+ io->papar |= BCLK;
+ iopunlock();
+}
+
+static void
+vclkenable(int i)
+{
+ IMM *io;
+
+ io = ioplock();
+ io->padir &= ~VCLK;
+ io->papar &= ~VCLK;
+ io->pbdir |= EnableVCLK;
+ io->pbpar &= ~EnableVCLK;
+ if(i)
+ io->pbdat |= EnableVCLK;
+ else
+ io->pbdat &= ~EnableVCLK;
+ iopunlock();
+}
+
+static void
+vclkin(ulong *clk, int v)
+{
+ int i;
+
+ for(i=0; i<7; i++)
+ *clk = (v>>i) & 1;
+}
+
+static void
+vclkset(char *ns, char *ms, char *vs, char *rs)
+{
+ int n, m, v, r;
+ ulong *clk;
+
+ clk = KADDR(CLOCKCR);
+ n = strtol(ns, nil, 0);
+ m = strtol(ms, nil, 0);
+ v = strtol(vs, nil, 0);
+ r = strtol(rs, nil, 0);
+ if(n < 3 || n > 127 || m < 3 || m > 127 || v != 1 && v != 8 ||
+ r != 1 && r != 2 && r != 4 && r != 8)
+ error(Ebadarg);
+ vclkenable(0);
+ vclkin(clk, n);
+ vclkin(clk, m);
+ *clk = (v==0) & 1;
+ *clk = 1; *clk = 1;
+ *clk = r == 2 || r == 8;
+ *clk = r == 4 || r == 8;
+ *clk = 1; /* clock out */
+ *clk = 0; /* disable clk/x */
+ *clk = 1; *clk = 0; *clk = 1;
+ *clk = 0; *clk = 0; *clk = 0;
+ vclkenable(1);
+}
+
+/*
+ * copy data aligned on 16-bit word boundaries.
+ */
+static void
+memmovew(ushort *to, ushort *from, long count)
+{
+ int n;
+
+ if(count <= 0)
+ return;
+ count >>= 1;
+ n = (count+7) >> 3;
+ switch(count&7) { /* Duff's device */
+ case 0: do { *to++ = *from++;
+ case 7: *to++ = *from++;
+ case 6: *to++ = *from++;
+ case 5: *to++ = *from++;
+ case 4: *to++ = *from++;
+ case 3: *to++ = *from++;
+ case 2: *to++ = *from++;
+ case 1: *to++ = *from++;
+ } while(--n > 0);
+ }
+}
+
+Dev fpgadevtab = {
+ 'G',
+ "fpga",
+
+ fpgareset,
+ devinit,
+ devshutdown,
+ fpgaattach,
+ fpgawalk,
+ fpgastat,
+ fpgaopen,
+ devcreate,
+ fpgaclose,
+ fpgaread,
+ devbread,
+ fpgawrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
diff --git a/os/ipengine/flash28f320b3b.c b/os/ipengine/flash28f320b3b.c
new file mode 100644
index 00000000..27bb90d6
--- /dev/null
+++ b/os/ipengine/flash28f320b3b.c
@@ -0,0 +1,43 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "../port/flashif.h"
+
+/*
+ * Intel 28F320B3B in word mode
+ */
+
+#define I(x) (x)
+enum {
+ ReadArray = 0x00FF,
+};
+
+#include "../port/flashintel"
+
+static int
+reset(Flash *f)
+{
+ f->id = 0x0089; /* can't use autoselect: might be running in flash */
+ f->devid = 0x8897;
+ f->write = intelwrite2;
+ f->erasezone = intelerase;
+ f->width = 2;
+ f->cmask = 0x00FF;
+ *(ushort*)f->addr = ClearStatus;
+ *(ushort*)f->addr = ReadArray;
+ f->nr = 2;
+ f->regions[0] = (Flashregion){8, 0, 8*(8*1024), 8*1024, 0};
+ f->regions[1] = (Flashregion){63, 64*1024, 4*1024*1024, 64*1024, 0};
+ return 0;
+}
+
+void
+flash28f320b3blink(void)
+{
+ addflashcard("Intel28F320B3B", reset);
+}
diff --git a/os/ipengine/fns.h b/os/ipengine/fns.h
new file mode 100644
index 00000000..6a92e5cd
--- /dev/null
+++ b/os/ipengine/fns.h
@@ -0,0 +1,120 @@
+#include "../port/portfns.h"
+
+void addpower(Power*);
+void archbacklight(int);
+void archconfinit(void);
+int archconfval(char**, char**, int);
+void archdisableuart(int);
+void archdisableusb(void);
+void archdisablevideo(void);
+void archenableuart(int, int);
+void archenableusb(int, int);
+void archenablevideo(void);
+void archkbdinit(void);
+void archresetvideo(void);
+int archetherenable(int, int*, int*, int, int);
+void archinit(void);
+int archoptionsw(void);
+void archreboot(void);
+void archsetirxcvr(int);
+uchar* archvideobuffer(long);
+ulong baudgen(int, int);
+int brgalloc(void);
+void brgfree(int);
+int cistrcmp(char*, char*);
+int cistrncmp(char*, char*, int);
+void clockcheck(void);
+void clockinit(void);
+void clockintr(Ureg*);
+void clrfptrap(void);
+#define coherence() /* nothing needed for uniprocessor */
+void cpminit(void);
+void cpuidprint(void);
+void dcflush(void*, ulong);
+void dcinval(void*, ulong);
+void delay(int);
+void dtlbmiss(void);
+void dumplongs(char*, ulong*, int);
+void dumpregs(Ureg*);
+void eieio(void);
+void faultpower(Ureg*);
+void firmware(int);
+void fpinit(void);
+int fpipower(Ureg*);
+void fpoff(void);
+void fprestore(FPU*);
+void fpsave(FPU*);
+ulong fpstatus(void);
+char* getconf(char*);
+ulong getdar(void);
+ulong getdec(void);
+ulong getdepn(void);
+ulong getdsisr(void);
+ulong getimmr(void);
+ulong getmsr(void);
+ulong getpvr(void);
+ulong gettbl(void);
+ulong gettbu(void);
+void gotopc(ulong);
+void icflush(void*, ulong);
+void idle(void);
+#define idlehands() /* nothing to do in the runproc */
+void intr(Ureg*);
+void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*);
+int intrstats(char*, int);
+void intrvec(void);
+int isaconfig(char*, int, ISAConf*);
+int isvalid_va(void*);
+void itlbmiss(void);
+void kbdinit(void);
+void kbdreset(void);
+void lcdpanel(int);
+void links(void);
+void mapfree(RMap*, ulong, int);
+void mapinit(RMap*, Map*, int);
+void mathinit(void);
+void mmuinit(void);
+ulong* mmuwalk(ulong*, ulong, int);
+void pcmenable(void);
+void pcmintrenable(int, void (*)(Ureg*, void*), void*);
+int pcmpin(int slot, int type);
+void pcmpower(int, int);
+int pcmpowered(int);
+void pcmsetvcc(int, int);
+void pcmsetvpp(int, int);
+void procsave(Proc*);
+void procsetup(Proc*);
+void putdec(ulong);
+void putmsr(ulong);
+void puttwb(ulong);
+ulong rmapalloc(RMap*, ulong, int, int);
+void screeninit(void);
+int screenprint(char*, ...); /* debugging */
+void (*screenputs)(char*, int);
+int segflush(void*, ulong);
+void toggleled(int);
+void setpanic(void);
+long spioutin(void*, long, void*);
+void spireset(void);
+ulong _tas(ulong*);
+void trapinit(void);
+void trapvec(void);
+void uartinstall(void);
+void uartspecial(int, int, Queue**, Queue**, int (*)(Queue*, int));
+void uartwait(void); /* debugging */
+void videoreset(void);
+void videotest(void);
+void wbflush(void);
+
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+ulong getcallerpc(void*);
+
+#define KADDR(a) ((void*)((ulong)(a)|KZERO))
+#define PADDR(a) ((((ulong)(a)&KSEGM)!=KSEG0)?(ulong)(a):((ulong)(a)&~KZERO))
+
+/* IBM bit field order */
+#define IBIT(b) ((ulong)1<<(31-(b)))
+#define SIBIT(n) ((ushort)1<<(15-(n)))
+
+/* compatibility with inf2.1 */
diff --git a/os/ipengine/io.h b/os/ipengine/io.h
new file mode 100644
index 00000000..30312c68
--- /dev/null
+++ b/os/ipengine/io.h
@@ -0,0 +1 @@
+#include "../mpc/800io.h"
diff --git a/os/ipengine/ipe b/os/ipengine/ipe
new file mode 100644
index 00000000..8e00c855
--- /dev/null
+++ b/os/ipengine/ipe
@@ -0,0 +1,109 @@
+# Bright Star Engineering ipEngine-1
+dev
+ root
+ cons archipe
+ env
+ mnt
+ pipe
+ prog
+ rtc
+ srv
+ dup
+ ssl
+ cap
+ sign
+
+ ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium netaux
+ ether netif netaux ethermedium
+ uart
+ flash
+# i2c i2c
+
+ ftl
+
+ fpga
+
+ip
+ il
+ tcp
+ udp
+# rudp
+# igmp
+ ipifc
+ icmp
+ icmp6
+ ipmux
+
+lib
+ interp
+ keyring
+ sec
+ mp
+ math
+ kern
+
+link
+ etherscc
+ ethermedium
+ flash28f320b3b
+
+mod
+ math
+ sys
+ keyring
+
+port
+ alarm
+ alloc
+ allocb
+ chan
+ dev
+ dial
+ dis
+ discall
+ exception
+ exportfs
+ inferno
+ latin1
+ nocache
+ nodynld
+ parse
+ pgrp
+ print
+ proc
+ qio
+ qlock
+ random
+ sysfile
+ taslock
+ xalloc
+
+code
+ int cflag = 0;
+ int consoleprint = 1;
+ int panicreset = 0;
+ int main_pool_pcnt = 50;
+ int heap_pool_pcnt = 50;
+ int image_pool_pcnt = 0;
+ void screeninit(void){}
+
+init
+ ipeinit
+
+root
+ /chan /
+ /dev /
+ /dis /
+ /env /
+ /fd /
+ /n /
+ /net /
+ /nvfs /
+ /prog /
+ /osinit.dis
+ /dis/lib/auth.dis
+ /dis/lib/ssl.dis
+ /n/local /
+ /n/remote /
+# authentication
+ /nvfs/default /usr/inferno/keyring/default
diff --git a/os/ipengine/main.c b/os/ipengine/main.c
new file mode 100644
index 00000000..cdd7ed58
--- /dev/null
+++ b/os/ipengine/main.c
@@ -0,0 +1,348 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "version.h"
+
+#define MAXCONF 32
+
+extern ulong kerndate;
+extern int cflag;
+int remotedebug;
+
+extern int main_pool_pcnt;
+extern int heap_pool_pcnt;
+extern int image_pool_pcnt;
+
+char *confname[MAXCONF];
+char *confval[MAXCONF];
+int nconf;
+
+void addconf(char *, char *);
+
+static void
+options(void)
+{
+ nconf = archconfval(confname, confval, sizeof(confname));
+}
+
+void
+doc(char *m)
+{
+ USED(m);
+ //iprint("%s...\n", m);
+}
+
+static void
+poolsizeinit(void)
+{
+ ulong nb;
+
+ nb = conf.npage*BY2PG;
+ poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
+ poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
+ poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
+}
+
+static void
+serialconsole(void)
+{
+ char *p;
+ int port, baud;
+
+ p = getconf("console");
+ if(p == nil)
+ p = "0";
+ if(p != nil && !remotedebug){
+ port = strtol(p, nil, 0);
+ baud = 9600;
+ p = getconf("baud");
+ if(p != nil){
+ baud = strtol(p, nil, 0);
+ if(baud < 9600)
+ baud = 9600;
+ }
+ uartspecial(port, baud, &kbdq, &printq, kbdcr2nl);
+ }
+}
+
+void
+main(void)
+{
+ machinit();
+ options();
+ archinit();
+ quotefmtinstall();
+ confinit();
+ cpminit();
+ xinit();
+ poolsizeinit();
+ trapinit();
+ mmuinit();
+ printinit();
+ uartinstall();
+ serialconsole();
+ doc("screeninit");
+ screeninit();
+ doc("kbdinit");
+ kbdinit();
+ doc("clockinit");
+ clockinit();
+ doc("procinit");
+ procinit();
+ cpuidprint();
+ doc("links");
+ links();
+ doc("chandevreset");
+ chandevreset();
+
+ eve = strdup("inferno");
+
+ print("\nInferno %s\n", VERSION);
+ print("Vita Nuova\n");
+ print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);
+
+ doc("userinit");
+ userinit();
+ doc("schedinit");
+ schedinit();
+}
+
+void
+machinit(void)
+{
+ int n;
+
+ n = m->machno;
+ memset(m, 0, sizeof(Mach));
+ m->machno = n;
+ m->mmask = 1<<m->machno;
+ m->iomem = KADDR(getimmr() & ~0xFFFF);
+ m->cputype = getpvr()>>16;
+ m->delayloop = 20000; /* initial estimate only; set by clockinit */
+ m->speed = 50; /* initial estimate only; set by archinit */
+}
+
+void
+init0(void)
+{
+ Osenv *o;
+ int i;
+ char buf[2*KNAMELEN];
+
+ up->nerrlab = 0;
+
+ spllo();
+
+ if(waserror())
+ panic("init0");
+ /*
+ * These are o.k. because rootinit is null.
+ * Then early kproc's will have a root and dot.
+ */
+ o = up->env;
+ o->pgrp->slash = namec("#/", Atodir, 0, 0);
+ cnameclose(o->pgrp->slash->name);
+ o->pgrp->slash->name = newcname("/");
+ o->pgrp->dot = cclone(o->pgrp->slash);
+
+ chandevinit();
+
+ if(!waserror()){
+ ksetenv("cputype", "power", 0);
+ snprint(buf, sizeof(buf), "power %s", conffile);
+ ksetenv("terminal", buf, 0);
+ poperror();
+ }
+ for(i = 0; i < nconf; i++)
+ if(confname[i][0] != '*'){
+ if(!waserror()){
+ ksetenv(confname[i], confval[i], 0);
+ poperror();
+ }
+ }
+
+ poperror();
+ disinit("/osinit.dis");
+}
+
+void
+userinit(void)
+{
+ Proc *p;
+ Osenv *o;
+
+ p = newproc();
+ o = p->env;
+
+ o->fgrp = newfgrp(nil);
+ o->pgrp = newpgrp();
+ o->egrp = newegrp();
+ kstrdup(&o->user, eve);
+
+ strcpy(p->text, "interp");
+
+ /*
+ * Kernel Stack
+ */
+ p->sched.pc = (ulong)init0;
+ p->sched.sp = (ulong)p->kstack+KSTACK;
+
+ ready(p);
+}
+
+Conf conf;
+
+void
+addconf(char *name, char *val)
+{
+ if(nconf >= MAXCONF)
+ return;
+ confname[nconf] = name;
+ confval[nconf] = val;
+ nconf++;
+}
+
+char*
+getconf(char *name)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++)
+ if(cistrcmp(confname[i], name) == 0)
+ return confval[i];
+ return 0;
+}
+
+void
+confinit(void)
+{
+ char *p;
+ int pcnt;
+
+ if(p = getconf("*kernelpercent"))
+ pcnt = 100 - strtol(p, 0, 0);
+ else
+ pcnt = 0;
+
+ conf.nscc = 4;
+ conf.smcuarts = (1<<1)|(1<<0); /* SMC2, SMC1 (usual console) */
+ conf.sccuarts = 0; /* SCC2 not available by default (it's Ether) */
+
+ archconfinit();
+
+ conf.npage = conf.npage0 + conf.npage1;
+ if(pcnt < 10)
+ pcnt = 70;
+ conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG;
+
+ conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+ conf.nmach = MAXMACH;
+}
+
+void
+exit(int ispanic)
+{
+ up = 0;
+ toggleled(3);
+ spllo();
+ print("cpu %d exiting\n", m->machno);
+
+ /* Shutdown running devices */
+ chandevshutdown();
+
+ delay(1000);
+ splhi();
+ if(ispanic)
+ for(;;);
+ archreboot();
+}
+
+void
+reboot(void)
+{
+ exit(0);
+}
+
+void
+halt(void)
+{
+ print("cpu halted\n");
+ microdelay(1000);
+ for(;;)
+ ;
+}
+
+int
+isaconfig(char *class, int ctlrno, ISAConf *isa)
+{
+ char cc[KNAMELEN], *p;
+ int i;
+
+ snprint(cc, sizeof cc, "%s%d", class, ctlrno);
+ p = getconf(cc);
+ if(p == nil)
+ return 0;
+
+ isa->nopt = tokenize(p, isa->opt, NISAOPT);
+ for(i = 0; i < isa->nopt; i++){
+ p = isa->opt[i];
+ if(cistrncmp(p, "type=", 5) == 0)
+ isa->type = p + 5;
+ else if(cistrncmp(p, "port=", 5) == 0)
+ isa->port = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "irq=", 4) == 0)
+ isa->irq = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "mem=", 4) == 0)
+ isa->mem = strtoul(p+4, &p, 0);
+ else if(cistrncmp(p, "size=", 5) == 0)
+ isa->size = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "freq=", 5) == 0)
+ isa->freq = strtoul(p+5, &p, 0);
+ else if(cistrncmp(p, "dma=", 4) == 0)
+ isa->dma = strtoul(p+4, &p, 0);
+ }
+ return 1;
+}
+
+/*
+ * Save the mach dependent part of the process state.
+ */
+void
+procsave(Proc*)
+{
+}
+
+void
+uartputs(char *s, int n)
+{
+// screenputs(buf, n);
+ putstrn(s, n);
+ uartwait();
+}
+
+/* stubs */
+void
+setfsr(ulong)
+{
+}
+
+ulong
+getfsr()
+{
+ return 0;
+}
+
+void
+setfcr(ulong)
+{
+}
+
+ulong
+getfcr()
+{
+ return 0;
+}
diff --git a/os/ipengine/mem.h b/os/ipengine/mem.h
new file mode 100644
index 00000000..4934fc50
--- /dev/null
+++ b/os/ipengine/mem.h
@@ -0,0 +1,156 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+/*
+ * Sizes
+ */
+
+#define BI2BY 8 /* bits per byte */
+#define BI2WD 32 /* bits per word */
+#define BY2WD 4 /* bytes per word */
+#define BY2V 8 /* bytes per double word */
+#define BY2PG 4096 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+#define CACHELINELOG 4
+#define CACHELINESZ (1<<CACHELINELOG)
+
+#define MAXMACH 1 /* max # cpus system can run */
+#define MACHSIZE BY2PG
+
+/*
+ * Time
+ */
+#define HZ 100 /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */
+#define MHz 1000000
+
+/*
+ * MSR bits
+ */
+
+#define POW 0x40000 /* enable power mgmt */
+#define TGPR 0x20000 /* GPR0-3 remapped; 603/603e specific */
+#define ILE 0x10000 /* interrupts little endian */
+#define EE 0x08000 /* enable external/decrementer interrupts */
+#define PR 0x04000 /* =1, user mode */
+#define FPE 0x02000 /* enable floating point */
+#define ME 0x01000 /* enable machine check exceptions */
+#define FE0 0x00800
+#define SE 0x00400 /* single-step trace */
+#define BE 0x00200 /* branch trace */
+#define FE1 0x00100
+#define MSR_IP 0x00040 /* =0, vector to nnnnn; =1, vector to FFFnnnnn */
+#define IR 0x00020 /* enable instruction address translation */
+#define DR 0x00010 /* enable data address translation */
+#define RI 0x00002 /* exception is recoverable */
+#define LE 0x00001 /* little endian mode */
+
+#define KMSR (ME|FE0|FE1|FPE)
+#define UMSR (KMSR|PR|EE|IR|DR)
+
+/*
+ * Magic registers
+ */
+
+#define MACH 30 /* R30 is m-> */
+#define USER 29 /* R29 is up-> */
+#define IOMEMR 28 /* R28 will be iomem-> */
+
+/*
+ * Fundamental addresses
+ */
+
+#define UREGSIZE ((8+32)*4)
+
+/*
+ * MMU
+ */
+
+/* L1 table entry and Mx_TWC flags */
+#define PTEVALID (1<<0)
+#define PTEWT (1<<1) /* write through */
+#define PTE4K (0<<2)
+#define PTE512K (1<<2)
+#define PTE8MB (3<<2)
+#define PTEG (1<<4) /* guarded */
+
+/* L2 table entry and Mx_RPN flags (also PTEVALID) */
+#define PTECI (1<<1) /* cache inhibit */
+#define PTESH (1<<2) /* page is shared; ASID ignored */
+#define PTELPS (1<<3) /* large page size */
+#define PTEWRITE 0x9F0
+
+/* TLB and MxEPN flag */
+#define TLBVALID (1<<9)
+
+/*
+ * Address spaces
+ */
+
+#define KUSEG 0x00000000
+#define KSEG0 0x20000000
+#define KSEGM 0xE0000000 /* mask to check which seg */
+
+#define KZERO KSEG0 /* base of kernel address space */
+#define KTZERO (KZERO+0x3000) /* first address in kernel text */
+#define KSTACK 8192 /* Size of kernel stack */
+
+/*
+ * Exception codes (trap vectors)
+ */
+#define CRESET 0x01
+#define CMCHECK 0x02
+#define CDSI 0x03
+#define CISI 0x04
+#define CEI 0x05
+#define CALIGN 0x06
+#define CPROG 0x07
+#define CFPU 0x08
+#define CDEC 0x09
+#define CSYSCALL 0x0C
+#define CTRACE 0x0D
+#define CFPA 0x0E
+/* rest are power-implementation dependent (8xx) */
+#define CEMU 0x10
+#define CIMISS 0x11
+#define CDMISS 0x12
+#define CITLBE 0x13
+#define CDTLBE 0x14
+#define CDBREAK 0x1C
+#define CIBREAK 0x1D
+#define CPBREAK 0x1E
+#define CDPORT 0x1F
+
+/*
+ * MPC8xx physical addresses (ipEngine)
+ */
+#define PHYSDRAM 0x00000000
+#define PHYSIMM 0xFF000000
+#define PHYSFLASH 0xFE000000
+#define FPGAMEM 0xFC000000
+
+/* extra addresses on ipEngine-1 */
+#define FPGACR 0xFF010000 /* FPGA control */
+#define CLOCKCR 0xFF020000 /* Clock synthesiser register */
+
+/* remaining ones are our choice */
+#define PHYSPCMCIA 0x40000000
+#define PCMCIALEN (8*MB) /* chosen to allow mapping by single TLB entry */
+#define ISAIO PHYSPCMCIA /* for inb.s */
+
+/*
+ * MPC8xx dual-ported CPM memory physical addresses
+ */
+#define PHYSDPRAM (PHYSIMM+0x2000)
+#define DPLEN1 0x200
+#define DPLEN2 0x400
+#define DPLEN3 0x800
+#define DPBASE (PHYSDPRAM+DPLEN1)
+
+#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */
diff --git a/os/ipengine/mkfile b/os/ipengine/mkfile
new file mode 100644
index 00000000..ca6d6373
--- /dev/null
+++ b/os/ipengine/mkfile
@@ -0,0 +1,105 @@
+SYSTARG=Inferno
+OBJTYPE=power
+<../../mkconfig
+
+#Configurable parameters
+
+CONF=ipe #default configuration
+CONFLIST=ipe
+KZERO=0x20003020
+
+SYSTARG=$OSTARG
+OBJTYPE=power
+INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed
+#INSTALLDIR=/$OBJTYPE
+
+#end configurable parameters
+
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system
+
+<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $ETHERS, $VGAS, $PORT, $MISC, $LIBS, $OTHERS
+
+OBJ=\
+ l.$O\
+ tlb.$O\
+ nofp.$O\
+ clock.$O\
+ cpm.$O\
+ faultpower.$O\
+ fpi.$O\
+ fpimem.$O\
+ fpipower.$O\
+ kbd.$O\
+ main.$O\
+ mmu.$O\
+ rmap.$O\
+ trap.$O\
+ $CONF.root.$O\
+ $IP\
+ $DEVS\
+ $ETHERS\
+ $LINKS\
+ $VGAS\
+ $PORT\
+ $MISC\
+ $OTHERS\
+
+LIBNAMES=${LIBS:%=lib%.a}
+
+HFILES=\
+ mem.h\
+ dat.h\
+ fns.h\
+ io.h\
+ ../mpc/800io.h\
+
+CFLAGS=-wFV -I. -I../mpc -I../port -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp
+KERNDATE=`{$NDATE}
+
+#default:V: i$CONF.sq
+default:V: i$CONF
+
+i$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES
+ $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c
+ $LD -o $target -T$KZERO -l -R4 $OBJ $CONF.$O $LIBFILES
+ $KSIZE $target
+
+i$CONF.sq: i$CONF
+ sqz -w i$CONF >$target
+
+install:V: i$CONF # i$CONF.sq
+ cp i$CONF $INSTALLDIR/i$CONF
+ #cp i$CONF.sq $INSTALLDIR/i$CONF.sq
+
+uninstall:V:
+ rm -f $ROOT/$OBJDIR/bin/i$CONF
+ rm -f $ROOT/$OBJDIR/bin/i$CONF.sq
+
+<../port/portmkfile
+
+%.$O: ../mpc/%.c
+ $CC $CFLAGS -I. ../mpc/$stem.c
+
+%.$O: ../mpc/%.s
+ $AS -I. -I../mpc ../mpc/$stem.s
+
+../init/$INIT.dis: ../init/$INIT.b
+ cd ../init; mk $INIT.dis
+
+clock.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
+devether.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
+faultpower.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
+main.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
+trap.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
+
+devether.$O $ETHERS: ../mpc/etherif.h ../port/netif.h
+archipe.$O: ../mpc/screen.h archipe.h
+screen.$O: ../mpc/screen.h
+
+$IP devip.$O: ../ip/ip.h
+
+devboot.$O: devboot.c
+ $CC $CFLAGS devboot.c
+
+devuart.$O: ../mpc/devuart.c
+ $CC $CFLAGS ../mpc/devuart.c
diff --git a/os/ipengine/mmu.c b/os/ipengine/mmu.c
new file mode 100644
index 00000000..c9cd758b
--- /dev/null
+++ b/os/ipengine/mmu.c
@@ -0,0 +1,20 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+void
+mmuinit(void)
+{
+ /* the l.s initial TLB settings do all that's required */
+}
+
+int
+segflush(void *a, ulong n)
+{
+ /* flush dcache then invalidate icache */
+ dcflush(a, n);
+ icflush(a, n);
+ return 0;
+}
diff --git a/os/ipengine/tlb.s b/os/ipengine/tlb.s
new file mode 100644
index 00000000..c7451823
--- /dev/null
+++ b/os/ipengine/tlb.s
@@ -0,0 +1,21 @@
+#include "mem.h"
+#define MB (1024*1024)
+
+/*
+ * TLB prototype entries, loaded once-for-all at startup,
+ * remaining unchanged thereafter.
+ * Limit the table to at most 8 entries to ensure
+ * it works on the 823 (other 8xx processors allow up to 32 TLB entries).
+ */
+#define TLBE(epn,rpn,twc) WORD $(epn); WORD $(twc); WORD $(rpn)
+
+TEXT tlbtab(SB), $-4
+
+ /* epn, rpn, twc */
+ TLBE(KZERO|PHYSDRAM|TLBVALID, PHYSDRAM|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEVALID) /* DRAM, 8M */
+ TLBE(KZERO|(PHYSDRAM+8*MB)|TLBVALID, (PHYSDRAM+8*MB)|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEVALID) /* DRAM, 8M */
+ TLBE(KZERO|PHYSIMM|TLBVALID, PHYSIMM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE512K|PTEVALID) /* IMMR, 512K (includes FPGA control and clock synth) */
+ TLBE(KZERO|PHYSFLASH|TLBVALID, PHYSFLASH|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* Flash, 8M */
+ TLBE(KZERO|FPGAMEM|TLBVALID, FPGAMEM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEG|PTEVALID) /* FPGA mem, 8M */
+TEXT tlbtabe(SB), $-4
+ RETURN