summaryrefslogtreecommitdiff
path: root/os/js
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/js
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/js')
-rw-r--r--os/js/README10
-rw-r--r--os/js/audio.h9
-rw-r--r--os/js/clock.c104
-rw-r--r--os/js/cs4231.h20
-rw-r--r--os/js/dat.h163
-rw-r--r--os/js/devcs4231.c1186
-rw-r--r--os/js/devrtc.c413
-rw-r--r--os/js/fns.h110
-rw-r--r--os/js/fsv.c198
-rw-r--r--os/js/io.h224
-rw-r--r--os/js/iob.c13
-rw-r--r--os/js/js104
-rw-r--r--os/js/kbd.c482
-rw-r--r--os/js/l.s560
-rw-r--r--os/js/main.c564
-rw-r--r--os/js/mem.h149
-rw-r--r--os/js/mkfile77
-rw-r--r--os/js/mmu.c252
-rw-r--r--os/js/ns16552.h81
-rw-r--r--os/js/rom.c103
-rw-r--r--os/js/rom.h57
-rw-r--r--os/js/screen.c483
-rw-r--r--os/js/screen.h49
-rw-r--r--os/js/softcursor.h13
-rw-r--r--os/js/superio.c216
-rw-r--r--os/js/trap.c472
-rw-r--r--os/js/ureg.h45
27 files changed, 6157 insertions, 0 deletions
diff --git a/os/js/README b/os/js/README
new file mode 100644
index 00000000..1bef576f
--- /dev/null
+++ b/os/js/README
@@ -0,0 +1,10 @@
+This port was done in a matter of days by Tad Hunt, Eric van Hensbergen
+and others when they were in the Lucent Inferno Business Unit, with a little
+bit of advice from Vita Nuova about various Sparc details (since one
+of us had done ports to micro-Sparcs). It is included mainly to
+allow another micro-Sparc port to be developed. Javastation-1s
+can still be found (but we haven't got one). A good cheap reference
+board would be good to have.
+
+The Javastation running Java and JavaOS was sluggish; running Limbo
+under Inferno it was actually quite snappy!
diff --git a/os/js/audio.h b/os/js/audio.h
new file mode 100644
index 00000000..1d88aa1b
--- /dev/null
+++ b/os/js/audio.h
@@ -0,0 +1,9 @@
+enum
+{
+ Bufsize = 16*1024, /* 92 ms each */
+ Nbuf = 16, /* 1.5 seconds total */
+ Rdma = 666, /* XXX - Tad: fixme */
+ Wdma = 666, /* XXX - Tad: fixme */
+};
+
+#define UNCACHED(type, v) (type*)((ulong)(v))
diff --git a/os/js/clock.c b/os/js/clock.c
new file mode 100644
index 00000000..581ee441
--- /dev/null
+++ b/os/js/clock.c
@@ -0,0 +1,104 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+#include "ureg.h"
+
+typedef struct Clock0link Clock0link;
+typedef struct Clock0link {
+ void (*clock)(void);
+ Clock0link* link;
+} Clock0link;
+
+static Clock0link *clock0link;
+static Lock clock0lock;
+
+void
+microdelay(int ms)
+{
+ int i;
+
+ ms *= 13334; /* experimentally indetermined */
+ for(i=0; i<ms; i++)
+ ;
+}
+
+typedef struct Ctr Ctr;
+struct Ctr
+{
+ ulong lim;
+ ulong ctr;
+ ulong limnr; /* non-resetting */
+ ulong ctl;
+};
+Ctr *ctr;
+
+void
+clockinit(void)
+{
+ KMap *k;
+
+ putphys(TIMECONFIG, 0); /* it's a processor counter */
+ k = kmappa(CLOCK, PTENOCACHE|PTEIO);
+ ctr = (Ctr*)VA(k);
+ ctr->lim = (CLOCKFREQ/HZ)<<10;
+}
+
+void
+clock(Ureg *ur)
+{
+ Clock0link *lp;
+ ulong i;
+
+ USED(ur);
+
+ i = ctr->lim; /* clear interrupt */
+ USED(i);
+ /* is this needed? page 6-43 801-3137-10 suggests so */
+ ctr->lim = (CLOCKFREQ/HZ)<<10;
+
+ m->ticks++;
+
+ if(up)
+ up->pc = ur->pc;
+
+ checkalarms();
+
+ lock(&clock0lock);
+ for(lp = clock0link; lp; lp = lp->link)
+ lp->clock();
+ unlock(&clock0lock);
+
+ if(up && up->state == Running) {
+ if(anyready())
+ sched();
+ }
+}
+
+Timer*
+addclock0link(void (*clockfunc)(void), int)
+{
+ Clock0link *lp;
+
+ if((lp = malloc(sizeof(Clock0link))) == 0){
+ print("addclock0link: too many links\n");
+ return nil;
+ }
+ ilock(&clock0lock);
+ lp->clock = clockfunc;
+ lp->link = clock0link;
+ clock0link = lp;
+ iunlock(&clock0lock);
+ return nil;
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ if(hz)
+ *hz = HZ;
+ return m->ticks;
+}
diff --git a/os/js/cs4231.h b/os/js/cs4231.h
new file mode 100644
index 00000000..daeda1b8
--- /dev/null
+++ b/os/js/cs4231.h
@@ -0,0 +1,20 @@
+#define IN(x) inb(csdev.port+(x))
+#define OUT(x,v) outb(csdev.port+(x),(v))
+
+void
+cs4231install(void)
+{
+ KMap *k;
+ static int installed=0;
+
+ if(installed)
+ return;
+
+ k = kmappa(AUDIO_PHYS_PAGE, PTEIO|PTENOCACHE);
+
+ csdev.port = VA(k)+AUDIO_INDEX_OFFSET;
+ dmasize(Wdma, 8);
+ dmasize(Rdma, 8);
+
+ installed=1;
+}
diff --git a/os/js/dat.h b/os/js/dat.h
new file mode 100644
index 00000000..e1691f4e
--- /dev/null
+++ b/os/js/dat.h
@@ -0,0 +1,163 @@
+typedef struct Conf Conf;
+typedef struct FPenv FPenv;
+typedef struct FPU FPU;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Mach Mach;
+typedef struct Ureg Ureg;
+typedef struct Lance Lance;
+typedef struct Lancemem Lancemem;
+typedef struct Etherpkt Etherpkt;
+typedef struct Lancepkt Lancepkt;
+
+typedef ulong Instr;
+
+struct Conf
+{
+ int nmach; /* processors */
+ int nproc; /* processes */
+ ulong monitor; /* graphics monitor id; 0 for none */
+ char ss2; /* is a sparcstation 2 */
+ char ss2cachebug; /* has sparcstation2 cache bug */
+ int ncontext; /* in mmu */
+ int vacsize; /* size of virtual address cache, in bytes */
+ int vaclinesize; /* size of cache line */
+ ulong npage0; /* total physical pages of memory, bank 0 */
+ ulong npage1; /* total physical pages of memory, bank 1 */
+ ulong base0; /* base of bank 0 */
+ ulong base1; /* base of bank 1 */
+ ulong ialloc; /* max interrupt time allocation in bytes */
+ ulong npage; /* total physical pages of memory */
+ int copymode; /* 0 is copy on write, 1 is copy on reference */
+ ulong ipif; /* Ip protocol interfaces */
+ ulong ip; /* Ip conversations per interface */
+ ulong arp; /* Arp table size */
+ ulong frag; /* Ip fragment assemble queue size */
+};
+
+
+/*
+ * FPenv.status
+ */
+enum
+{
+ FPINIT,
+ FPACTIVE,
+ FPINACTIVE,
+};
+
+struct FPenv
+{
+ ulong status;
+ ulong pad;
+};
+
+/*
+ * This structure must agree with fpsave and fprestore asm routines
+ */
+struct FPU
+{
+
+ double regs[17]; /* floating point registers */
+ FPenv env;
+};
+
+/*
+ * machine dependent definitions used by ../port/dat.h
+ */
+
+struct Label
+{
+ ulong sp;
+ ulong pc;
+};
+
+struct Lock
+{
+ ulong key;
+ ulong pc;
+ ulong sr;
+ int pri;
+};
+
+#include "../port/portdat.h"
+
+/*
+ * machine dependent definitions not used by ../port/dat.h
+ */
+
+struct Mach
+{
+ ulong ticks; /* of the clock since boot time */
+ int machno; /* physical id of this processor */
+ Proc *proc; /* current process on this processor */
+ Label sched; /* scheduler wakeup */
+ Lock alarmlock; /* access to alarm list */
+ void *alarm; /* alarms bound to this clock */
+ ulong *contexts; /* hardware context table */
+ ulong *ctx; /* the context */
+ int fptrap; /* FP trap occurred while unsave */
+
+ int nrdy;
+
+ int stack[1];
+};
+
+/*
+ * XXX - Eric: It just works....
+ */
+
+/*
+ * LANCE CSR3 (bus control bits)
+ */
+#define BSWP 0x4
+#define ACON 0x2
+#define BCON 0x1
+
+struct Lancepkt
+{
+ uchar d[6];
+ uchar s[6];
+ uchar type[2];
+ uchar data[1500];
+ uchar crc[4];
+};
+
+/*
+ * system dependent lance stuff
+ * filled by lancesetup()
+ */
+struct Lance
+{
+ ushort lognrrb; /* log2 number of receive ring buffers */
+ ushort logntrb; /* log2 number of xmit ring buffers */
+ ushort nrrb; /* number of receive ring buffers */
+ ushort ntrb; /* number of xmit ring buffers */
+ ushort *rap; /* lance address register */
+ ushort *rdp; /* lance data register */
+ ushort busctl; /* bus control bits */
+ uchar ea[6]; /* our ether addr */
+ int sep; /* separation between shorts in lance ram
+ as seen by host */
+ ushort *lanceram; /* start of lance ram as seen by host */
+ Lancemem *lm; /* start of lance ram as seen by lance */
+ Lancepkt *rp; /* receive buffers (host address) */
+ Lancepkt *tp; /* transmit buffers (host address) */
+ Lancepkt *lrp; /* receive buffers (lance address) */
+ Lancepkt *ltp; /* transmit buffers (lance address) */
+};
+
+/*
+ * Fake kmap
+ */
+typedef void KMap;
+#define VA(k) ((ulong)(k))
+#define kmap(p) (KMap*)((p)->pa|KZERO)
+#define kunmap(k)
+#define MACHP(n) (n==0? &mach0 : *(Mach**)0)
+
+extern Mach *m;
+extern Proc *up;
+extern Mach mach0;
+
+#define swcursor 1
diff --git a/os/js/devcs4231.c b/os/js/devcs4231.c
new file mode 100644
index 00000000..2e02c462
--- /dev/null
+++ b/os/js/devcs4231.c
@@ -0,0 +1,1186 @@
+/*
+ * preliminary Crystal CS4231 audio driver,
+ * initially based on SB16 driver, and therefore needs work.
+ * for instance, i suspect the linked-list buffering is excessive:
+ * a rolling buffering scheme or double buffering should be fine,
+ * and possibly simpler.
+ *
+ * To do:
+ * stop/start?
+ * is the linux mix_cvt ideal?
+ * ad1845 differences
+ * adpcm freezing
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "devtab.h"
+#include "io.h"
+#include "audio.h"
+
+#define DPRINT if(chatty)print
+
+typedef struct AChan AChan;
+typedef struct AQueue AQueue;
+typedef struct Buf Buf;
+typedef struct Vol Vol;
+
+enum
+{
+ Qdir = 0,
+ Qaudio,
+ Qaudioctl,
+
+ Fmono = 1,
+ Fin = 2,
+ Fout = 4,
+
+ Vaudio = 0,
+ Vaux1,
+ Vaux2,
+ Vline,
+ Vmic,
+ Vmono,
+ Vspeed,
+ Vchans,
+ Vbits,
+ Nvol,
+
+ Speed = 22050,
+ Ncmd = 50, /* max volume command words */
+};
+
+enum {
+ Paddr= 0,
+ TRD= 1<<5,
+ MCE= 1<<6,
+ Pdata= 1,
+ Pstatus= 2,
+ Pio= 3,
+
+ LeftADC= 0,
+ MGE= 1<<5,
+ ISline= 0<<6,
+ ISaux1= 1<<6,
+ ISmic= 2<<6,
+ ISloop= 3<<6,
+ ISmask= 3<<6,
+ RightADC= 1,
+ LeftAux1= 2,
+ Mute= 1<<7,
+ RightAux1= 3,
+ LeftAux2= 4,
+ RightAux2= 5,
+ LeftDAC= 6,
+ RightDAC= 7,
+ OutFormat= 8,
+ Stereo= 1<<4,
+ Linear8= 0<<5,
+ uLaw= 1<<5,
+ Linear16= 2<<5,
+ aLaw= 3<<5,
+ ADPCM= 5<<5,
+ Fmask= 7<<5,
+ Config= 9,
+ PEN= 1<<0,
+ CEN= 1<<1,
+ Nocal= 0<<3,
+ Convcal= 1<<3,
+ DACcal= 2<<3,
+ Fullcal= 3<<3,
+ PinControl= 10,
+ IEN= 1<<1,
+ DEN= 1<<3,
+ Xctl0= 1<<6,
+ Xctl1= 1<<7,
+ Status= 11,
+ ACI= 1<<5,
+ Mode= 12,
+ Mode2= 1<<6,
+ Loopback= 13,
+ LBE= 1<<0,
+ PlayCount1= 14,
+ PlayCount0= 15,
+ Feature1= 16,
+ PMCE= 1<<4,
+ CMCE= 1<<5,
+ Feature2= 17,
+ LeftLine= 18,
+ RightLine= 19,
+ Timer0= 20,
+ Timer1= 21,
+ Feature3= 23,
+ FeatureStatus= 24,
+ PI= 1<<4, /* playback interrupt */
+ CI= 1<<5, /* capture interrupt */
+ TI= 1<<6, /* timer interrupt */
+ ChipID= 25,
+ MonoCtl= 26,
+ MBY= 1<<5, /* mono bypass */
+ MOM= 1<<6,
+ InFormat= 28,
+ RecCount1= 30,
+ RecCount0= 31,
+};
+
+#define csdelay() microdelay(1)
+
+static Dirtab audiodir[] =
+{
+ "audio", {Qaudio}, 0, 0666,
+ "audioctl", {Qaudioctl}, 0, 0666,
+};
+#define NPORT (sizeof audiodir/sizeof(Dirtab))
+
+struct Buf
+{
+ uchar* virt;
+ int count;
+ Buf* next;
+};
+struct AQueue
+{
+ Lock;
+ Buf* first;
+ Buf* last;
+};
+struct AChan
+{
+ QLock;
+ Rendez r;
+ Buf buf[Nbuf]; /* buffers and queues */
+ AQueue empty;
+ AQueue full;
+ Buf* current;
+ Buf* filling;
+ int flushing;
+};
+static struct
+{
+ QLock;
+ int opened;
+ int bufinit; /* boolean if buffers allocated */
+ int rivol[Nvol]; /* right/left input/output volumes */
+ int livol[Nvol];
+ int rovol[Nvol];
+ int lovol[Nvol];
+ int loopback;
+
+ AChan in;
+ AChan out;
+} audio;
+
+static char* encname(int);
+
+static int dacload(int, int);
+static int auxload(int, int);
+static int adcload(int, int);
+static int monoload(int, int);
+
+struct Vol
+{
+ char* name;
+ int flag;
+ int ilval; /* initial values */
+ int irval;
+ int reg;
+ int (*load)(int, int);
+};
+
+static Vol volumes[] = {
+[Vaudio] {"audio", Fout, 50, 50, LeftDAC, dacload},
+[Vaux1] {"aux1", Fin, 0, 0, LeftAux1, auxload},
+[Vaux2] {"aux2", Fin, 0, 0, LeftAux2, auxload},
+[Vline] {"line", Fin, 0, 0, LeftLine, auxload},
+[Vmono] {"mono", Fin|Fout|Fmono, 0, 0, MonoCtl, monoload},
+[Vmic] {"mic", Fin, 0, 0, LeftADC, adcload},
+
+[Vspeed] {"rate", Fin|Fout|Fmono, Speed, Speed,},
+[Vchans] {"chans", Fin|Fout|Fmono, 2, 2,},
+[Vbits] {"bits", Fin|Fout|Fmono, 8, 8,},
+ {0},
+};
+
+static struct
+{
+ Lock;
+ int port;
+ int irq;
+ uchar sticky;
+ uchar regs[32];
+} csdev;
+
+static void contininput(void);
+static void continoutput(void);
+
+static char Evolume[] = "illegal audioctl specifier";
+
+static int chatty;
+
+#include "cs4231.h"
+
+static int
+xin(int r)
+{
+ int i;
+
+ for(i=100; --i >= 0 && IN(Paddr) & 0x80;)
+ csdelay();
+ OUT(Paddr, r|csdev.sticky);
+ csdelay();
+ return IN(Pdata);
+}
+
+static void
+xout(int r, int v)
+{
+ int i;
+
+ for(i=100; --i >= 0 && IN(Paddr) & 0x80;)
+ csdelay();
+ OUT(Paddr, r|csdev.sticky);
+ csdelay();
+ OUT(Pdata, v);
+ //csdelay();
+}
+
+static void
+speaker(int on)
+{
+ int s;
+
+ s = xin(PinControl);
+ if(on)
+ s |= Xctl0;
+ else
+ s &= ~Xctl0;
+ xout(PinControl, s);
+}
+
+static Buf*
+getbuf(AQueue *q)
+{
+ Buf *b;
+
+ ilock(q);
+ b = q->first;
+ if(b)
+ q->first = b->next;
+ iunlock(q);
+
+ return b;
+}
+
+static void
+putbuf(AQueue *q, Buf *b)
+{
+ ilock(q);
+ b->next = 0;
+ if(q->first)
+ q->last->next = b;
+ else
+ q->first = b;
+ q->last = b;
+ iunlock(q);
+}
+
+static void
+achanreset(AChan *ac)
+{
+ int i;
+
+ ac->filling = 0;
+ ac->flushing = 0;
+ ac->current = 0;
+ ac->empty.first = 0;
+ ac->empty.last = 0;
+ ac->full.first = 0;
+ ac->full.last = 0;
+ for(i=0; i<Nbuf; i++){
+ ac->buf[i].count = 0;
+ putbuf(&ac->empty, &ac->buf[i]);
+ }
+}
+
+static void
+startoutput(void)
+{
+ ilock(&csdev);
+ if(audio.out.current == 0)
+ continoutput();
+ iunlock(&csdev);
+}
+
+static void
+continoutput(void)
+{
+ Buf *b;
+ int f;
+ ulong n;
+
+ b = getbuf(&audio.out.full);
+ audio.out.current = b;
+ //xout(Config, xin(Config)&~PEN);
+ if(b){
+ n = b->count;
+ dmasetup(Wdma, b->virt, n, 0);
+ f = xin(OutFormat);
+ if((f & Fmask) == ADPCM)
+ n >>= 2;
+ else{
+ if((f & Fmask) == Linear16)
+ n >>= 1;
+ if(f & Stereo)
+ n >>= 1;
+ }
+ n--;
+ xout(PlayCount0, n);
+ xout(PlayCount1, n>>8);
+ xout(Config, xin(Config)|PEN);
+ DPRINT("cs: out %d\n", n);
+ } else
+ xout(Config, xin(Config)&~PEN);
+}
+
+static void
+startinput(void)
+{
+ ilock(&csdev);
+ if(audio.in.current == 0)
+ contininput();
+ iunlock(&csdev);
+}
+
+static void
+contininput(void)
+{
+ Buf *b;
+ int f;
+ ulong n;
+
+ xout(Config, xin(Config)&~CEN);
+ if(!audio.opened || audio.in.flushing){
+ return;
+ }
+ b = getbuf(&audio.in.empty);
+ audio.in.current = b;
+ if(b){
+ n = Bufsize;
+ dmasetup(Rdma, b->virt, Bufsize, 1);
+ f = xin(InFormat);
+ if((f & Fmask) == ADPCM)
+ n >>= 2;
+ else{
+ if((f & Fmask) == Linear16)
+ n >>= 1;
+ if(f & Stereo)
+ n >>= 1;
+ }
+ n--;
+ xout(RecCount0, n);
+ xout(RecCount1, n>>8);
+ xout(Config, xin(Config)|CEN);
+ DPRINT("cs: in %d\n", n);
+ }
+}
+
+static void
+cswait(void)
+{
+ int i;
+
+ for(i=50; --i >= 0 && IN(Paddr) & 0x80;)
+ microdelay(2000);
+ if(i < 0)
+ print("cswait1\n");
+ for(i=1000; --i >= 0 && (xin(Status) & ACI) == 0;)
+ csdelay();
+ for(i=1000; --i >= 0 && xin(Status) & ACI;)
+ microdelay(2000);
+ /* could give error(Eio) if i < 0 */
+ if(i < 0)
+ print("cswait2\n");
+}
+
+static int
+csspeed(int freq)
+{
+ int i;
+ static int freqtab[] = { /* p. 33 CFS2-CFS0 */
+ /* xtal1 xtal2 */
+ 8000, 5510,
+ 16000, 11025,
+ 27420, 18900,
+ 32000, 22050,
+ 0, 37800,
+ 0, 44100,
+ 48000, 33075,
+ 9600, 6620,
+ };
+ for(i=0; i<16; i++)
+ if(freqtab[i] == freq){
+ xout(OutFormat, (xin(OutFormat)&~0xF) | i);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+csformat(int r, int flag, int form, int *vec)
+{
+ int v;
+
+ if(form == Linear8){
+ if(vec[Vbits] == 16)
+ form = Linear16;
+ else if(vec[Vbits] == 4)
+ form = ADPCM;
+ }
+ if(vec[Vchans] == 2)
+ form |= Stereo;
+ DPRINT("csformat(%x,%x,%x)\n", r, flag, form);
+ if((xin(r)&0xF0) != form){
+ v = xin(Feature1);
+ xout(Feature1, v|flag);
+ xout(r, (xin(r)&~0xF0)|form);
+ xout(Feature1, v);
+ }
+ csdev.regs[r] = form;
+}
+
+static void
+cs4231intr(Ureg*, void*)
+{
+ int ir, s;
+ Buf *b;
+
+ lock(&csdev);
+ csdev.sticky |= TRD;
+ ir = IN(Pstatus);
+ s = xin(FeatureStatus);
+ if(s & PI){
+ b = audio.out.current;
+ audio.out.current = 0;
+ dmaend(Wdma);
+ continoutput();
+ if(b)
+ putbuf(&audio.out.empty, b);
+ wakeup(&audio.out.r);
+ }
+ if(s & CI){
+ b = audio.in.current;
+ audio.in.current = 0;
+ dmaend(Rdma);
+ contininput();
+ if(b){
+ b->count = Bufsize;
+ putbuf(&audio.in.full, b);
+ }
+ wakeup(&audio.in.r);
+ }
+ OUT(Pstatus, 0);
+ csdev.sticky &= ~TRD;
+ unlock(&csdev);
+ if(s & 0xF)
+ DPRINT("audiointr: #%x\n", s);
+}
+
+static int
+anybuf(void *p)
+{
+ return ((AChan*)p)->empty.first != 0;
+}
+
+static int
+anyinput(void *p)
+{
+ return ((AChan*)p)->full.first != 0;
+}
+
+static int
+outcomplete(void *p)
+{
+ return ((AChan*)p)->full.first == 0 && ((AChan*)p)->current==0;
+}
+
+static int
+incomplete(void *p)
+{
+ return ((AChan*)p)->current == 0;
+}
+
+static void
+acbufinit(AChan *ac)
+{
+ int i;
+ void *p;
+
+ for(i=0; i<Nbuf; i++) {
+ //p = xspanalloc(Bufsize, CACHELINESZ, 64*1024);
+ //dcflush(p, Bufsize);
+ p = xalloc(Bufsize);
+ ac->buf[i].virt = UNCACHED(uchar, p);
+ }
+}
+
+static void
+setempty(void)
+{
+ ilock(&csdev);
+ achanreset(&audio.in);
+ achanreset(&audio.out);
+ iunlock(&csdev);
+}
+
+void
+cs4231reset(void)
+{
+}
+
+static char mix_cvt[101] = {
+ 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
+ 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
+ 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
+ 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
+ 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,
+ 100
+};
+
+static int
+dacload(int r, int v)
+{
+ USED(r);
+ DPRINT("dacload(%x,%d)\n", r, v);
+ if(v == 0)
+ return Mute;
+ return 63-((v*63)/100);
+}
+
+static int
+monoload(int r, int v)
+{
+ DPRINT("monoload(%x,%d)\n", r, v);
+ if(v == 0)
+ return r|Mute;
+ return (r&~(Mute|MBY))|(15-((v*15)/100));
+}
+
+static int
+auxload(int r, int v)
+{
+ DPRINT("auxload(%x,%d)\n", r, v);
+ USED(r);
+ if(v == 0)
+ return Mute;
+ return 31-(v*31)/100;
+}
+
+static int
+adcload(int r, int v)
+{
+ DPRINT("adcload(%x,%d)\n", r, v);
+ return (r&~0xF)|((v*15)/100)|MGE;
+}
+
+static void
+mxvolume(void)
+{
+ Vol *v;
+ int i, l, r;
+
+ ilock(&csdev);
+ speaker(0);
+ for(i =0; volumes[i].name; i++){
+ v = &volumes[i];
+ if(v->load == 0)
+ continue;
+ if(v->flag & Fin){
+ l = audio.livol[i];
+ r = audio.rivol[i];
+ } else {
+ l = audio.lovol[i];
+ r = audio.rovol[i];
+ }
+ if(l < 0)
+ l = 0;
+ if(r < 0)
+ r = 0;
+ if(l > 100)
+ l = 100;
+ if(r > 100)
+ r = 100;
+ l = mix_cvt[l];
+ r = mix_cvt[r];
+ if((v->flag & Fmono) == 0){
+ xout(v->reg, (*v->load)(xin(v->reg), l));
+ xout(v->reg+1, (*v->load)(xin(v->reg+1), r));
+ } else
+ xout(v->reg, (*v->load)(xin(v->reg), l));
+ }
+ xout(LeftADC, (xin(LeftADC)&~ISmask)|csdev.regs[LeftADC]);
+ xout(RightADC, (xin(RightADC)&~ISmask)|csdev.regs[RightADC]);
+ if(audio.loopback)
+ xout(Loopback, xin(Loopback)|LBE);
+ else
+ xout(Loopback, xin(Loopback)&~LBE);
+ csformat(InFormat, CMCE, csdev.regs[InFormat], audio.livol);
+ csformat(OutFormat, PMCE, csdev.regs[OutFormat], audio.lovol);
+ if(audio.lovol[Vaudio] || audio.rovol[Vaudio])
+ speaker(1);
+ iunlock(&csdev);
+}
+
+static void
+flushinput(void)
+{
+ Buf *b;
+
+ ilock(&csdev);
+ audio.in.flushing = 1;
+ iunlock(&csdev);
+ qlock(&audio.in);
+ if(waserror()){
+ qunlock(&audio.in);
+ nexterror();
+ }
+ sleep(&audio.in.r, incomplete, &audio.in);
+ qunlock(&audio.in);
+ poperror();
+ ilock(&csdev);
+ audio.in.flushing = 0;
+ iunlock(&csdev);
+ if((b = audio.in.filling) != 0){
+ audio.in.filling = 0;
+ putbuf(&audio.in.empty, b);
+ }
+ while((b = getbuf(&audio.in.full)) != 0)
+ putbuf(&audio.in.empty, b);
+}
+
+static void
+waitoutput(void)
+{
+ qlock(&audio.out);
+ if(waserror()){
+ qunlock(&audio.out);
+ nexterror();
+ }
+ startoutput();
+ while(!outcomplete(&audio.out))
+ sleep(&audio.out.r, outcomplete, &audio.out);
+ qunlock(&audio.out);
+ poperror();
+}
+
+static void
+resetlevel(void)
+{
+ int i;
+
+ for(i=0; volumes[i].name; i++) {
+ audio.lovol[i] = volumes[i].ilval;
+ audio.rovol[i] = volumes[i].irval;
+ audio.livol[i] = volumes[i].ilval;
+ audio.rivol[i] = volumes[i].irval;
+ }
+}
+
+void
+cs4231init(void)
+{
+ cs4231install();
+
+ csdev.regs[LeftADC] = ISmic;
+ csdev.regs[RightADC] = ISmic;
+ dmasize(Wdma, 8);
+ dmasize(Rdma, 8);
+ csdev.sticky = 0;
+ OUT(Paddr, Mode);
+ csdelay();
+ if((IN(Pdata) & 0x8F) != 0x8a){
+ DPRINT("port %x not cs4231a: %x\n", IN(Pdata));
+ return;
+ }
+ print("audio0: cs4231a: port %x irq %d wdma %d rdma %d\n", csdev.port, csdev.irq, Wdma, Rdma);
+
+ resetlevel();
+
+ cswait();
+ OUT(Paddr, Mode);
+ csdelay();
+ OUT(Pdata, Mode2|IN(Pdata)); /* mode2 for all the trimmings */
+ csdelay();
+ cswait();
+
+ csdev.sticky = MCE;
+ xout(Config, Fullcal);
+ csspeed(volumes[Vspeed].ilval);
+ csformat(InFormat, CMCE, Linear8, audio.livol);
+ csformat(OutFormat, PMCE, Linear8, audio.lovol);
+ csdev.sticky &= ~MCE;
+ OUT(Paddr, csdev.sticky);
+ microdelay(10000);
+ cswait(); /* recalibration takes ages */
+
+ xout(FeatureStatus, 0);
+ OUT(Pstatus, 0);
+ setvec(csdev.irq, cs4231intr, 0);
+ xout(PinControl, xin(PinControl)|IEN);
+}
+
+Chan*
+cs4231attach(char *param)
+{
+ return devattach('A', param);
+}
+
+Chan*
+cs4231clone(Chan *c, Chan *nc)
+{
+ return devclone(c, nc);
+}
+
+int
+cs4231walk(Chan *c, char *name)
+{
+ return devwalk(c, name, audiodir, NPORT, devgen);
+}
+
+void
+cs4231stat(Chan *c, char *db)
+{
+ devstat(c, db, audiodir, NPORT, devgen);
+}
+
+Chan*
+cs4231open(Chan *c, int omode)
+{
+ switch(c->qid.path & ~CHDIR) {
+ default:
+ error(Eperm);
+ break;
+
+ case Qaudioctl:
+ case Qdir:
+ break;
+
+ case Qaudio:
+ qlock(&audio);
+ if(audio.opened){
+ qunlock(&audio);
+ error(Einuse);
+ }
+ if(audio.bufinit == 0) {
+ audio.bufinit = 1;
+ acbufinit(&audio.in);
+ acbufinit(&audio.out);
+ }
+ audio.opened = 1;
+ setempty();
+ qunlock(&audio);
+ mxvolume();
+ break;
+ }
+ c = devopen(c, omode, audiodir, NPORT, devgen);
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+
+ return c;
+}
+
+void
+cs4231create(Chan *c, char *name, int omode, ulong perm)
+{
+ USED(c, name, omode, perm);
+ error(Eperm);
+}
+
+void
+cs4231close(Chan *c)
+{
+ Buf *b;
+
+ switch(c->qid.path & ~CHDIR) {
+ default:
+ error(Eperm);
+ break;
+
+ case Qdir:
+ case Qaudioctl:
+ break;
+
+ case Qaudio:
+ if(c->flag & COPEN) {
+ qlock(&audio);
+ audio.opened = 0;
+ if(waserror()){
+ qunlock(&audio);
+ nexterror();
+ }
+ b = audio.out.filling;
+ if(b){
+ audio.out.filling = 0;
+ putbuf(&audio.out.full, b);
+ }
+ waitoutput();
+ flushinput();
+ //tsleep(&up->sleep, return0, 0, 500);
+ //speaker(0);
+ qunlock(&audio);
+ poperror();
+ }
+ break;
+ }
+}
+
+long
+cs4231read(Chan *c, char *a, long n, vlong offset)
+{
+ int liv, riv, lov, rov, ifmt, ofmt;
+ long m, n0;
+ char buf[350];
+ Buf *b;
+ int j;
+
+ n0 = n;
+ switch(c->qid.path & ~CHDIR) {
+ default:
+ error(Eperm);
+ break;
+
+ case Qdir:
+ return devdirread(c, a, n, audiodir, NPORT, devgen);
+
+ case Qaudio:
+ qlock(&audio.in);
+ if(waserror()){
+ qunlock(&audio.in);
+ nexterror();
+ }
+ while(n > 0) {
+ b = audio.in.filling;
+ if(b == 0) {
+ b = getbuf(&audio.in.full);
+ if(b == 0) {
+ startinput();
+ sleep(&audio.in.r, anyinput, &audio.in);
+ continue;
+ }
+ audio.in.filling = b;
+ b->count = 0;
+ }
+ m = Bufsize-b->count;
+ if(m > n)
+ m = n;
+ memmove(a, b->virt+b->count, m);
+
+ b->count += m;
+ n -= m;
+ a += m;
+ if(b->count >= Bufsize) {
+ audio.in.filling = 0;
+ putbuf(&audio.in.empty, b);
+ }
+ }
+ qunlock(&audio.in);
+ poperror();
+ break;
+
+ case Qaudioctl:
+ j = 0;
+ buf[0] = 0;
+ for(m=0; volumes[m].name; m++){
+ liv = audio.livol[m];
+ riv = audio.rivol[m];
+ lov = audio.lovol[m];
+ rov = audio.rovol[m];
+ j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
+ if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
+ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
+ j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
+ else{
+ if(volumes[m].flag & Fin)
+ j += snprint(buf+j, sizeof(buf)-j, " in %d", liv);
+ if(volumes[m].flag & Fout)
+ j += snprint(buf+j, sizeof(buf)-j, " out %d", lov);
+ }
+ }else{
+ if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov)
+ j += snprint(buf+j, sizeof(buf)-j, " left %d right %d",
+ liv, riv);
+ else{
+ if(volumes[m].flag & Fin)
+ j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d",
+ liv, riv);
+ if(volumes[m].flag & Fout)
+ j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d",
+ lov, rov);
+ }
+ }
+ j += snprint(buf+j, sizeof(buf)-j, "\n");
+ }
+ ifmt = xin(InFormat);
+ ofmt = xin(OutFormat);
+ if(ifmt != ofmt){
+ j += snprint(buf+j, sizeof(buf)-j, "in enc %s\n", encname(ifmt));
+ j += snprint(buf+j, sizeof(buf)-j, "out enc %s\n", encname(ofmt));
+ } else
+ j += snprint(buf+j, sizeof(buf)-j, "enc %s\n", encname(ifmt));
+ j += snprint(buf+j, sizeof(buf)-j, "loop %d\n", audio.loopback);
+ {int i; for(i=0; i<32; i++){j += snprint(buf+j, sizeof(buf)-j, " %d:%x", i, xin(i)); }j += snprint(buf+j,sizeof(buf)-j,"\n");}
+ USED(j);
+
+ return readstr(offset, a, n, buf);
+ }
+ return n0-n;
+}
+
+Block*
+cs4231bread(Chan *c, long n, ulong offset)
+{
+ return devbread(c, n, offset);
+}
+
+long
+cs4231write(Chan *c, char *a, long n, vlong offset)
+{
+ long m, n0;
+ int i, nf, v, left, right, in, out, fmt, doload;
+ char buf[255], *field[Ncmd];
+ Buf *b;
+
+ USED(offset);
+
+ n0 = n;
+ switch(c->qid.path & ~CHDIR) {
+ default:
+ error(Eperm);
+ break;
+
+ case Qaudioctl:
+ waitoutput();
+ flushinput();
+ qlock(&audio);
+ if(waserror()){
+ qunlock(&audio);
+ nexterror();
+ }
+ v = Vaudio;
+ doload = 0;
+ left = 1;
+ right = 1;
+ in = 1;
+ out = 1;
+ if(n > sizeof(buf)-1)
+ n = sizeof(buf)-1;
+ memmove(buf, a, n);
+ buf[n] = '\0';
+
+ nf = getfields(buf, field, Ncmd, 1, " \t\n,");
+ for(i = 0; i < nf; i++){
+ /*
+ * a number is volume
+ */
+ if(field[i][0] >= '0' && field[i][0] <= '9') {
+ m = strtoul(field[i], 0, 10);
+ if(left && out)
+ audio.lovol[v] = m;
+ if(left && in)
+ audio.livol[v] = m;
+ if(right && out)
+ audio.rovol[v] = m;
+ if(right && in)
+ audio.rivol[v] = m;
+ if(v == Vspeed){
+ ilock(&csdev);
+ csdev.sticky = MCE;
+ csspeed(m);
+ csdev.sticky &= ~MCE;
+ OUT(Paddr, csdev.sticky);
+ microdelay(10000);
+ cswait();
+ iunlock(&csdev);
+ } else
+ doload = 1;
+ continue;
+ }
+
+ for(m=0; volumes[m].name; m++) {
+ if(strcmp(field[i], volumes[m].name) == 0) {
+ v = m;
+ in = 1;
+ out = 1;
+ left = 1;
+ right = 1;
+ break;
+ }
+ }
+ if(volumes[m].name)
+ continue;
+
+ if(strcmp(field[i], "chat") == 0){
+ chatty = !chatty;
+ continue;
+ }
+
+ if(strcmp(field[i], "reset") == 0) {
+ resetlevel();
+ doload = 1;
+ continue;
+ }
+ if(strcmp(field[i], "loop") == 0) {
+ if(++i >= nf)
+ error(Evolume);
+ audio.loopback = strtoul(field[i], 0, 10);
+ doload = 1;
+ continue;
+ }
+ if(strcmp(field[i], "enc") == 0) {
+ if(++i >= nf)
+ error(Evolume);
+ fmt = -1;
+ if(strcmp(field[i], "ulaw") == 0)
+ fmt = uLaw;
+ else if(strcmp(field[i], "alaw") == 0)
+ fmt = aLaw;
+ else if(strcmp(field[i], "pcm") == 0)
+ fmt = Linear8;
+ else if(strcmp(field[i], "adpcm") == 0)
+ fmt = ADPCM;
+ else
+ error(Evolume);
+ if(in)
+ csdev.regs[InFormat] = fmt;
+ if(out)
+ csdev.regs[OutFormat] = fmt;
+ doload = 1;
+ continue;
+ }
+ if(strcmp(field[i], "dev") == 0) {
+ if(++i >= nf)
+ error(Evolume);
+ if(in){
+ fmt = -1;
+ if(strcmp(field[i], "mic") == 0)
+ fmt = ISmic;
+ else if(strcmp(field[i], "line") == 0)
+ fmt = ISline;
+ else if(strcmp(field[i], "aux1") == 0)
+ fmt = ISaux1;
+ else if(strcmp(field[i], "loop") == 0)
+ fmt = ISloop;
+ else
+ error(Evolume);
+ if(left)
+ csdev.regs[LeftADC] = fmt;
+ if(right)
+ csdev.regs[RightADC] = fmt;
+ doload = 1;
+ }
+ continue;
+ }
+ if(strcmp(field[i], "in") == 0) {
+ in = 1;
+ out = 0;
+ continue;
+ }
+ if(strcmp(field[i], "out") == 0) {
+ in = 0;
+ out = 1;
+ continue;
+ }
+ if(strcmp(field[i], "left") == 0) {
+ left = 1;
+ right = 0;
+ continue;
+ }
+ if(strcmp(field[i], "right") == 0) {
+ left = 0;
+ right = 1;
+ continue;
+ }
+ error(Evolume);
+ }
+ if(doload)
+ mxvolume();
+ qunlock(&audio);
+ poperror();
+ n=0;
+ break;
+
+ case Qaudio:
+ qlock(&audio.out);
+ if(waserror()){
+ qunlock(&audio.out);
+ nexterror();
+ }
+ while(n > 0) {
+ b = audio.out.filling;
+ if(b == 0) {
+ b = getbuf(&audio.out.empty);
+ if(b == 0) {
+ startoutput();
+ sleep(&audio.out.r, anybuf, &audio.out);
+ continue;
+ }
+ b->count = 0;
+ audio.out.filling = b;
+ }
+
+ m = Bufsize-b->count;
+ if(m > n)
+ m = n;
+ memmove(b->virt+b->count, a, m);
+
+ b->count += m;
+ n -= m;
+ a += m;
+ if(b->count >= Bufsize) {
+ audio.out.filling = 0;
+ putbuf(&audio.out.full, b);
+ }
+ }
+ qunlock(&audio.out);
+ poperror();
+ break;
+ }
+ return n0 - n;
+}
+
+long
+cs4231bwrite(Chan *c, Block *bp, ulong offset)
+{
+ return devbwrite(c, bp, offset);
+}
+
+void
+cs4231remove(Chan *c)
+{
+ USED(c);
+ error(Eperm);
+}
+
+void
+cs4231wstat(Chan *c, char *dp)
+{
+ USED(c, dp);
+ error(Eperm);
+}
+
+static char *
+encname(int v)
+{
+ switch(v & ~(0xF|Stereo)){
+ case uLaw: return "ulaw";
+ case aLaw: return "alaw";
+ case Linear8: return "pcm";
+ case Linear16: return "pcm16";
+ case ADPCM: return "adpcm";
+ default: return "?";
+ }
+}
diff --git a/os/js/devrtc.c b/os/js/devrtc.c
new file mode 100644
index 00000000..25fcfa1e
--- /dev/null
+++ b/os/js/devrtc.c
@@ -0,0 +1,413 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "io.h"
+
+/*
+ * Mostek MK48T12-15 Zeropower/Timekeeper
+ * This driver is actually portable.
+ */
+typedef struct Rtc Rtc;
+struct Rtc
+{
+ int sec;
+ int min;
+ int hour;
+ int wday;
+ int mday;
+ int mon;
+ int year;
+};
+
+static uchar rtcgencksum(void);
+static void setrtc(Rtc *rtc);
+static long rtctime(void);
+static int *yrsize(int yr);
+static int *yrsize(int yr);
+static ulong rtc2sec(Rtc *rtc);
+static void sec2rtc(ulong secs, Rtc *rtc);
+
+static struct
+{
+ uchar *cksum;
+ uchar *ram;
+ RTCdev *rtc;
+}nvr;
+
+enum{
+ Qdir,
+ Qrtc,
+ Qnvram,
+};
+
+QLock rtclock; /* mutex on clock operations */
+
+static Dirtab rtcdir[]={
+ ".", {Qdir, 0, QTDIR}, 0, 0555,
+ "rtc", {Qrtc, 0}, 0, 0666,
+ "nvram", {Qnvram, 0}, NVWRITE, 0666,
+};
+#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0]))
+
+static void
+rtcinit(void)
+{
+ KMap *k;
+
+ k = kmappa(NVR_CKSUM_PHYS, PTENOCACHE|PTEIO);
+ nvr.cksum = (uchar*)VA(k);
+
+ k = kmappa(NVR_PHYS, PTENOCACHE|PTEIO);
+ nvr.ram = (uchar*)VA(k);
+ nvr.rtc = (RTCdev*)(VA(k)+RTCOFF);
+
+ rtcgencksum();
+}
+
+static Chan*
+rtcattach(char *spec)
+{
+ return devattach('r',spec);
+}
+
+static Walkqid*
+rtcwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen);
+}
+
+static int
+rtcstat(Chan *c, uchar *dp, int n)
+{
+ return devstat(c, dp, n, rtcdir, NRTC, devgen);
+}
+
+static Chan*
+rtcopen(Chan *c, int omode)
+{
+ omode = openmode(omode);
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ if(strcmp(up->env->user, eve)!=0 && omode!=OREAD)
+ error(Eperm);
+ break;
+ case Qnvram:
+ if(strcmp(up->env->user, eve)!=0)
+ error(Eperm);
+ }
+ return devopen(c, omode, rtcdir, NRTC, devgen);
+}
+
+static void
+rtccreate(Chan *c, char *name, int omode, ulong perm)
+{
+ USED(c, name, omode, perm);
+ error(Eperm);
+}
+
+static void
+rtcclose(Chan *c)
+{
+ USED(c);
+}
+
+static long
+rtcread(Chan *c, void *buf, long n, vlong offset)
+{
+ ulong t, ot;
+
+ if(c->qid.type & QTDIR)
+ return devdirread(c, buf, n, rtcdir, NRTC, devgen);
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ qlock(&rtclock);
+ t = rtctime();
+ do{
+ ot = t;
+ t = rtctime(); /* make sure there's no skew */
+ }while(t != ot);
+ qunlock(&rtclock);
+ n = readnum(offset, buf, n, t, 12);
+ return n;
+ case Qnvram:
+ if(offset > NVREAD)
+ return 0;
+ if(n > NVREAD - offset)
+ n = NVREAD - offset;
+ qlock(&rtclock);
+ memmove(buf, nvr.ram+offset, n);
+ qunlock(&rtclock);
+ return n;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+/*
+ * XXX - Tad: fixme to generate the correct checksum
+ */
+static uchar
+rtcgencksum(void)
+{
+ uchar cksum;
+ int i;
+ static uchar p1cksum = 0;
+ static uchar p1cksumvalid=0;
+
+ if(!p1cksumvalid) {
+ for(i=1; i < 0x1000 ; i++)
+ p1cksum ^= nvr.cksum[i];
+ p1cksumvalid = 1;
+ }
+
+ cksum = p1cksum;
+
+ for(i=0; i < 0xfdf ; i++) {
+ cksum ^= nvr.ram[i];
+ }
+
+ return cksum;
+}
+
+static long
+rtcwrite(Chan *c, void *buf, long n, vlong offset)
+{
+ Rtc rtc;
+ ulong secs;
+ char *cp, sbuf[32];
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ /*
+ * read the time
+ */
+ if(offset != 0 || n >= sizeof(sbuf)-1)
+ error(Ebadarg);
+ memmove(sbuf, buf, n);
+ sbuf[n] = '\0';
+ cp = sbuf;
+ while(*cp){
+ if(*cp>='0' && *cp<='9')
+ break;
+ cp++;
+ }
+ secs = strtoul(cp, 0, 0);
+ /*
+ * convert to bcd
+ */
+ sec2rtc(secs, &rtc);
+ /*
+ * write it
+ */
+ qlock(&rtclock);
+ setrtc(&rtc);
+ qunlock(&rtclock);
+ return n;
+ case Qnvram:
+ if(offset > NVWRITE)
+ return 0;
+ if(n > NVWRITE - offset)
+ n = NVWRITE - offset;
+ qlock(&rtclock);
+ memmove(nvr.ram+offset, buf, n);
+ *nvr.cksum = rtcgencksum();
+ qunlock(&rtclock);
+ return n;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+#define bcd2dec(bcd) (((((bcd)>>4) & 0x0F) * 10) + ((bcd) & 0x0F))
+#define dec2bcd(dec) ((((dec)/10)<<4)|((dec)%10))
+
+static void
+setrtc(Rtc *rtc)
+{
+ struct RTCdev *dev;
+
+ dev = nvr.rtc;
+ dev->control |= RTCWRITE;
+ wbflush();
+ dev->year = dec2bcd(rtc->year % 100);
+ dev->mon = dec2bcd(rtc->mon);
+ dev->mday = dec2bcd(rtc->mday);
+ dev->hour = dec2bcd(rtc->hour);
+ dev->min = dec2bcd(rtc->min);
+ dev->sec = dec2bcd(rtc->sec);
+ wbflush();
+ dev->control &= ~RTCWRITE;
+ wbflush();
+}
+
+static long
+rtctime(void)
+{
+ struct RTCdev *dev;
+ Rtc rtc;
+
+ dev = nvr.rtc;
+ dev->control |= RTCREAD;
+ wbflush();
+ rtc.sec = bcd2dec(dev->sec) & 0x7F;
+ rtc.min = bcd2dec(dev->min & 0x7F);
+ rtc.hour = bcd2dec(dev->hour & 0x3F);
+ rtc.mday = bcd2dec(dev->mday & 0x3F);
+ rtc.mon = bcd2dec(dev->mon & 0x3F);
+ rtc.year = bcd2dec(dev->year);
+ dev->control &= ~RTCREAD;
+ wbflush();
+
+ if (rtc.mon < 1 || rtc.mon > 12)
+ return 0;
+ /*
+ * the world starts Jan 1 1970
+ */
+ if(rtc.year < 70)
+ rtc.year += 2000;
+ else
+ rtc.year += 1900;
+
+ return rtc2sec(&rtc);
+}
+
+#define SEC2MIN 60L
+#define SEC2HOUR (60L*SEC2MIN)
+#define SEC2DAY (24L*SEC2HOUR)
+
+/*
+ * days per month plus days/year
+ */
+static int dmsize[] =
+{
+ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+static int ldmsize[] =
+{
+ 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * return the days/month for the given year
+ */
+static int *
+yrsize(int yr)
+{
+ if((yr % 4) == 0)
+ return ldmsize;
+ else
+ return dmsize;
+}
+
+/*
+ * compute seconds since Jan 1 1970
+ */
+static ulong
+rtc2sec(Rtc *rtc)
+{
+ ulong secs;
+ int i;
+ int *d2m;
+
+ secs = 0;
+
+ /*
+ * seconds per year
+ */
+ for(i = 1970; i < rtc->year; i++){
+ d2m = yrsize(i);
+ secs += d2m[0] * SEC2DAY;
+ }
+
+ /*
+ * seconds per month
+ */
+ d2m = yrsize(rtc->year);
+ for(i = 1; i < rtc->mon; i++)
+ secs += d2m[i] * SEC2DAY;
+
+ secs += (rtc->mday-1) * SEC2DAY;
+ secs += rtc->hour * SEC2HOUR;
+ secs += rtc->min * SEC2MIN;
+ secs += rtc->sec;
+
+ return secs;
+}
+
+/*
+ * compute rtc from seconds since Jan 1 1970
+ */
+static void
+sec2rtc(ulong secs, Rtc *rtc)
+{
+ int d;
+ long hms, day;
+ int *d2m;
+
+ /*
+ * break initial number into days
+ */
+ hms = secs % SEC2DAY;
+ day = secs / SEC2DAY;
+ if(hms < 0) {
+ hms += SEC2DAY;
+ day -= 1;
+ }
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ rtc->sec = hms % 60;
+ d = hms / 60;
+ rtc->min = d % 60;
+ d /= 60;
+ rtc->hour = d;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d = 1970; day >= *yrsize(d); d++)
+ day -= *yrsize(d);
+ else
+ for (d = 1970; day < 0; d--)
+ day += *yrsize(d-1);
+ rtc->year = d;
+
+ /*
+ * generate month
+ */
+ d2m = yrsize(rtc->year);
+ for(d = 1; day >= d2m[d]; d++)
+ day -= d2m[d];
+ rtc->mday = day + 1;
+ rtc->mon = d;
+
+ return;
+}
+
+Dev rtcdevtab = {
+ 'r',
+ "rtc",
+
+ devreset,
+ rtcinit,
+ devshutdown,
+ rtcattach,
+ rtcwalk,
+ rtcstat,
+ rtcopen,
+ rtccreate,
+ rtcclose,
+ rtcread,
+ devbread,
+ rtcwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
diff --git a/os/js/fns.h b/os/js/fns.h
new file mode 100644
index 00000000..2ad8ac14
--- /dev/null
+++ b/os/js/fns.h
@@ -0,0 +1,110 @@
+#include "../port/portfns.h"
+#define dumplongs(x, y, z)
+#define clockcheck()
+#define setpanic()
+
+void links(void);
+void prom_printf(char *format, ...); /* can't use after mmuinit() */
+void savefpregs(FPU *);
+void restfpregs(FPU*);
+void savefsr(FPenv *);
+void restfsr(FPenv *);
+void disabfp(void);
+void fpinit(void);
+void fpsave(FPU*);
+void bootargs(ulong);
+void cacheinit(void);
+ulong call_openboot(void*, ...);
+void clearftt(ulong);
+#define clearmmucache()
+void clockinit(void);
+void clock(Ureg*);
+#define coherence() /* nothing to do on uniprocessor */
+void dcflush(void);
+void disabfp(void);
+void enabfp(void);
+char* excname(ulong);
+
+#define flushpage(pa) icflush()
+void flushtlb(void);
+void flushtlbctx(void);
+void flushtlbpage(ulong);
+int fpcr(int);
+int fpquiet(void);
+void fpregrestore(char*);
+void fpregsave(char*);
+int fptrap(void);
+int getfpq(ulong*);
+ulong getfsr(void);
+ulong getpcr(void);
+ulong getphys(ulong);
+ulong getrmmu(ulong);
+ulong getpsr(void);
+void icflush(void);
+int isvalid_va(void*);
+void flushicache(void);
+void flushdcache(void);
+void flushiline(ulong);
+void flushdline(ulong);
+#define idlehands() /* nothing to do in the runproc */
+void intrinit(void);
+void ioinit(void);
+void kbdclock(void);
+void kbdrepeat(int);
+void kbdinit(void);
+void kbdintr(void);
+#define KADDR(a) ((void*)((ulong)(a)|KZERO))
+#define PADDR(a) ((ulong)(a)&~KZERO)
+void kmapinit(void);
+void* kmappa(ulong, ulong);
+ulong kmapsbus(int);
+ulong kmapdma(ulong, ulong);
+int kprint(char*, ...);
+void kproftimer(ulong);
+void kunmap(KMap*);
+void lanceintr(void);
+void lancesetup(Lance*);
+void lancetoggle(void);
+void mmuinit(void);
+void mousebuttons(int);
+void printinit(void);
+#define procrestore(p)
+#define procsave(p)
+#define procsetup(x) ((p)->fpstate = FPinit)
+void putphys(ulong, ulong);
+void putrmmu(ulong, ulong);
+void putstr(char*);
+void puttbr(ulong);
+void systemreset(void);
+void screeninit(void);
+void screenputc(char *);
+void screenputs(char*, int);
+void scsiintr(void);
+void setpcr(ulong);
+void setpsr(ulong);
+void spldone(void);
+void trap(Ureg*);
+void trapinit(void);
+#define wbflush() /* mips compatibility */
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+ulong getcallerpc(void*);
+void dumpregs(Ureg*);
+
+void ns16552special(int,int,Queue**,Queue**,int (*)(Queue*,int));
+char ns16552dmarcv(int);
+void ns16552install(void);
+void ns16552intr(int);
+
+long dmasetup(int,void*,long,int);
+void dmaend(int);
+int dmacount(int);
+
+void superioinit(ulong va, uchar*, uchar*, uchar*, uchar*);
+ulong superiova(void);
+
+uchar superio_readctl(void);
+uchar superio_readdata(void);
+void superio_writectl(uchar val);
+void superio_writedata(uchar val);
+void outb(ulong, uchar);
+uchar inb(ulong);
diff --git a/os/js/fsv.c b/os/js/fsv.c
new file mode 100644
index 00000000..9832ce3b
--- /dev/null
+++ b/os/js/fsv.c
@@ -0,0 +1,198 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "io.h"
+#include "dat.h"
+#include "fns.h"
+
+#include <draw.h>
+#include <memdraw.h>
+#include "screen.h"
+
+extern Video *vid;
+extern Memimage gscreen;
+
+static Vctlr* init(Vctlr* vctlr, int x, int y, int d);
+static int setcolour(ulong p, ulong r, ulong g, ulong b);
+static void enable(void);
+static void disable(void);
+static void move(int cx, int cy);
+static void load(Cursor *c);
+static int isloaded(void);
+
+extern void* memcpy(void*, void*, int);
+extern void cursorupdate0(void);
+
+Vctlr FSV = {
+ "FSV", /* name */
+ init, /* init */
+ 0, /* page */
+ setcolour, /* setcolor */
+
+ enable, /* enable cursor fn */
+ disable, /* disable cursor fn */
+ move, /* move cursor fn */
+ load, /* load cursor fn */
+ isloaded, /* is cursor loaded? */
+ 0, /* deprecated */
+
+ 1024, /* screen width (x) */
+ 768, /* screen height (y) */
+ 3, /* depth */
+
+ 0, /* hidecount */
+ 0, /* loaded */
+};
+
+static int lastx=-1;
+static int lasty=-1;
+
+static Vctlr*
+init(Vctlr* vctlr, int x, int y, int d)
+{
+ USED(vctlr,x,y,d);
+
+ return &FSV;
+}
+
+static int
+setcolour(ulong p, ulong r, ulong g, ulong b)
+{
+ if(gscreen.ldepth == 0)
+ return 0; /* can't change mono screen colormap */
+ else{
+ vid->addr = p << 24;
+ vid->color = r << 24;
+ vid->color = g << 24;
+ vid->color = b << 24;
+ return 1;
+ }
+}
+
+static ulong backingstore[64];
+static Memdata backingstoredata = {
+ nil,
+ backingstore
+};
+
+static ulong backingnocursor[64];
+static Memdata backingnocursordata = {
+ nil,
+ backingnocursor
+};
+
+static ulong backwithcursor[64];
+static Memdata backwithcursordata = {
+ nil,
+ backwithcursor
+};
+
+static Memimage backingnocursormem = {
+ {0,0,16,16},
+ {0,0,16,16},
+ 3,
+ 0,
+ &backingnocursordata,
+ 0,
+ 16/4,
+ 0,
+ 0,
+};
+static Memimage backingmem = {
+ {0,0,16,16},
+ {0,0,16,16},
+ 3,
+ 0,
+ &backingstoredata,
+ 0,
+ 16/4,
+ 0,
+ 0,
+};
+
+static void
+disable(void)
+{
+ if(FSV.hidecount++)
+ return;
+ if(lastx < 0 || lasty < 0)
+ return;
+
+ memimagedraw(&gscreen, Rect(lastx,lasty,lastx+16,lasty+16),
+ &backingnocursormem, Pt(0,0), memones, Pt(0,0));
+}
+
+static void
+enable(void)
+{
+ uchar *p;
+ uchar mask;
+ uchar *cset;
+ int i;
+
+ if(--FSV.hidecount > 0)
+ return;
+ FSV.hidecount = 0;
+
+ if(lastx < 0 || lasty < 0)
+ return;
+
+ memimagedraw(&backingmem,Rect(0,0,16,16),&gscreen,Pt(lastx,lasty),memones,
+ Pt(0,0));
+
+ memcpy(backingnocursor,backingstore,256);
+ p = (uchar*)backingmem.data->data;
+
+ cset = FSV.cursor.set;
+
+ for(i=0;i<32;i++) {
+ mask = ~cset[i];
+
+ if(!(mask&(1<<7))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<6))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<5))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<4))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<3))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<2))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<1))) *p = 0xff;
+ ++p;
+ if(!(mask&(1<<0))) *p = 0xff;
+ ++p;
+ }
+
+ memimagedraw(&gscreen,Rect(lastx,lasty,lastx+16,lasty+16),&backingmem,Pt(0,0),
+ memones,Pt(0,0));
+}
+
+static void
+move(int cx, int cy)
+{
+ if(!FSV.loaded)
+ return;
+
+ disable();
+ cursorupdate0();
+ lastx = cx;
+ lasty = cy;
+ enable();
+}
+
+
+static void
+load(Cursor *curs)
+{
+ FSV.cursor = *curs;
+ FSV.loaded=1;
+}
+
+static int
+isloaded(void)
+{
+ return FSV.loaded;
+}
diff --git a/os/js/io.h b/os/js/io.h
new file mode 100644
index 00000000..c3868eb2
--- /dev/null
+++ b/os/js/io.h
@@ -0,0 +1,224 @@
+/*
+ * most device registers are memory mapped, but
+ * a few things are accessed using putphys/getphys
+ */
+#define SBUS(n) (0x30000000+(n)*0x10000000)
+#define FRAMEBUF(n) SBUS(n)
+#define FRAMEBUFID(n) (SBUS(n)+0x000000)
+#define DISPLAYRAM(n) (SBUS(n)+0x800000)
+#define CLOCK 0x71D00000
+#define CLOCKFREQ 1000000 /* one microsecond increments */
+
+#define SUPERIO_PHYS_PAGE 0x71300000
+#define SUPERIO_INDEX_OFFSET 0x398
+#define SUPERIO_DATA_OFFSET 0x399
+#define SUPERIO_MOUSE_KBD_DATA_PORT 0x60
+#define SUPERIO_MOUSE_KBD_CTL_PORT 0x64
+
+#define AUDIO_PHYS_PAGE 0x66666666
+#define AUDIO_INDEX_OFFSET 0x830
+
+enum
+{
+ Mousevec = 13,
+ Kbdvec = 13
+};
+
+#define NVR_CKSUM_PHYS 0x71200000 /* non-volatile RAM cksum page */
+#define NVR_PHYS 0x71201000 /* non-volatile RAM */
+#define DMA 0x78400000 /* SCSI and Ether DMA registers */
+#define SCSI 0x78800000 /* NCR53C90 registers */
+#define ETHER 0x78C00000 /* RDP, RAP */
+#define FLOPPY 0x71400000
+#define SYSINTR 0x71E10000 /* system interrupt control registers */
+
+#define TIMECONFIG 0x71D10010 /* timer configuration register (phys) */
+#define AUXIO1 0x71900000
+#define AUXIO2 0x71910000
+
+typedef struct Sysint Sysint;
+struct Sysint
+{
+ ulong pending;
+ ulong mask;
+ ulong maskclr;
+ ulong maskset;
+ ulong target;
+};
+
+enum {
+ MaskAllIntr = 1<<31,
+ MEIntr = 1<<30,
+ MSIIntr = 1<<29,
+ EMCIntr = 1<<28,
+ VideoIntr = 1<<20, /* supersparc only */
+ Timer10 = 1<<19,
+ EtherIntr = 1<<16,
+ SCCIntr = 1<<15,
+ KbdIntr = 1<<13,
+ /* bits 7 to 13 are SBUS levels 1 to 7 */
+};
+#define SBUSINTR(x) (1<<((x)+6))
+
+typedef struct SCCdev SCCdev;
+struct SCCdev
+{
+ uchar ptrb;
+ uchar dummy1;
+ uchar datab;
+ uchar dummy2;
+ uchar ptra;
+ uchar dummy3;
+ uchar dataa;
+ uchar dummy4;
+};
+
+/*
+ * non-volatile ram
+ */
+#define NVREAD (4096-32) /* minus RTC */
+#define NVWRITE (0x800) /* */
+#define IDOFF (4096-8-32)
+
+/*
+ * real-time clock
+ */
+typedef struct RTCdev RTCdev;
+struct RTCdev
+{
+ uchar control; /* read or write the device */
+ uchar sec;
+ uchar min;
+ uchar hour;
+ uchar wday;
+ uchar mday;
+ uchar mon;
+ uchar year;
+};
+#define RTCOFF 0xFF8
+#define RTCREAD (0x40)
+#define RTCWRITE (0x80)
+
+/*
+ * dma
+ */
+typedef struct DMAdev DMAdev;
+struct DMAdev {
+ /* ESP/SCSI DMA */
+ ulong csr; /* Control/Status */
+ ulong addr; /* address in 16Mb segment */
+ ulong count; /* transfer byte count */
+ ulong diag;
+
+ /* Ether DMA */
+ ulong ecsr; /* Control/Status */
+ ulong ediag;
+ ulong cache; /* cache valid bits */
+ uchar base; /* base address (16Mb segment) */
+};
+
+enum {
+ Int_pend = 0x00000001, /* interrupt pending */
+ Err_pend = 0x00000002, /* error pending */
+ Pack_cnt = 0x0000000C, /* pack count (mask) */
+ Int_en = 0x00000010, /* interrupt enable */
+ Dma_Flush = 0x00000020, /* flush pack end error */
+ Drain = 0x00000040, /* drain pack to memory */
+ Dma_Reset = 0x00000080, /* hardware reset (sticky) */
+ Write = 0x00000100, /* set for device to memory (!) */
+ En_dma = 0x00000200, /* enable DMA */
+ Req_pend = 0x00000400, /* request pending */
+ Byte_addr = 0x00001800, /* next byte addr (mask) */
+ En_cnt = 0x00002000, /* enable count */
+ Tc = 0x00004000, /* terminal count */
+ Ilacc = 0x00008000, /* which ether chip */
+ Dev_id = 0xF0000000, /* device ID */
+};
+
+/*
+ * NCR53C90 SCSI controller (every 4th location)
+ */
+typedef struct SCSIdev SCSIdev;
+struct SCSIdev {
+ uchar countlo; /* byte count, low bits */
+ uchar pad1[3];
+ uchar countmi; /* byte count, middle bits */
+ uchar pad2[3];
+ uchar fifo; /* data fifo */
+ uchar pad3[3];
+ uchar cmd; /* command byte */
+ uchar pad4[3];
+ union {
+ struct { /* read only... */
+ uchar status; /* status */
+ uchar pad05[3];
+ uchar intr; /* interrupt status */
+ uchar pad06[3];
+ uchar step; /* sequence step */
+ uchar pad07[3];
+ uchar fflags; /* fifo flags */
+ uchar pad08[3];
+ uchar config; /* RW: configuration */
+ uchar pad09[3];
+ uchar Reserved1;
+ uchar pad0A[3];
+ uchar Reserved2;
+ uchar pad0B[3];
+ uchar conf2; /* RW: configuration */
+ uchar pad0C[3];
+ uchar conf3; /* RW: configuration */
+ uchar pad0D[3];
+ uchar partid; /* unique part id */
+ uchar pad0E[3];
+ uchar fbottom; /* RW: fifo bottom */
+ uchar pad0F[3];
+ };
+ struct { /* write only... */
+ uchar destid; /* destination id */
+ uchar pad15[3];
+ uchar timeout; /* during selection */
+ uchar pad16[3];
+ uchar syncperiod; /* synchronous xfr period */
+ uchar pad17[3];
+ uchar syncoffset; /* synchronous xfr offset */
+ uchar pad18[3];
+ uchar RW0;
+ uchar pad19[3];
+ uchar clkconf;
+ uchar pad1A[3];
+ uchar test;
+ uchar pad1B[3];
+ uchar RW1;
+ uchar pad1C[3];
+ uchar RW2;
+ uchar pad1D[3];
+ uchar counthi; /* byte count, hi bits */
+ uchar pad1E[3];
+ uchar RW3;
+ uchar pad1F[3];
+ };
+ };
+};
+
+/*
+ * DMA2 ENET
+ */
+enum {
+ E_Int_pend = 0x00000001, /* interrupt pending */
+ E_Err_pend = 0x00000002, /* error pending */
+ E_draining = 0x0000000C, /* E-cache draining */
+ E_Int_en = 0x00000010, /* interrupt enable */
+ E_Invalidate = 0x00000020, /* mark E-cache invalid */
+ E_Slave_err = 0x00000040, /* slave access size error (sticky) */
+ E_Reset = 0x00000080, /* invalidate cache & reset interface (sticky) */
+ E_Drain = 0x00000400, /* force draining of E-cache to memory */
+ E_Dsbl_wr_drn = 0x00000800, /* disable E-cache drain on descriptor writes from ENET */
+ E_Dsbl_rd_drn = 0x00001000, /* disable E-cache drain on slave reads to ENET */
+ E_Ilacc = 0x00008000, /* `modifies ENET DMA cycle' */
+ E_Dsbl_buf_wr = 0x00010000, /* disable buffering of slave writes to ENET */
+ E_Dsbl_wr_inval = 0x00020000, /* do not invalidate E-cache on slave writes */
+ E_Burst_size = 0x000C0000, /* DMA burst size */
+ E_Loop_test = 0x00200000, /* loop back mode */
+ E_TP_select = 0x00400000, /* zero for AUI mode */
+ E_Dev_id = 0xF0000000, /* device ID */
+};
diff --git a/os/js/iob.c b/os/js/iob.c
new file mode 100644
index 00000000..4873847e
--- /dev/null
+++ b/os/js/iob.c
@@ -0,0 +1,13 @@
+#include "u.h"
+
+void
+outb(ulong addr, uchar val)
+{
+ *(uchar*)addr = val;
+}
+
+uchar
+inb(ulong addr)
+{
+ return *(uchar*)addr;
+}
diff --git a/os/js/js b/os/js/js
new file mode 100644
index 00000000..16e2ff64
--- /dev/null
+++ b/os/js/js
@@ -0,0 +1,104 @@
+dev
+ root
+ cons
+ env
+ mnt
+ pipe
+ prog
+ rtc
+ srv
+ dup
+ ssl
+ draw
+ pointer
+
+ ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium
+ lance netif netaux ethermedium
+
+ ns16552
+ tinyfs
+ cap
+# cs4231 A
+
+ip
+# il
+ tcp
+ udp
+# rudp
+# igmp
+ ipifc
+ icmp
+ icmp6
+ ipmux
+
+lib
+ interp
+ tk
+ prefab
+ draw
+ memlayer
+ memdraw
+ keyring
+ sec
+ mp
+ kern
+# math
+
+mod
+ sys
+ draw
+ prefab
+ tk
+ keyring
+
+link
+ pppmedium ppp compress
+
+init
+ jsinit
+
+
+port
+ alarm
+ alloc
+ allocb
+ chan
+ dev
+ dial
+ dis
+ discall
+ exception
+ exportfs
+ inferno
+ latin1
+ nocache
+ parse
+ pgrp
+ print
+ proc
+ qio
+ qlock
+ sysfile
+ taslock
+ xalloc
+
+code
+ int kernel_pool_pcnt = 10;
+ int main_pool_pcnt = 40;
+ int heap_pool_pcnt = 20;
+ int image_pool_pcnt = 40;
+ int consoleprint = 1;
+ int cflag = 1;
+
+
+root
+ /chan /
+ /dev /
+ /dis
+ /env /
+ /fd /
+ /n
+ /net /
+ /nvfs /
+ /prog /
+ /osinit.dis
diff --git a/os/js/kbd.c b/os/js/kbd.c
new file mode 100644
index 00000000..38bae986
--- /dev/null
+++ b/os/js/kbd.c
@@ -0,0 +1,482 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum
+{
+ Data= 0x60, /* data port */
+
+ Status= 0x64, /* status port */
+ Inready= 0x01, /* input character ready */
+ Outbusy= 0x02, /* output busy */
+ Sysflag= 0x04, /* system flag */
+ Cmddata= 0x08, /* cmd==0, data==1 */
+ Inhibit= 0x10, /* keyboard/mouse inhibited */
+ Minready= 0x20, /* mouse character ready */
+ Rtimeout= 0x40, /* general timeout */
+ Parity= 0x80,
+
+ Cmd= 0x64, /* command port (write only) */
+
+ CTdata= 0x0, /* chips & Technologies ps2 data port */
+ CTstatus= 0x1, /* chips & Technologies ps2 status port */
+ Enable= 1<<7,
+ Clear= 1<<6,
+ Error= 1<<5,
+ Intenable= 1<<4,
+ Reset= 1<<3,
+ Tready= 1<<2,
+ Rready= 1<<1,
+ Idle= 1<<0,
+
+ Spec= 0x80,
+
+ PF= Spec|0x20, /* num pad function key */
+ View= Spec|0x00, /* view (shift window up) */
+ KF= Spec|0x40, /* function key */
+ Shift= Spec|0x60,
+ Break= Spec|0x61,
+ Ctrl= Spec|0x62,
+ Latin= Spec|0x63,
+ Caps= Spec|0x64,
+ Num= Spec|0x65,
+ Middle= Spec|0x66,
+ No= 0x00, /* peter */
+
+ Home= KF|13,
+ Up= KF|14,
+ Pgup= KF|15,
+ Print= KF|16,
+ Left= View,
+ Right= View,
+ End= '\r',
+ Down= View,
+ Pgdown= View,
+ Ins= KF|20,
+ Del= 0x7F,
+
+ Rbutton=4,
+ Mbutton=2,
+ Lbutton=1,
+};
+
+uchar
+kbtab[] = {
+[0x00] No, 0x1b, '1', '2', '3', '4', '5', '6',
+[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t',
+[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+[0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's',
+[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+[0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v',
+[0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*',
+[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', No, No, No, KF|11,
+[0x58] KF|12, No, No, No, No, No, No, No,
+};
+
+uchar
+kbtabshift[] = {
+[0x00] No, 0x1b, '!', '@', '#', '$', '%', '^',
+[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t',
+[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+[0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S',
+[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+[0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V',
+[0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*',
+[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5,
+[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7',
+[0x48] '8', '9', '-', '4', '5', '6', '+', '1',
+[0x50] '2', '3', '0', '.', No, No, No, KF|11,
+[0x58] KF|12, No, No, No, No, No, No, No,
+};
+
+uchar
+kbtabesc1[] = {
+[0x00] No, No, No, No, No, No, No, No,
+[0x08] No, No, No, No, No, No, No, No,
+[0x10] No, No, No, No, No, No, No, No,
+[0x18] No, No, No, No, '\n', Ctrl, No, No,
+[0x20] No, No, No, No, No, No, No, No,
+[0x28] No, No, Shift, No, No, No, No, No,
+[0x30] No, No, No, No, No, '/', No, Print,
+[0x38] Latin, No, No, No, No, No, No, No,
+[0x40] No, No, No, No, No, No, Break, Home,
+[0x48] Up, Pgup, No, Left, No, Right, No, End,
+[0x50] Down, Pgdown, Ins, Del, No, No, No, No,
+[0x58] No, No, No, No, No, No, No, No,
+};
+
+static int keybuttons;
+static uchar ccc;
+static int shift;
+
+enum
+{
+ /* controller command byte */
+ Cscs1= (1<<6), /* scan code set 1 */
+ Cmousedis= (1<<5), /* mouse disable */
+ Ckbddis= (1<<4), /* kbd disable */
+ Csf= (1<<2), /* system flag */
+ Cmouseint= (1<<1), /* mouse interrupt enable */
+ Ckbdint= (1<<0), /* kbd interrupt enable */
+};
+
+/*
+ * wait for output no longer busy
+ */
+static int
+outready(void)
+{
+ int tries;
+
+ for(tries = 0; (superio_readctl() & Outbusy); tries++){
+ if(tries > 500)
+ return -1;
+ microdelay(2);
+ }
+ return 0;
+}
+
+/*
+ * wait for input
+ */
+static int
+inready(void)
+{
+ int tries;
+
+ for(tries = 0; !(superio_readctl() & Inready); tries++){
+ if(tries > 500)
+ return -1;
+ microdelay(2);
+ }
+ return 0;
+}
+
+/*
+ * send a command to the mouse
+ */
+static int
+mousecmd(int cmd)
+{
+ unsigned int c;
+ int tries;
+
+ c = 0;
+ tries = 0;
+ do{
+ if(tries++ > 2)
+ break;
+ if(outready() < 0)
+ break;
+ superio_writectl(0xD4);
+ if(outready() < 0)
+ break;
+ superio_writedata(cmd);
+ if(outready() < 0)
+ break;
+ if(inready() < 0)
+ break;
+ c = superio_readdata();
+ } while(c == 0xFE || c == 0);
+
+ if(c != 0xFA){
+ print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * ask 8042 to enable the use of address bit 20
+ */
+void
+i8042a20(void)
+{
+ outready();
+ superio_writectl(0xD1);
+ outready();
+ superio_writedata(0xDF);
+ outready();
+}
+
+/*
+ * ask 8042 to reset the machine
+ */
+void
+i8042reset(void)
+{
+ ushort *s = (ushort*)(KZERO|0x472);
+ int i, x;
+
+ *s = 0x1234; /* BIOS warm-boot flag */
+
+ /*
+ * newer reset the machine command
+ */
+ outready();
+ superio_writectl(0xFE);
+ outready();
+
+ /*
+ * Pulse it by hand (old somewhat reliable)
+ */
+ x = 0xDF;
+ for(i = 0; i < 5; i++){
+ x ^= 1;
+ outready();
+ superio_writectl(0xD1);
+ outready();
+ superio_writedata(x); /* toggle reset */
+ microdelay(100);
+ }
+}
+
+/*
+ * ps/2 mouse message is three bytes
+ *
+ * byte 0 - 0 0 SDY SDX 1 M R L
+ * byte 1 - DX
+ * byte 2 - DY
+ *
+ * shift & left button is the same as middle button
+ */
+static int
+ps2mouseputc(int c)
+{
+ static short msg[3];
+ static int nb;
+ static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 };
+ int buttons, dx, dy;
+
+ /*
+ * check byte 0 for consistency
+ */
+ if(nb==0 && (c&0xc8)!=0x08)
+ return 0;
+
+ msg[nb] = c;
+ if(++nb == 3) {
+ nb = 0;
+ if(msg[0] & 0x10)
+ msg[1] |= 0xFF00;
+ if(msg[0] & 0x20)
+ msg[2] |= 0xFF00;
+
+ buttons = b[(msg[0]&7) | (shift ? 8 : 0)] | keybuttons;
+ dx = msg[1];
+ dy = -msg[2];
+ mousetrack(buttons, dx, dy, 1);
+ }
+ return 0;
+}
+
+/*
+ * keyboard interrupt
+ */
+void
+kbdintr(void)
+{
+ int s, c, i;
+ static int esc1, esc2;
+ static int caps;
+ static int ctl;
+ static int num;
+ static int collecting, nk;
+ static int alt;
+ static Rune kc[5];
+ int keyup;
+
+ /*
+ * get status
+ */
+ s = superio_readctl();
+ if(!(s&Inready))
+ return;
+
+ /*
+ * get the character
+ */
+ c = superio_readdata();
+
+ /*
+ * if it's the mouse...
+ */
+ if(s & Minready) {
+ ps2mouseputc(c);
+ return;
+ }
+
+ /*
+ * e0's is the first of a 2 character sequence
+ */
+ if(c == 0xe0){
+ esc1 = 1;
+ return;
+ } else if(c == 0xe1){
+ esc2 = 2;
+ return;
+ }
+
+ keyup = c&0x80;
+ c &= 0x7f;
+ if(c > sizeof kbtab){
+/* print("unknown key %ux\n", c|keyup); */
+ return;
+ }
+
+ if(esc1){
+ c = kbtabesc1[c];
+ esc1 = 0;
+ } else if(esc2){
+ esc2--;
+ return;
+ } else if(shift)
+ c = kbtabshift[c];
+ else
+ c = kbtab[c];
+
+ if(caps && c<='z' && c>='a')
+ c += 'A' - 'a';
+
+ /*
+ * keyup only important for shifts
+ */
+ if(keyup){
+ switch(c){
+ case Latin:
+ alt = 0;
+ break;
+ case Shift:
+ shift = 0;
+ break;
+ case Ctrl:
+ ctl = 0;
+ break;
+ }
+ return;
+ }
+
+ /*
+ * normal character
+ */
+ if(!(c & Spec)){
+ if(ctl){
+ if(alt && c == Del)
+ exit(0);
+ c &= 0x1f;
+ }
+ if(!collecting){
+ kbdputc(kbdq, c);
+ return;
+ }
+ kc[nk++] = c;
+ c = latin1(kc, nk);
+ if(c < -1) /* need more keystrokes */
+ return;
+ if(c != -1) /* valid sequence */
+ kbdputc(kbdq, c);
+ else /* dump characters */
+ for(i=0; i<nk; i++)
+ kbdputc(kbdq, kc[i]);
+ nk = 0;
+ collecting = 0;
+ return;
+ } else {
+ switch(c){
+ case Caps:
+ caps ^= 1;
+ return;
+ case Num:
+ num ^= 1;
+ return;
+ case Shift:
+ shift = 1;
+ return;
+ case Latin:
+ alt = 1;
+ collecting = 1;
+ nk = 0;
+ return;
+ case Ctrl:
+ ctl = 1;
+ return;
+ }
+ }
+ kbdputc(kbdq, c);
+}
+
+/*
+ * set up a ps2 mouse
+ */
+static void
+ps2mouse(void)
+{
+ int x;
+
+ /* enable kbd/mouse xfers and interrupts */
+ x = splhi();
+ ccc &= ~Cmousedis;
+ ccc |= Cmouseint;
+ if(outready() < 0)
+ print("mouse init failed\n");
+ superio_writectl(0x60);
+ if(outready() < 0)
+ print("mouse init failed\n");
+ superio_writedata(ccc);
+ if(outready() < 0)
+ print("mouse init failed\n");
+ superio_writectl(0xA8);
+ if(outready() < 0){
+ splx(x);
+ return;
+ }
+
+ /* make mouse streaming, enabled */
+ mousecmd(0xEA);
+ mousecmd(0xF4);
+ splx(x);
+}
+
+void
+kbdinit(void)
+{
+ int c;
+
+ kbdq = qopen(4*1024, 0, 0, 0);
+ qnoblock(kbdq, 1);
+
+ /* wait for a quiescent controller */
+ while((c = superio_readctl()) & (Outbusy | Inready))
+ if(c & Inready)
+ superio_readdata();
+
+ /* get current controller command byte */
+ superio_writectl(0x20);
+ if(inready() < 0){
+ print("kbdinit: can't read ccc\n");
+ ccc = 0;
+ } else
+ ccc = superio_readdata();
+
+ /* enable kbd xfers and interrupts */
+ /* disable mouse */
+ ccc &= ~Ckbddis;
+ ccc |= Csf | Ckbdint | Cscs1 | Cmousedis;
+ if(outready() < 0)
+ print("kbd init failed\n");
+ superio_writectl(0x60);
+ if(outready() < 0)
+ print("kbd init failed\n");
+ superio_writedata(ccc);
+ outready();
+
+ /* Assume ps2 mouse */
+ ps2mouse();
+}
diff --git a/os/js/l.s b/os/js/l.s
new file mode 100644
index 00000000..b8eb8e0c
--- /dev/null
+++ b/os/js/l.s
@@ -0,0 +1,560 @@
+#include "mem.h"
+
+#define SYSPSR (PSREF|PSRET|PSRSUPER|SPL(15))
+#define NOOP ORN R0, R0; ORN R0, R0; ORN R0, R0; ORN R0, R0; ORN R0, R0
+#define FLUSH WORD $0x81d80000 /* IFLUSH (R0) */
+
+#define MMUASI 0x4
+#define TLBASI 0x3
+#define IFLUSHASI 0x36
+#define DFLUSHASI 0x37
+#define PHYSASI 0x20 /* MMU bypass */
+#define CTLASI 0x20 /* 0x2F on bigger sun4M */
+
+TEXT start(SB), $-4
+ /* get virtual, fast */
+
+ /* copy ROM's L1 page table entries, mapping VA:0 and VA:KZERO to PA:0 */
+ MOVW $setSB(SB), R2
+
+ MOVW $CTPR, R7
+ MOVW (R7, MMUASI), R5
+ SLL $4, R5, R5
+ MOVW (R5, PHYSASI), R5 /* context table entry 0 */
+ SRL $4, R5, R5
+ SLL $8, R5, R5 /* to physical pointer */
+
+ MOVW $(((KZERO>>24)&0xFF)*4), R4 /* KZERO base in level 1 ptab */
+ MOVW (R5, PHYSASI), R6 /* L1 region 0 set by boot */
+ ADD R4,R5,R10
+ MOVW R6, (R10, PHYSASI) /* map KZERO */
+
+ ADD $4, R5
+ MOVW (R5, PHYSASI), R6
+ ADD R4, R5, R10
+ MOVW R6, (R10, PHYSASI) /* map KZERO+16Mbytes */
+
+ /* now mapped correctly. jmpl to where we want to be */
+
+ MOVW $startvirt(SB), R7
+ JMPL (R7)
+ RETURN /* can't get here */
+
+TEXT startvirt(SB), $-4
+ MOVW $edata(SB),R9
+ MOVW $end(SB),R10
+clrbss:
+ MOVW R0,(R9)
+ ADD $4, R9
+ CMP R9, R10
+ BNE clrbss
+ NOOP
+
+ MOVW $rom(SB), R7
+ MOVW R8, (R7) /* romvec passed in %i0==R8 */
+
+ /* turn off the cache but ensure ITBR enabled */
+ MOVW (R0, MMUASI), R7
+ ANDN $(ENABCACHE|ITBRDISABLE), R7
+ MOVW R7, (R0, MMUASI)
+
+ FLUSH
+ NOOP
+
+
+ MOVW $MID, R7 /* disable Sbus DMA */
+ MOVW (R7, PHYSASI), R8
+ ANDN $(0x1E<<15), R8
+ MOVW R8, (R7, PHYSASI)
+
+ MOVW $BOOTSTACK, R1
+
+ MOVW $(SPL(0xF)|PSREF|PSRSUPER), R7
+ OR $PSRET, R7 /* allow rom use while debugging ... */
+ MOVW R7, PSR
+
+ MOVW $(0x35<<22), R7 /* NVM OFM DZM NS */
+ MOVW R7, fsr+0(SB)
+ MOVW $fsr+0(SB), R8
+ MOVW (R8), FSR
+ FMOVD $0.5, F26 /* 0.5 -> F26 */
+ FSUBD F26, F26, F24 /* 0.0 -> F24 */
+ FADDD F26, F26, F28 /* 1.0 -> F28 */
+ FADDD F28, F28, F30 /* 2.0 -> F30 */
+
+ FMOVD F24, F0
+ FMOVD F24, F2
+ FMOVD F24, F4
+ FMOVD F24, F6
+ FMOVD F24, F8
+ FMOVD F24, F10
+ FMOVD F24, F12
+ FMOVD F24, F14
+ FMOVD F24, F16
+ FMOVD F24, F18
+ FMOVD F24, F20
+ FMOVD F24, F22
+
+ MOVW $mach0(SB), R(MACH)
+/* MOVW $0x8, R7 /**/
+ MOVW R0, WIM
+
+ JMPL main(SB)
+ MOVW (R0), R0
+ RETURN
+
+TEXT call0(SB), $-4
+ JMPL (R0)
+ JMPL (R0)
+ JMPL (R0)
+ JMPL (R0)
+ RETURN
+
+TEXT getcinfo(SB), $0
+ MOVW (R7, 0x0C), R7
+ RETURN
+
+TEXT flushiline(SB), $0
+ MOVW R0, (R7, 0x0C)
+ NOOP
+ RETURN
+
+TEXT flushdline(SB), $0
+ MOVW R0, (R7, 0x0E)
+ NOOP
+ RETURN
+
+TEXT getphys(SB), $0
+
+ MOVW (R7, PHYSASI), R7
+ RETURN
+
+TEXT putphys(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, PHYSASI)
+ RETURN
+
+TEXT getrmmu(SB), $0
+
+ MOVW (R7, MMUASI), R7
+ RETURN
+
+TEXT putrmmu(SB), $0
+
+ MOVW 4(FP), R8
+ MOVW R8, (R7, MMUASI)
+ RETURN
+
+TEXT getpcr(SB), $0
+
+ MOVW (R0, MMUASI), R7
+ RETURN
+
+TEXT setpcr(SB), $0
+
+ MOVW R7, (R0, MMUASI)
+ FLUSH /* `strongly recommended' after STA to PCR */
+ NOOP
+ RETURN
+
+TEXT _tas(SB), $0
+
+ TAS (R7), R7 /* LDSTUB, thank you ken */
+ RETURN
+
+#ifdef notdef
+TEXT _tas(SB), $0 /* it seems we must be splhi */
+
+ MOVW PSR, R8
+ MOVW $SYSPSR, R9
+ MOVW R9, PSR
+ NOOP
+ TAS (R7), R7 /* LDSTUB, thank you ken */
+ MOVW R8, PSR
+ NOOP
+ RETURN
+#endif
+
+TEXT softtas(SB), $0 /* all software; avoid LDSTUB */
+
+ MOVW PSR, R8
+ MOVW $SYSPSR, R9
+ MOVW R9, PSR
+ NOOP
+ MOVB (R7), R10
+ CMP R10, R0
+ BE gotit
+ /* cache is write through, no need to flush */
+ MOVW $0xFF, R7
+ MOVW R8, PSR
+ NOOP
+ RETURN
+
+gotit:
+ MOVW $0xFF, R10
+ MOVB R10, (R7)
+ /* cache is write through, no need to flush */
+ MOVW $0, R7
+ MOVW R8, PSR
+ NOOP
+ RETURN
+
+TEXT spllo(SB), $0
+
+ MOVW PSR, R7
+ MOVW R7, R10
+ ANDN $SPL(15), R10
+ MOVW R10, PSR
+ NOOP
+ RETURN
+
+TEXT splhi(SB), $0
+
+ MOVW R15, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW PSR, R7
+ MOVW R7, R10
+ OR $SPL(15), R10
+ MOVW R10, PSR
+ NOOP
+ RETURN
+
+TEXT splxpc(SB), $0
+
+ MOVW R7, PSR /* BUG: book says this is buggy */
+ NOOP
+ RETURN
+
+
+TEXT splx(SB), $0
+
+ MOVW R15, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW R7, PSR /* BUG: book says this is buggy */
+ NOOP
+ RETURN
+TEXT spldone(SB), $0
+
+ RETURN
+
+TEXT rfnote(SB), $0
+
+ MOVW R7, R1 /* 1st arg is &uregpointer */
+ ADD $4, R1 /* point at ureg */
+ JMP restore
+
+TEXT traplink(SB), $-4
+
+ /* R8 to R23 are free to play with */
+ /* R17 contains PC, R18 contains nPC */
+ /* R19 has PSR loaded from vector code */
+
+ ANDCC $PSRPSUPER, R19, R0
+ BE usertrap
+
+kerneltrap:
+ /*
+ * Interrupt or fault from kernel
+ */
+ ANDN $7, R1, R20 /* dbl aligned */
+ MOVW R1, (0-(4*(32+6))+(4*1))(R20) /* save R1=SP */
+ /* really clumsy: store these in Ureg so can be restored below */
+ MOVW R2, (0-(4*(32+6))+(4*2))(R20) /* SB */
+ MOVW R5, (0-(4*(32+6))+(4*5))(R20) /* USER */
+ MOVW R6, (0-(4*(32+6))+(4*6))(R20) /* MACH */
+ SUB $(4*(32+6)), R20, R1
+
+trap1:
+ MOVW Y, R20
+ MOVW R20, (4*(32+0))(R1) /* Y */
+ MOVW TBR, R20
+ MOVW R20, (4*(32+1))(R1) /* TBR */
+ AND $~0x1F, R19 /* force CWP=0 */
+ MOVW R19, (4*(32+2))(R1) /* PSR */
+ MOVW R18, (4*(32+3))(R1) /* nPC */
+ MOVW R17, (4*(32+4))(R1) /* PC */
+ MOVW R0, (4*0)(R1)
+ MOVW R3, (4*3)(R1)
+ MOVW R4, (4*4)(R1)
+ MOVW R7, (4*7)(R1)
+ RESTORE R0, R0
+ /* now our registers R8-R31 are same as before trap */
+ /* save registers two at a time */
+ MOVD R8, (4*8)(R1)
+ MOVD R10, (4*10)(R1)
+ MOVD R12, (4*12)(R1)
+ MOVD R14, (4*14)(R1)
+ MOVD R16, (4*16)(R1)
+ MOVD R18, (4*18)(R1)
+ MOVD R20, (4*20)(R1)
+ MOVD R22, (4*22)(R1)
+ MOVD R24, (4*24)(R1)
+ MOVD R26, (4*26)(R1)
+ MOVD R28, (4*28)(R1)
+ MOVD R30, (4*30)(R1)
+ /* SP and SB and u and m are already set; away we go */
+ MOVW R1, R7 /* pointer to Ureg */
+ SUB $8, R1
+ MOVW $SYSPSR, R8
+ MOVW R8, PSR
+ NOOP
+ JMPL trap(SB)
+
+ ADD $8, R1
+restore:
+ MOVW (4*(32+2))(R1), R8 /* PSR */
+ MOVW R8, PSR
+ NOOP
+
+ MOVD (4*30)(R1), R30
+ MOVD (4*28)(R1), R28
+ MOVD (4*26)(R1), R26
+ MOVD (4*24)(R1), R24
+ MOVD (4*22)(R1), R22
+ MOVD (4*20)(R1), R20
+ MOVD (4*18)(R1), R18
+ MOVD (4*16)(R1), R16
+ MOVD (4*14)(R1), R14
+ MOVD (4*12)(R1), R12
+ MOVD (4*10)(R1), R10
+ MOVD (4*8)(R1), R8
+ SAVE R0, R0
+ MOVD (4*6)(R1), R6
+ MOVD (4*4)(R1), R4
+ MOVD (4*2)(R1), R2
+ MOVW (4*(32+0))(R1), R20 /* Y */
+ MOVW R20, Y
+ MOVW (4*(32+4))(R1), R17 /* PC */
+ MOVW (4*(32+3))(R1), R18 /* nPC */
+ MOVW (4*1)(R1), R1 /* restore R1=SP */
+ RETT R17, R18
+
+usertrap:
+ /*
+ * Interrupt or fault from user
+ */
+ MOVW R1, R8
+ MOVW R2, R9
+ MOVW $setSB(SB), R2
+ MOVW $(USERADDR+BY2PG), R1
+ MOVW R8, (0-(4*(32+6))+(4*1))(R1) /* save R1=SP */
+ MOVW R9, (0-(4*(32+6))+(4*2))(R1) /* save R2=SB */
+ MOVW R5, (0-(4*(32+6))+(4*5))(R1) /* save R5=USER */
+ MOVW R6, (0-(4*(32+6))+(4*6))(R1) /* save R6=MACH */
+ MOVW $USERADDR, R(USER)
+ MOVW $mach0(SB), R(MACH)
+ SUB $(4*(32+6)), R1
+ JMP trap1
+
+TEXT puttbr(SB), $0
+ MOVW R7, TBR
+ NOOP
+ RETURN
+
+TEXT gettbr(SB), $0
+
+ MOVW TBR, R7
+ RETURN
+
+TEXT r1(SB), $0
+
+ MOVW R1, R7
+ RETURN
+
+TEXT getwim(SB), $0
+
+ MOVW WIM, R7
+ RETURN
+
+TEXT setlabel(SB), $0
+
+ MOVW R1, (R7)
+ MOVW R15, 4(R7)
+ MOVW $0, R7
+ RETURN
+
+TEXT gotolabel(SB), $0
+
+ MOVW (R7), R1
+ MOVW 4(R7), R15
+ MOVW $1, R7
+ RETURN
+
+TEXT getpsr(SB), $0
+
+ MOVW PSR, R7
+ RETURN
+
+TEXT setpsr(SB), $0
+
+ MOVW R7, PSR
+ NOOP
+ RETURN
+
+TEXT savefpregs(SB), $0
+
+ MOVD F0, (0*4)(R7)
+ MOVD F2, (2*4)(R7)
+ MOVD F4, (4*4)(R7)
+ MOVD F6, (6*4)(R7)
+ MOVD F8, (8*4)(R7)
+ MOVD F10, (10*4)(R7)
+ MOVD F12, (12*4)(R7)
+ MOVD F14, (14*4)(R7)
+ MOVD F16, (16*4)(R7)
+ MOVD F18, (18*4)(R7)
+ MOVD F20, (20*4)(R7)
+ MOVD F22, (22*4)(R7)
+ MOVD F24, (24*4)(R7)
+ MOVD F26, (26*4)(R7)
+ MOVD F28, (28*4)(R7)
+ MOVD F30, (30*4)(R7)
+ MOVW FSR, (34*4)(R7)
+
+ MOVW PSR, R8
+ ANDN $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT savefsr(SB), $0
+ MOVW FSR, 0(R7)
+ RETURN
+
+TEXT restfsr(SB), $0
+ MOVW 0(R7), FSR
+ RETURN
+
+
+TEXT fpinit(SB), $0
+ MOVW PSR, R8
+ OR $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT disabfp(SB), $0
+
+ MOVW PSR, R8
+ ANDN $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT restfpregs(SB), $0
+
+ MOVW PSR, R8
+ OR $PSREF, R8
+ MOVW R8, PSR
+
+ NOOP /* wait for PSR to quiesce */
+
+
+ MOVD (0*4)(R7), F0
+ MOVD (2*4)(R7), F2
+ MOVD (4*4)(R7), F4
+ MOVD (6*4)(R7), F6
+ MOVD (8*4)(R7), F8
+ MOVD (10*4)(R7), F10
+ MOVD (12*4)(R7), F12
+ MOVD (14*4)(R7), F14
+ MOVD (16*4)(R7), F16
+ MOVD (18*4)(R7), F18
+ MOVD (20*4)(R7), F20
+ MOVD (22*4)(R7), F22
+ MOVD (24*4)(R7), F24
+ MOVD (26*4)(R7), F26
+ MOVD (28*4)(R7), F28
+ MOVD (30*4)(R7), F30
+ MOVW (34*4)(R7), FSR
+
+ ANDN $PSREF, R8
+ MOVW R8, PSR
+ RETURN
+
+TEXT getfpq(SB), $0
+
+ MOVW R7, R8 /* must be D aligned */
+ MOVW $fsr+0(SB), R9
+ MOVW $0, R7
+getfpq1:
+ MOVW FSR, (R9)
+ MOVW (R9), R10
+ ANDCC $(1<<13), R10 /* queue not empty? */
+ BE getfpq2
+ MOVW (R8), R0 /* SS2 bug fix */
+ MOVD FQ, (R8)
+ ADD $1, R7
+ ADD $8, R8
+ BA getfpq1
+getfpq2:
+ RETURN
+
+TEXT getfsr(SB), $0
+ MOVW $fsr+0(SB), R7
+ MOVW FSR, (R7)
+ MOVW (R7), R7
+ RETURN
+
+TEXT clearftt(SB), $0
+ MOVW R7, fsr+0(SB)
+ MOVW $fsr+0(SB), R7
+ MOVW (R7), FSR
+ FMOVF F0, F0
+ RETURN
+
+TEXT getcallerpc(SB), $-4
+ MOVW 0(R1), R7
+ RETURN
+
+TEXT icflush(SB), $-4
+JMPL (R0)
+ MOVW R0, (R0, IFLUSHASI)
+ FLUSH /* flush prefetch */
+ NOOP
+ RETURN
+
+TEXT dcflush(SB), $0
+
+ MOVW R0, (R0, DFLUSHASI) /* can only flush the lot */
+ RETURN
+
+TEXT flushtlbpage(SB), $0
+
+ AND $(~(BY2PG-1)), R7 /* type 0 */
+ MOVW R0, (R7, TLBASI)
+ RETURN
+
+TEXT flushtlbctx(SB), $0
+
+ MOVW $0x300, R7
+ MOVW R0, (R7, TLBASI)
+ RETURN
+
+TEXT flushtlb(SB), $0
+
+ MOVW $0x400, R7
+ MOVW R0, (R7, TLBASI)
+ RETURN
+
+GLOBL mach0+0(SB), $MACHSIZE
+GLOBL fsr+0(SB), $BY2WD
+
+/*
+ * Interface to OPEN BOOT ROM. Must save and restore state because
+ * of different calling conventions. We don't use it, but it's here
+ * for reference..
+ */
+
+TEXT call_openboot(SB), $16
+ MOVW R1, R14 /* save my SP in their SP */
+ MOVW R2, sb-4(SP)
+ MOVW R(MACH), mach-8(SP)
+ MOVW R(USER), user-12(SP)
+ MOVW param1+4(FP), R8
+ MOVW param2+8(FP), R9
+ MOVW param3+12(FP), R10
+ MOVW param4+16(FP), R11
+ JMPL (R7)
+ MOVW R14, R1 /* restore my SP */
+ MOVW user-12(SP), R(USER)
+ MOVW mach-8(SP), R(MACH)
+ MOVW sb-4(SP), R2
+ MOVW R8, R7 /* move their return value into mine */
+ RETURN
diff --git a/os/js/main.c b/os/js/main.c
new file mode 100644
index 00000000..d539ca11
--- /dev/null
+++ b/os/js/main.c
@@ -0,0 +1,564 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "version.h"
+
+Mach *m = &mach0;
+Proc *up;
+int cflag;
+
+ulong cachetable[1024];
+
+Sysint *sysintr;
+struct {
+ uchar format;
+ uchar type;
+ uchar ea[6];
+ uchar pad[32-8];
+} idprom;
+
+int cpuserver;
+ulong bank[8];
+uchar mempres[64];
+char fbstr[32];
+ulong fbslot;
+int usecg6;
+Label catch;
+uchar *sp;
+
+int cold=1;
+
+typedef struct Sysparam Sysparam;
+struct Sysparam
+{
+ int id; /* Model type from id prom */
+ char *name; /* System name */
+ char ss2; /* Is Sparcstation 2? */
+ int vacsize; /* Cache size */
+ int vacline; /* Cache line size */
+ int ncontext; /* Number of MMU contexts */
+ char cachebug; /* Machine needs cache bug work around */
+ int nbank; /* Number of banks of memory */
+ int banksize; /* Maximum Mbytes per bank */
+ int pcnt; /* percent of mem for kernel? */
+}
+sysparam[] =
+{
+ { 0xFF, "unknown Sun4M",0, 0, 0, 64, 0, 4, 32 ,0},
+ { 0x80, "JavaStation uSparcII",0, 0, 0, 256, 0, 4, 32 ,2},
+ { 0 }
+};
+Sysparam *sparam;
+
+void
+doc(char *m)
+{
+ print("%s\n", m);
+}
+
+static void poolsizeinit(void);
+
+void
+main(void)
+{
+
+
+ machinit();
+ trapinit();
+ quotefmtinstall();
+ confinit();
+ xinit();
+ mmuinit();
+ intrinit();
+ clockinit();
+ printinit();
+ screeninit();
+ ioinit();
+ doc("ioinit...");
+ ns16552install();
+ poolsizeinit();
+ doc("ns16552install...");
+ kbdinit();
+ doc("kbdinit...");
+ cacheinit();
+ doc("cacheinit...");
+ procinit();
+ doc("procinit...");
+ putphys(MID, 0x1F<<16); /* enable arbitration */
+ links();
+ doc("links");
+ chandevreset();
+ doc("chandevreset...");
+
+ print("\nInferno Operating System\n");
+ print("%s-%s \n\n",VERSION, conffile);
+ print("JIT Compilation Mode = %d\n",cflag);
+
+ userinit();
+ doc("userinit...");
+
+ /* clear pending processor interrupts */
+ putphys(PROCINTCLR, (~0<<17)|(1<<15));
+ print("berore schedinit\n");
+ schedinit();
+}
+
+extern int main_pool_pcnt;
+extern int heap_pool_pcnt;
+extern int image_pool_pcnt;
+
+static void
+poolsizeinit(void)
+{
+ ulong nb = conf.npage*BY2PG;
+
+ print("Total memory available: %ld K\n",nb/1024);
+ poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
+ poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
+ poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
+}
+
+void
+intrinit(void)
+{
+ KMap *k;
+
+ /* clear fault status */
+ getphys(AFSR);
+
+ k = kmappa(SYSINTR, PTEIO|PTENOCACHE);
+ sysintr = (Sysint*)VA(k);
+
+ /* mask all interrupts */
+ sysintr->maskset = ~0;
+
+ /* allow these */
+ sysintr->maskclr=MaskAllIntr|MEIntr|MSIIntr|EMCIntr|EtherIntr|KbdIntr;
+
+ /* clear pending processor interrupts */
+ putphys(PROCINTCLR, (~0<<17)|(1<<15));
+
+}
+
+void
+systemreset(void)
+{
+ microdelay(200);
+ putphys(SYSCTL, getphys(SYSCTL)|1); /* power on reset */
+}
+
+void
+machinit(void)
+{
+ memset(m, 0, sizeof(Mach));
+}
+
+void
+ioinit(void)
+{
+ KMap *k;
+ uchar *sindex; /* superio index */
+ uchar *sdata; /* superio data */
+ uchar *mkctl; /* superio mouse/kbd ctl register */
+ uchar *mkdata; /* superio mouse/kbd data register */
+
+
+ /* enable the uart's on the superio chip */
+ k = kmappa(SUPERIO_PHYS_PAGE, PTEIO|PTENOCACHE);
+ sindex = (uchar*)(VA(k)+SUPERIO_INDEX_OFFSET);
+ sdata = (uchar*)(VA(k)+SUPERIO_DATA_OFFSET);
+ mkdata = (uchar*)(VA(k)+SUPERIO_MOUSE_KBD_DATA_PORT);
+ mkctl = (uchar*)(VA(k)+SUPERIO_MOUSE_KBD_CTL_PORT);
+
+ superioinit(VA(k),sindex,sdata,mkctl,mkdata);
+ doc("superioinit...");
+}
+
+void
+init0(void)
+{
+ Osenv *o;
+
+ up->nerrlab = 0;
+
+ print("before spllo");
+
+ spllo();
+
+ print("Sun Sparc %s\n", sparam->name);
+ print("bank 0: %ldM 1: %ldM\n", bank[0], bank[1]);
+ print("frame buffer id %lux slot %ld %s\n",conf.monitor,fbslot,fbstr);
+
+
+ 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();
+ poperror();
+ disinit("/osinit.dis");
+}
+
+
+void
+userinit(void)
+{
+ Proc *p;
+ Osenv *o;
+
+ p = newproc();
+ o = p->env;
+
+ o->fgrp = newfgrp(nil);
+ o->pgrp = newpgrp();
+ kstrdup(&o->user, eve);
+ strcpy(p->text,"interp");
+
+ p->fpstate = FPINIT;
+ fpinit();
+
+ /*
+ * Kernel Stack
+ */
+ p->sched.pc = (ulong)init0;
+ p->sched.sp = (ulong)p->kstack+KSTACK-8;
+ p->sched.sp &= ~7; /* SP must be 8-byte aligned */
+
+ ready(p);
+}
+
+uchar *
+pusharg(char *p)
+{
+ int n;
+
+ n = strlen(p)+1;
+ sp -= n;
+ memmove(sp, p, n);
+ return sp;
+}
+
+void
+exit(int ispanic)
+{
+ USED(ispanic);
+
+ spllo();
+ print("cpu exiting\n");
+
+ /* Shutdown running devices */
+ chandevshutdown();
+
+ microdelay(500);
+ systemreset();
+}
+
+void
+reboot(void)
+{
+ exit(0);
+}
+
+void
+halt(void)
+{
+ spllo();
+ print("cpu halted\n");
+ microdelay(500);
+ for(;;);
+}
+
+int
+probemem(ulong addr)
+{
+ ulong pcr, save0;
+ int works;
+
+ save0 = getphys(0);
+ pcr = getpcr()|NOFAULT;
+ works = 0;
+ setpcr(pcr & ~MEMPCHECK);
+ putphys(addr, ~addr);
+ if(addr)
+ putphys(0, 0x89ABCDEF);
+ if(getphys(addr) == ~addr){
+ setpcr(pcr);
+ putphys(addr, addr);
+ if(addr)
+ putphys(0, 0x89ABCDEF);
+ if(getphys(addr) == addr)
+ works = 1;
+ }
+ setpcr(pcr & ~NOFAULT);
+ putphys(0, save0);
+ getphys(AFSR); /* clear fault status */
+ getrmmu(SFSR); /* clear fault status */
+ return works;
+}
+
+/*
+ * this assumes that if a bank is not empty,
+ * its first slot is filled.
+ *
+ * ../port/alloc.c and ../port/page.c
+ * need to be changed to support more than two banks.
+ */
+void
+scanbank(ulong base, uchar *mempres, int n)
+{
+ int i;
+ ulong addr, npg;
+
+ npg = 0;
+ for(i=0; i<n; i++){
+ mempres[i] = 0;
+ addr = base + i*MB;
+ if(!probemem(addr))
+ break;
+ if(addr != base) {
+ /* check for mirrors */
+ putphys(addr, addr);
+ if(getphys(base) == addr)
+ break;
+ }
+ mempres[i] = 1;
+ npg += MB/BY2PG;
+ }
+ if(npg){
+ if(conf.npage0 == 0){
+ conf.base0 = base;
+ conf.npage0 = npg;
+ }else if(conf.npage1 < npg){
+ conf.base1 = base;
+ conf.npage1 = npg;
+ }
+ }
+}
+
+void
+physcopyin(void *d, ulong s, int n)
+{
+ int i, j;
+ ulong w;
+
+ for(i=0; i<n; i+=sizeof(ulong)) {
+ w = getphys(s+i);
+ j = n-i;
+ if(j > sizeof(ulong))
+ j = sizeof(ulong);
+ memmove((uchar*)d+i, &w, j);
+ }
+}
+
+Conf conf;
+
+void
+confinit(void)
+{
+ ulong i;
+ ulong ktop;
+
+ conf.monitor = 0;
+
+ conf.nmach = 1;
+ if(conf.nmach > MAXMACH)
+ panic("confinit");
+
+ /* fetch ID prom */
+ physcopyin(&idprom, NVR_PHYS+IDOFF, sizeof(idprom));
+ if(idprom.format!=1 || (idprom.type&0xF0)!=0x80)
+ *(ulong*)~0 = 0; /* not a new generation sparc; die! */
+
+ for(sparam = sysparam; sparam->id; sparam++)
+ if(sparam->id == idprom.type)
+ break;
+
+ /* First entry in the table is the default */
+ if(sparam->id == 0)
+ sparam = sysparam;
+
+ conf.ss2 = sparam->ss2;
+ conf.vacsize = sparam->vacsize;
+ conf.vaclinesize = sparam->vacline;
+ conf.ncontext = sparam->ncontext;
+ conf.ss2cachebug = sparam->cachebug;
+
+ for(i=0; i<sparam->nbank; i++)
+ if(probemem(i*sparam->banksize*MB))
+ scanbank(i*sparam->banksize*MB, mempres,
+ sparam->banksize);
+
+ bank[0] = conf.npage0*BY2PG/MB;
+ bank[1] = conf.npage1*BY2PG/MB;
+
+ if(bank[1] == 0){
+ /*
+ * This split of memory into 2 banks fools the allocator into
+ * allocating low memory pages from bank 0 for the ethernet
+ * since it has only a 24bit address *counter.
+ * NB. Suns must have at LEAST 8Mbytes.
+ */
+ conf.npage1 = conf.npage0 - (8*MB)/BY2PG;
+ conf.base1 = conf.base0 + 8*MB;
+ conf.npage0 = (8*MB)/BY2PG;
+ bank[1] = bank[0]-8;
+ bank[0] = 8;
+ }
+
+ conf.npage = conf.npage0+conf.npage1;
+
+ ktop = PGROUND((ulong)end);
+ ktop = PADDR(ktop);
+ conf.npage0 -= ktop/BY2PG;
+ conf.base0 += ktop;
+
+ conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+ conf.copymode = 0; /* copy on write */
+ conf.arp = 32;
+ conf.ialloc = (((conf.npage*(100-sparam->pcnt))/100)/2)*BY2PG;
+
+ eve = strdup("inferno");
+
+#ifdef notdef
+ /* XXX - Eric - Autoconfigure memory */
+ /* XXX - Tad: 8 eigths, total... */
+ mainmem->maxsize = (conf.npage*BY2PG)/8;
+ heapmem->maxsize = ((conf.npage*BY2PG)*5)/8;
+ imagmem->maxsize = ((conf.npage*BY2PG)*2)/8;
+#endif
+}
+
+/*
+ * set up the lance
+ */
+void
+lancesetup(Lance *lp)
+{
+ KMap *k;
+ DMAdev *dma;
+ ulong pa, va;
+ int i;
+
+ k = kmappa(ETHER, PTEIO|PTENOCACHE);
+ lp->rdp = (void*)(VA(k)+0);
+ lp->rap = (void*)(VA(k)+2);
+ for(i=0; i<6; i++)
+ lp->ea[i] = idprom.ea[i];
+
+ lp->lognrrb = 7;
+ lp->logntrb = 7;
+ lp->nrrb = 1<<lp->lognrrb;
+ lp->ntrb = 1<<lp->logntrb;
+ lp->sep = 1;
+ lp->busctl = BSWP | ACON | BCON;
+
+ /*
+ * Allocate area for lance init block and descriptor rings
+ */
+ pa = PADDR(xspanalloc(BY2PG, BY2PG, 0));
+
+ /* map at LANCESEGM */
+ va = kmapdma(pa, BY2PG);
+ lp->lanceram = (ushort*)va;
+ lp->lm = (Lancemem*)va;
+
+ /*
+ * Allocate space in host memory for the io buffers.
+ */
+ i = (lp->nrrb+lp->ntrb)*sizeof(Lancepkt);
+ i = (i+(BY2PG-1))/BY2PG;
+ pa = PADDR(xspanalloc(i*BY2PG, BY2PG, 0));
+ va = kmapdma(pa, i*BY2PG);
+
+ lp->lrp = (Lancepkt*)va;
+ lp->rp = (Lancepkt*)va;
+ lp->ltp = lp->lrp+lp->nrrb;
+ lp->tp = lp->rp+lp->nrrb;
+
+ k = kmappa(DMA, PTEIO|PTENOCACHE);
+ dma = (DMAdev*)VA(k);
+ dma->base = 0xff;
+
+ /*
+ * for now, let's assume the ROM has left the results of its
+ * auto-sensing
+ */
+#ifdef notdef
+ if(dma->ecsr & E_TP_select)
+ print("Twisted pair ethernet\n");
+ else
+ print("AUI ethernet\n");
+#endif
+ microdelay(1);
+ dma->ecsr |= E_Int_en|E_Invalidate|E_Dsbl_wr_inval|E_Dsbl_rd_drn;
+ microdelay(1);
+}
+
+static void
+linkproc(void)
+{
+ spllo();
+ (*up->kpfun)(up->arg);
+}
+
+void
+kprocchild(Proc *p, void (*func)(void*), void *arg)
+{
+ p->sched.pc = (ulong)linkproc;
+ p->sched.sp = (ulong)p->kstack+KSTACK-8;
+
+ p->kpfun = func;
+ p->arg = arg;
+}
+
+
+void
+FPsave(void *f) /* f should be a FPenv */
+{
+ savefsr(f);
+}
+
+void
+FPrestore(void *f) /* f should be a FPenv */
+{
+ restfsr(f);
+}
+
+void
+fpsave(FPU *f)
+{
+ savefpregs( f );
+}
+
+void
+fprestore(FPU *f)
+{
+ restfpregs(f);
+}
+
+int
+islo(void)
+{
+ int val;
+ val = (getpsr()&SPL(15)) == 0;
+
+ return val;
+}
+
+void
+setvec(void)
+{
+ /* XXX - Tad: eventually implement this */
+}
diff --git a/os/js/mem.h b/os/js/mem.h
new file mode 100644
index 00000000..f17c1782
--- /dev/null
+++ b/os/js/mem.h
@@ -0,0 +1,149 @@
+/*
+ * 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 MAXMACH 1 /* max # cpus system can run */
+
+/*
+ * Time
+ */
+#define HZ 50 /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
+
+/*
+ * PSR bits
+ */
+#define PSREC 0x00002000
+#define PSREF 0x00001000
+#define PSRSUPER 0x00000080
+#define PSRPSUPER 0x00000040
+#define PSRET 0x00000020
+#define SPL(n) (n<<8)
+
+/*
+ * Magic registers
+ */
+
+#define MACH 6 /* R6 is m-> */
+#define USER 5 /* R5 is u-> */
+
+/*
+ * Fundamental addresses
+ */
+
+#define USERADDR 0xE0000000
+#define UREGADDR (USERADDR+BY2PG-((32+6)*BY2WD))
+#define BOOTSTACK (KTZERO-0*BY2PG)
+#define TRAPS (KTZERO-2*BY2PG)
+
+/*
+ * Reference MMU registers (ASI 4)
+ */
+#define PCR 0x000
+#define CTPR 0x100
+#define CXR 0x200
+#define SFSR 0x300
+#define SFAR 0x400
+
+/*
+ * Processor Control Register
+ */
+#define ITBRDISABLE (1<<16)
+#define BOOTMODE (1<<14) /* `must be cleared for normal operation' */
+#define MEMPCHECK (1<<12) /* check parity */
+#define ENABCACHE (3<<8) /* I & D caches */
+#define NOFAULT (1<<1) /* no fault */
+
+/*
+ * special MMU regions
+ * DMA segment for SBus DMA mapping via I/O MMU (hardware fixes location)
+ * the frame buffer is mapped as one MMU region (16 Mbytes)
+ * IO segments for device register pages etc.
+ */
+#define DMARANGE 0
+#define DMASEGSIZE ((16*MB)<<DMARANGE)
+#define DMASEGBASE (0 - DMASEGSIZE)
+#define FBSEGSIZE (1*(16*MB)) /* multiples of 16*MB */
+#define FBSEGBASE (DMASEGBASE - DMASEGSIZE)
+#define IOSEGSIZE (16*MB)
+#define IOSEGBASE (FBSEGBASE - IOSEGSIZE)
+
+/*
+ * MMU entries
+ */
+#define PTPVALID 1 /* page table pointer */
+#define PTEVALID 2 /* page table entry */
+#define PTERONLY (2<<2) /* read/execute */
+#define PTEWRITE (3<<2) /* read/write/execute */
+#define PTEKERNEL (4<<2) /* execute only */
+#define PTENOCACHE (0<<7)
+#define PTECACHE (1<<7)
+#define PTEACCESS (1<<5)
+#define PTEMODIFY (1<<6)
+#define PTEMAINMEM 0
+#define PTEIO 0
+#define PTEPROBEMEM (PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM)
+#define PTEUNCACHED PTEACCESS /* use as software flag for putmmu */
+
+#define NTLBPID 64 /* limited by microsparc hardware contexts */
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 128
+
+#define INVALIDPTE 0
+#define PPN(pa) (((ulong)(pa)>>4)&0x7FFFFF0)
+#define PPT(pn) ((ulong*)KADDR((((ulong)(pn)&~0xF)<<4)))
+
+/*
+ * Virtual addresses
+ */
+#define VTAG(va) ((va>>22)&0x03F)
+#define VPN(va) ((va>>13)&0x1FF)
+
+/*
+ * Address spaces
+ */
+#define KZERO 0xE0000000 /* base of kernel address space */
+#define KTZERO (KZERO+4*BY2PG) /* first address in kernel text */
+#define KSTACK 8192 /* size of kernel stack */
+
+#define MACHSIZE 4096
+
+/*
+ * control registers in physical address space (ASI 20)
+ */
+#define IOCR 0x10000000 /* IO MMU control register */
+#define IBAR 0x10000004 /* IO MMU page table base address */
+#define AFR 0x10000018 /* address flush register */
+#define AFSR 0x10001000 /* asynch fault status */
+#define AFAR 0x10001004 /* asynch fault address */
+#define SSCR(i) (0x10001010+(i)*4) /* Sbus slot i config register */
+#define MFSR 0x10001020 /* memory fault status register */
+#define MFAR 0x10001024 /* memory fault address register */
+#define MID 0x10002000 /* sbus arbitration enable */
+
+#define SYSCTL 0x71F00000 /* system control & reset register */
+#define PROCINTCLR 0x71E00004 /* clear pending processor interrupts */
+
+/*
+ * IO MMU page table entry
+ */
+#define IOPTEVALID (1<<1)
+#define IOPTEWRITE (1<<2)
diff --git a/os/js/mkfile b/os/js/mkfile
new file mode 100644
index 00000000..1640eb9e
--- /dev/null
+++ b/os/js/mkfile
@@ -0,0 +1,77 @@
+SYSTARG=Inferno
+OBJTYPE=sparc
+<../../mkconfig
+
+#Configurable parameters
+
+CONF=js #default configuration
+CONFLIST=js
+
+SYSTARG=$OSTARG
+OBJTYPE=sparc
+INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed
+
+#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\
+ clock.$O\
+ main.$O\
+ mmu.$O\
+ fsv.$O\
+ screen.$O\
+ trap.$O\
+ rom.$O\
+ iob.$O\
+ superio.$O\
+ kbd.$O\
+ $CONF.root.$O\
+ $IP\
+ $DEVS\
+ $ETHERS\
+ $LINKS\
+ $VGAS\
+ $PORT\
+ $MISC\
+ $OTHERS\
+
+LIBNAMES=${LIBS:%=lib%.a}
+#LIBDIRS=$LIBS
+
+HFILES=\
+ mem.h\
+ dat.h\
+ fns.h\
+ io.h\
+ audio.h\
+ cs4231.h\
+ ns16552.h\
+ rom.h\
+ screen.h\
+ softcursor.h\
+ ureg.h\
+
+CFLAGS=-wFV -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp
+KERNDATE=`{$NDATE}
+
+default:V: i$CONF
+
+i$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES
+ $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c
+ $LD -M -o $target -H3 -T0xE0004000 -R0x4 -l $OBJ $CONF.$O $LIBFILES
+
+# "raw" version of kernel for binary comparison testing
+i$CONF.raw: $OBJ $CONF.c $CONF.root.h $LIBNAMES
+ $CC $CFLAGS '-DKERNDATE='0 $CONF.c
+ $LD -s -M -o $target -H3 -T0xE0004000 -R0x4 -l $OBJ $CONF.$O $LIBFILES
+
+install:V: $INSTALLDIR/i$CONF $INSTALLDIR/i$CONF.raw
+
+<../port/portmkfile
+
+%.$O: io.h
+clock.$O main.$O trap.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h
diff --git a/os/js/mmu.c b/os/js/mmu.c
new file mode 100644
index 00000000..4283fa79
--- /dev/null
+++ b/os/js/mmu.c
@@ -0,0 +1,252 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+typedef struct Ctx Ctx;
+/*
+ * software description of an MMU context
+ */
+struct Ctx
+{
+ Ctx *prev; /* less recently used */
+ Ctx *next; /* more recently used */
+ Proc *proc; /* process that owns this context */
+ ushort index; /* which context this is */
+};
+
+ulong *ioptes; /* IO MMU's table (shared by all processors) */
+
+/* offset of x into the three page table levels in a context */
+#define AOFF(x) (((ulong)x)>>24)
+#define BOFF(x) ((((ulong)x)>>18)&(64-1))
+#define COFF(x) ((((ulong)x)>>12)&(64-1))
+#define ISPTAB(x) ((((ulong)x)&3) == PTPVALID)
+#define KPN(va) PPN(PADDR(va))
+
+#define NIOPTE (DMASEGSIZE/BY2PG)
+
+/*
+ * allocate kernel page map and enter one mapping. Return
+ * address of the mapping.
+ */
+static ulong*
+putkmmu(ulong virt, ulong phys, int level)
+{
+ ulong *a, *b, *c;
+
+
+ a = &PPT(m->contexts[0])[AOFF(virt)];
+ if(level > 1) {
+ if(*a == 0){
+ b = (ulong*)xspanalloc(64*sizeof(ulong),
+ 64*sizeof(ulong), 0);
+ *a = KPN(b) | PTPVALID;
+ } else {
+ if(!ISPTAB(*a))
+ panic("putkmmu virt=%lux *a=%lux", virt, *a);
+ b = PPT(*a);
+ }
+ b = &b[BOFF(virt)];
+ if(level > 2) {
+ if(*b == 0){
+ c = (ulong*)xspanalloc(64*sizeof(ulong),
+ 64*sizeof(ulong), 0);
+ *b = KPN(c) | PTPVALID;
+ } else {
+ if(!ISPTAB(*b))
+ panic("putkmmu virt=%lux *b=%lux",
+ virt, *b);
+ c = PPT(*b);
+ }
+ c = &c[COFF(virt)];
+ *c = phys;
+ return c;
+ } else {
+ *b = phys;
+ return b;
+ }
+ } else {
+ *a = phys;
+ return a;
+ }
+}
+
+void
+mmuinit(void)
+{
+ int i, n;
+ ulong *a;
+
+ m->contexts = (ulong*)xspanalloc(conf.ncontext*sizeof(ulong),
+ conf.ncontext*sizeof(ulong),
+ 0);
+
+ /*
+ * context 0 will have the prototype level 1 entries
+ */
+ a = (ulong*)xspanalloc(256*sizeof(ulong), 256*sizeof(ulong), 0);
+
+ m->contexts[0] = KPN(a) | PTPVALID;
+
+ /*
+ * map all memory to KZERO
+ */
+ n = 128*MB/BY2PG;
+
+ /* pages to first segment boundary */
+ for(i=0; i<(256*1024/BY2PG); i++)
+ putkmmu(KZERO|(i*BY2PG),
+ PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 3);
+
+ /* segments to first 16Mb boundary */
+ for(; i<(16*MB)/BY2PG; i += 64)
+ putkmmu(KZERO|(i*BY2PG),
+ PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 2);
+
+ /* 16 Mbyte regions to end */
+ for(; i<n; i += 64*64)
+ putkmmu(KZERO|(i*BY2PG),
+ PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 1);
+
+ /*
+ * allocate page table pages for IO mapping
+ */
+ n = IOSEGSIZE/BY2PG;
+ for(i=0; i<n; i++)
+ putkmmu(IOSEGBASE+(i*BY2PG), 0, 3);
+
+ /*
+ * load kernel context
+ */
+
+ putrmmu(CTPR, PADDR(m->contexts)>>4);
+ putrmmu(CXR, 0);
+ flushtlb();
+
+ ioptes = (ulong*)xspanalloc(NIOPTE*sizeof(ulong), DMASEGSIZE/1024, 0);
+ putphys(IBAR, PADDR(ioptes)>>4);
+ putphys(IOCR, (DMARANGE<<2)|1); /* IO MMU enable */
+}
+
+
+void
+flushicache(void)
+{
+ int i;
+ ulong addr = 0;
+
+ for(i=0;i<512;i++) {
+ flushiline(addr);
+ addr += 1<<5;
+ }
+}
+
+void
+flushdcache(void)
+{
+ int i;
+ ulong addr = 0;
+
+ for(i=0;i<512;i++) {
+ flushdline(addr);
+ addr += 1<<5;
+ }
+}
+
+int
+segflush(void *p, ulong l)
+{
+ USED(p,l);
+ flushicache();
+ return 0;
+}
+
+void
+cacheinit(void)
+{
+ flushdcache();
+ flushicache();
+ setpcr(getpcr()|ENABCACHE);
+}
+
+typedef struct Mregion Mregion;
+struct Mregion
+{
+ ulong addr;
+ long size;
+};
+
+struct
+{
+ Mregion io;
+ Mregion dma;
+ Lock;
+}kmapalloc = {
+ {IOSEGBASE, IOSEGSIZE},
+ {DMASEGBASE, DMASEGSIZE},
+};
+
+void
+kmapinit(void)
+{
+}
+
+KMap*
+kmappa(ulong pa, ulong flag)
+{
+ ulong k;
+
+ lock(&kmapalloc);
+ k = kmapalloc.io.addr;
+ kmapalloc.io.addr += BY2PG;
+ if((kmapalloc.io.size -= BY2PG) < 0)
+ panic("kmappa");
+ putkmmu(k, PPN(pa)|PTEKERNEL|PTEWRITE|PTEVALID|flag, 3);
+ flushtlbpage(k);
+ unlock(&kmapalloc);
+ return (KMap*)k;
+}
+
+ulong
+kmapdma(ulong pa, ulong n)
+{
+ ulong va0, va;
+ int i, j;
+
+
+ lock(&kmapalloc);
+ i = (n+(BY2PG-1))/BY2PG;
+ va0 = kmapalloc.dma.addr;
+ kmapalloc.dma.addr += i*BY2PG;
+ if((kmapalloc.dma.size -= i*BY2PG) <= 0)
+ panic("kmapdma");
+ va = va0;
+ for(j=0; j<i; j++) {
+ putkmmu(va, PPN(pa)|PTEKERNEL|PTEVALID|PTEWRITE, 3);
+ flushtlbpage(va);
+ ioptes[(va>>PGSHIFT)&(NIOPTE-1)] = PPN(pa)|IOPTEVALID|IOPTEWRITE;
+ va += BY2PG;
+ pa += BY2PG;
+ }
+ unlock(&kmapalloc);
+ return va0;
+}
+
+/*
+ * map the frame buffer
+ */
+ulong
+kmapsbus(int slot)
+{
+ int i, n;
+
+ lock(&kmapalloc);
+ n = FBSEGSIZE/BY2PG;
+ for(i=0; i<n; i += 64*64)
+ putkmmu(FBSEGBASE+(i*BY2PG), PPN(SBUS(slot)+(i*BY2PG))|PTEKERNEL|PTEWRITE|PTEVALID, 1);
+ unlock(&kmapalloc);
+ return FBSEGBASE;
+}
diff --git a/os/js/ns16552.h b/os/js/ns16552.h
new file mode 100644
index 00000000..d36e0c4a
--- /dev/null
+++ b/os/js/ns16552.h
@@ -0,0 +1,81 @@
+/*
+ * Javastation specific code for the ns16552 (really the superio chip,
+ * but it has a serial port that looks like the ns16552).
+ */
+enum
+{
+ UartFREQ= 1843200,
+ TTYABase = 0x2F8
+};
+
+#define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
+#define uartrdreg(u,r) inb((u)->port + r)
+
+void ns16552setup(ulong, ulong, char*);
+
+static void
+uartpower(int, int)
+{
+}
+
+/*
+ * handle an interrupt to a single uart
+ */
+static void
+ns16552intrx(Ureg *ur, void *arg)
+{
+ USED(ur);
+
+ ns16552intr((ulong)arg);
+}
+
+/*
+ * install the uarts (called by reset)
+ */
+void
+ns16552install(void)
+{
+ static int already;
+ void uartclock(void);
+
+ if(already)
+ return;
+ already = 1;
+
+ /* first two ports are always there and always the normal frequency */
+ ns16552setup(superiova()+TTYABase, UartFREQ, "eia0");
+ ns16552special(0, 38400, &kbdq, &printq, kbdputc);
+ addclock0link(uartclock, 22);
+}
+
+/*
+ * If the UART's receiver can be connected to a DMA channel,
+ * this function does what is necessary to create the
+ * connection and returns the DMA channel number.
+ * If the UART's receiver cannot be connected to a DMA channel,
+ * a -1 is returned.
+ */
+char
+ns16552dmarcv(int dev)
+{
+
+ USED(dev);
+ return -1;
+}
+
+long
+dmasetup(int,void*,long,int)
+{
+ return 0;
+}
+
+void
+dmaend(int)
+{
+}
+
+int
+dmacount(int)
+{
+ return 0;
+}
diff --git a/os/js/rom.c b/os/js/rom.c
new file mode 100644
index 00000000..a477cfe5
--- /dev/null
+++ b/os/js/rom.c
@@ -0,0 +1,103 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+typedef struct Rom Rom;
+
+struct Rom
+{
+ uint magic;
+ uint version;
+ uint plugin_version;
+ uint monitor_id;
+
+ void **physmemlist;
+ void **virtmemlist;
+ void **availphysmemlist;
+ void *config_info;
+
+ char **bootcmd;
+
+ uint (*open)();
+ uint (*close)();
+
+ uint (*read_blocks)();
+ uint (*write_blocks)();
+
+ uint (*transmit_pkt)();
+ uint (*poll_pkt)();
+
+ uint (*read_bytes)();
+ uint (*write_bytes)();
+ uint (*seek)();
+
+ uchar *input;
+ uchar *output;
+
+ uchar (*getchar)();
+ uchar (*putchar)();
+ uchar (*noblock_getchar)();
+ uchar (*noblock_putchar)();
+
+ uchar (*fb_writestr)(char*);
+
+ void (*boot)(char*);
+
+ void (*printf)(char*,...);
+
+ void (*some_kbd_thing)();
+ int *ms_count;
+ void (*exit)();
+ void (**vector)();
+ void (**interpret)(char*,...);
+ void *bootparam;
+ uint (*mac_addr)();
+ char **v2_bootpath;
+ char ** v2_bootargs;
+ int *v2_stdin;
+ int *v2_stdout;
+ void* (*v2_phandle)();
+ char* (*v2_allocphys)();
+ char* (*v2_freephys)();
+ char* (*v2_map_dev)();
+ char* (*v2_unmap_dev)();
+ ulong (*v2_open)();
+ uint (*v2_close)();
+ uint (*v2_read)();
+ uint (*v2_write)();
+ uint (*v2_seek)();
+ void (*v2_chain)();
+ void (*v2_release)();
+ char *(*v3_alloc)();
+ int *reserved[14];
+ void (*setctxsegmap)();
+ int (*v3_startcpu)();
+ int (*v3_stopcpu)();
+ int (*v3_idlecpu)();
+ int (*v3_resumecpu)();
+};
+
+Rom *rom; /* open boot rom vector -- assigned by l.s */
+
+void
+prom_printf(char *format, ...)
+{
+ char buf[512];
+ int l;
+ va_list ap;
+
+ va_start(ap, format);
+ l = vseprint(buf,buf+sizeof(buf),format,ap) - buf;
+ va_end(ap);
+
+ call_openboot(rom->v2_write,*rom->v2_stdout,buf,l);
+}
+
+void
+prom_halt(void)
+{
+ call_openboot(rom->exit,0xfeedface);
+}
diff --git a/os/js/rom.h b/os/js/rom.h
new file mode 100644
index 00000000..ed4ee2cb
--- /dev/null
+++ b/os/js/rom.h
@@ -0,0 +1,57 @@
+typedef struct ROM ROM;
+typedef struct ROMconf ROMconf;
+
+struct ROM
+{
+ uint magic;
+ uint version;
+ uint plugversion;
+ uint monid;
+ uint pad1[3];
+ ROMconf *conf;
+ uint pad2[17];
+ void (*boot)(void*);
+ uint pad3[1];
+ void (*enter)(void);
+ int *msec;
+ void (*exit)(void);
+ void (**callback)(void);
+ uint (*interpret)(void*);
+ uint pad4[2];
+ char **bootpath;
+ char **bootargs;
+ uint *stdin;
+ uint *stdout;
+ uint (*phandle)(uint);
+ uint (*alloc)(void*, uint);
+ void (*free)(void*);
+ uint (*map)(void*, uint, uint, uint);
+ void (*unmap)(void*, uint);
+ uint (*open)(char*);
+ uint (*close)(uint);
+ uint (*read)(uint, void*, int);
+ uint (*write)(uint, void*, int);
+ uint (*seek)(uint, uint, uint);
+ void (*chain)(void*, uint, void*, void*, uint);
+ void (*release)(void*, uint);
+ uint pad4[15];
+ void (*putcxsegm)(int, ulong, int);
+ int (*startcpu)(uint, uint, uint, uint);
+ int (*stopcpu)(uint);
+ int (*idlecpu)(uint);
+ int (*resumecpu)(uint);
+};
+
+struct ROMconf
+{
+ uint (*next)(uint);
+ uint (*child)(uint);
+ int (*getproplen)(uint, void*);
+ int (*getprop)(uint, void*, void*);
+ int (*setprop)(uint, void*, void*);
+ void* (*nextprop)(uint, void*);
+};
+
+#define ROMMAGIC 0x10010407
+
+extern ROM *rom;
diff --git a/os/js/screen.c b/os/js/screen.c
new file mode 100644
index 00000000..17c12376
--- /dev/null
+++ b/os/js/screen.c
@@ -0,0 +1,483 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "io.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+#include <cursor.h>
+
+#include "softcursor.h"
+#include "screen.h"
+
+#define Backgnd (0xFF)
+
+
+ulong consbits = 0xC0;
+Memdata consdata = {
+ nil,
+ &consbits
+};
+Memimage conscol =
+{
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &consdata,
+ 0,
+ 1
+};
+
+ulong onesbits = ~0;
+Memdata onesdata = {
+ nil,
+ &onesbits,
+};
+Memimage xones =
+{
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &onesdata,
+ 0,
+ 1
+};
+Memimage *memones = &xones;
+
+ulong zerosbits = 0;
+Memdata zerosdata = {
+ nil,
+ &zerosbits,
+};
+Memimage xzeros =
+{
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &zerosdata,
+ 0,
+ 1
+};
+Memimage *memzeros = &xzeros;
+
+ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd;
+Memdata backdata = {
+ nil,
+ &backbits
+};
+Memimage xback =
+{
+ { 0, 0, 1, 1 },
+ { -100000, -100000, 100000, 100000 },
+ 3,
+ 1,
+ &backdata,
+ 0,
+ 1
+};
+Memimage *back = &xback;
+
+Video *vid;
+static Memsubfont *memdefont;
+static Lock screenlock;
+Memimage gscreen;
+Memdata gscreendata;
+static Point curpos;
+static Rectangle window;
+
+static Vctlr* vctlr;
+
+static Cursor arrow = {
+ { -1, -1 },
+ { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+ 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+ 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+ 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+ },
+ { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+ 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+ 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+ 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+ },
+};
+
+
+void
+graphicscmap(int invert)
+{
+ int num, den, i, j;
+ int r, g, b, cr, cg, cb, v;
+
+ if(vctlr->setcolor == nil)
+ return;
+
+ for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){
+ for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){
+ den=r;
+ if(g>den) den=g;
+ if(b>den) den=b;
+ if(den==0) /* divide check -- pick grey shades */
+ cr=cg=cb=v*17;
+ else{
+ num=17*(4*den+v);
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ if(invert)
+ vctlr->setcolor(255-i-(j&15),
+ cr*0x01010101,
+ cg*0x01010101,
+ cb*0x01010101);
+ else
+ vctlr->setcolor(i+(j&15),
+ cr*0x01010101,
+ cg*0x01010101,
+ cb*0x01010101);
+ }
+ }
+}
+
+static char s1[] =
+{
+ 0x00, 0x00, 0xC0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+void
+dacinit(void)
+{
+ int i;
+
+ /* Control registers */
+ vid->addr = 0x01 << 24;
+ vid->color = 0x02 << 24;
+ for(i = 0; i < sizeof s1; i++)
+ vid->cntrl = s1[i] << 24;
+
+ /* Cursor programming */
+ vid->addr = 0x00 << 24;
+ vid->color = 0x03 << 24;
+ vid->cntrl = 0xC0 << 24;
+ for(i = 0; i < 12; i++)
+ vid->cntrl = 0 << 24;
+
+ /* Load Cursor Ram */
+ vid->addr = 0x00 << 24;
+ vid->color = 0x04 << 24;
+ for(i = 0; i < 0x400; i++)
+ vid->cntrl = 0xff << 24;
+
+ graphicscmap(1);
+
+ /* Overlay Palette Ram */
+ vid->addr = 0x00 << 24;
+ vid->color = 0x01 << 24;
+ for(i = 0; i < 0x10; i++) {
+ vid->cntrl = 0xff << 24;
+ vid->cntrl = 0xff << 24;
+ vid->cntrl = 0xff << 24;
+ }
+
+ /* Overlay Palette Ram */
+ vid->addr = 0x81;
+ vid->color = 0x01;
+ for(i = 0; i < 3; i++) {
+ vid->cntrl = 0xff << 24;
+ vid->cntrl = 0xff << 24;
+ vid->cntrl = 0xff << 24;
+ }
+}
+
+void
+vctlrinit(int x, int y, int d)
+{
+ int h;
+ ulong va;
+
+ if(vctlr == nil){
+ /*
+ * find a controller somehow
+ * and call its init routine
+ */
+ extern Vctlr FSV;
+
+ vctlr = FSV.init(0, x, y, d);
+ vctlr->load(&arrow);
+ }
+
+ if(vctlr == nil)
+ panic("%s",Ebadarg);
+
+ gscreen.data = &gscreendata;
+ gscreen.r.min = Pt(0, 0);
+ gscreen.r.max = Pt(vctlr->x, vctlr->y);
+ gscreen.clipr = gscreen.r;
+ gscreen.ldepth = vctlr->d;
+ gscreen.repl = 0;
+ va = kmapsbus(FSVSLOT); /* FSV is in slot 2 */
+ gscreendata.data = (ulong *)(va+0x800000); /* Framebuffer Magic */
+ gscreen.width = (vctlr->x *(1<<gscreen.ldepth)+31)/32;
+
+
+ h = memdefont->height;
+
+ vid = (Video*)(va+0x240000); /* RAMDAC Magic */
+ memset(gscreendata.data, Backgnd, vctlr->x*vctlr->y);
+ window = gscreen.r;
+ window.max.x = vctlr->x;
+ window.max.y = (vctlr->y/h) * h;
+ curpos = window.min;
+ if (gscreen.ldepth == 3){
+ dacinit();
+ }
+
+ memset(gscreendata.data, Backgnd, vctlr->x*vctlr->y);
+ window = gscreen.r;
+ window.max.x = vctlr->x;
+ window.max.y = (vctlr->y/h) * h;
+ curpos = window.min;
+}
+
+void
+screeninit(void)
+{
+ memdefont = getmemdefont();
+ vctlrinit(1024, 768, 3);
+}
+
+ulong*
+attachscreen(Rectangle *r, int *ld, int *width, int *softscreen)
+{
+ *r = gscreen.r;
+ *ld = gscreen.ldepth;
+ *width = gscreen.width;
+ *softscreen = 0;
+ return gscreendata.data;
+}
+
+void
+detachscreen(void)
+{
+}
+
+void
+flushmemscreen(Rectangle)
+{
+}
+
+static void
+scroll(void)
+{
+ int o;
+ Point p;
+ Rectangle r;
+
+ o = 4*memdefont->height;
+ r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
+ p = Pt(window.min.x, window.min.y+o);
+ memdraw(&gscreen, r, &gscreen, p, memones, p);
+ r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
+ memdraw(&gscreen, r, back, memzeros->r.min, memones, memzeros->r.min);
+
+ curpos.y -= o;
+}
+
+void
+screenputc(char *buf)
+{
+ Point p;
+ int h, w, pos;
+ Rectangle r;
+ static int *xp;
+ static int xbuf[256];
+
+ h = memdefont->height;
+ if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
+ xp = xbuf;
+
+ switch(buf[0]) {
+ case '\n':
+ if(curpos.y+h >= window.max.y)
+ scroll();
+ curpos.y += h;
+ screenputc("\r");
+ break;
+ case '\r':
+ xp = xbuf;
+ curpos.x = window.min.x;
+ break;
+ case '\t':
+ p = memsubfontwidth(memdefont, " ");
+ w = p.x;
+ *xp++ = curpos.x;
+ pos = (curpos.x-window.min.x)/w;
+ pos = 8-(pos%8);
+ curpos.x += pos*w;
+ break;
+ case '\b':
+ if(xp <= xbuf)
+ break;
+ xp--;
+ r = Rpt(Pt(*xp, curpos.y), Pt(curpos.x, curpos.y + h));
+ memdraw(&gscreen, r, back, back->r.min, memones, back->r.min);
+ curpos.x = *xp;
+ break;
+ default:
+ p = memsubfontwidth(memdefont, buf);
+ w = p.x;
+
+ if(curpos.x >= window.max.x-w)
+ screenputc("\n");
+
+ *xp++ = curpos.x;
+ memimagestring(&gscreen, curpos, &conscol, memdefont, buf);
+ curpos.x += w;
+ }
+}
+
+void
+screenputs(char *s, int n)
+{
+ int i;
+ Rune r;
+ char buf[4];
+extern int cold;
+
+if(!cold)
+ return;
+
+ if(islo() == 0) {
+ /* don't deadlock trying to print in interrupt */
+ if(!canlock(&screenlock))
+ return;
+ } else
+ lock(&screenlock);
+
+ while(n > 0) {
+ i = chartorune(&r, s);
+ if(i == 0){
+ s++;
+ --n;
+ continue;
+ }
+ memmove(buf, s, i);
+ buf[i] = 0;
+ n -= i;
+ s += i;
+ screenputc(buf);
+ }
+
+ unlock(&screenlock);
+}
+
+
+void
+cursorenable(void)
+{
+ if(vctlr->enable == nil)
+ return;
+
+ vctlr->enable();
+
+ if(!vctlr->isloaded())
+ vctlr->load(&arrow);
+}
+
+void
+cursordisable(void)
+{
+ if(vctlr->disable == nil)
+ return;
+
+ vctlr->disable();
+}
+
+static Rectangle cursoroffrect;
+static int cursorisoff;
+static Point hot;
+
+void
+cursorupdate0(void)
+{
+ int inrect, x, y;
+
+ x = mouse.x - hot.x;
+ y = mouse.y - hot.y;
+ inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x
+ && y >= cursoroffrect.min.y && y < cursoroffrect.max.y);
+ if (cursorisoff == inrect)
+ return;
+ cursorisoff = inrect;
+ if (inrect)
+ cursordisable();
+ else
+ cursorenable();
+}
+
+void
+cursorupdate(Rectangle r)
+{
+ lock(&screenlock);
+ r.min.x -= 16;
+ r.min.y -= 16;
+ cursoroffrect = r;
+ if (swcursor)
+ cursorupdate0();
+ unlock(&screenlock);
+}
+
+void
+drawcursor(Drawcursor* c)
+{
+ Cursor curs;
+ int j, i, h, bpl;
+ uchar *bc, *bs, *cclr, *cset;
+
+ if(vctlr->load == nil)
+ return;
+
+ /* Set the default system cursor */
+ if(c->data == nil) {
+ lock(&screenlock);
+ vctlr->load(&arrow);
+ unlock(&screenlock);
+ return;
+ }
+
+ hot.x = c->hotx;
+ hot.y = c->hoty;
+ curs.offset = hot;
+ bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 0);
+
+ h = (c->maxy-c->miny)/2;
+ if(h > 16)
+ h = 16;
+
+ bc = c->data;
+ bs = c->data + h*bpl;
+
+ cclr = curs.clr;
+ cset = curs.set;
+ for(i = 0; i < h; i++) {
+ for(j = 0; j < 2; j++) {
+ cclr[j] = bc[j];
+ cset[j] = bs[j];
+ }
+ bc += bpl;
+ bs += bpl;
+ cclr += 2;
+ cset += 2;
+ }
+ lock(&screenlock);
+ vctlr->load(&curs);
+ unlock(&screenlock);
+}
+
diff --git a/os/js/screen.h b/os/js/screen.h
new file mode 100644
index 00000000..158ba592
--- /dev/null
+++ b/os/js/screen.h
@@ -0,0 +1,49 @@
+typedef struct Cursor Cursor;
+typedef struct Vctlr Vctlr;
+typedef struct Video Video;
+typedef struct Thc Thc;
+
+#define FSVSLOT 2 /* MrCoffee Hard Coded FB Location */
+
+struct Cursor
+{
+ Point offset;
+ uchar clr[2*16];
+ uchar set[2*16];
+};
+
+struct Vctlr {
+ char* name;
+ Vctlr* (*init)(Vctlr*, int, int, int);
+ void (*page)(int);
+ int (*setcolor)(ulong, ulong, ulong, ulong);
+
+ void (*enable)(void);
+ void (*disable)(void);
+ void (*move)(int, int);
+ void (*load)(Cursor*);
+ int (*isloaded)(void);
+ int (*cursorintersectsoff)(Rectangle*);
+
+ int x;
+ int y;
+ int d;
+
+ Vctlr* link;
+
+ int hidecount;
+ int loaded;
+ Cursor cursor;
+ Lock l;
+};
+
+
+struct Video
+{
+ /* Brooktree 458/451 */
+ ulong addr; /* address register */
+ ulong color; /* color palette */
+ ulong cntrl; /* control register */
+ ulong ovrl; /* overlay palette */
+};
+
diff --git a/os/js/softcursor.h b/os/js/softcursor.h
new file mode 100644
index 00000000..579914ec
--- /dev/null
+++ b/os/js/softcursor.h
@@ -0,0 +1,13 @@
+/*
+ * this should be #define'd to nothing if you have a hardware cursor
+ */
+
+void cursormaybeoff(Rectangle*, Memimage*, Rectangle, Memimage*, Point*);
+
+/*
+ * also, you should #define cussoron() and cursoroff() to nothing
+ * if you have a hardware cursor.. This isn't as bad as it sounds, because
+ * this file is only included in port/devdraw.c, and it doesn't need to
+ * touch the cursor if it's a hardware cursor
+ * -Tad
+ */
diff --git a/os/js/superio.c b/os/js/superio.c
new file mode 100644
index 00000000..e3030eab
--- /dev/null
+++ b/os/js/superio.c
@@ -0,0 +1,216 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+
+enum
+{
+ /* superio configuration registers */
+ SioFER = 0x0, /* function enable register */
+ SioFAR = 0x1, /* function address register */
+ SioPTR = 0x2, /* power and test egister */
+ SioFCR = 0x3, /* function control register */
+ SioPCR = 0x4, /* printer control register */
+ SioKRR = 0x5, /* keyboard and RTC control register */
+ SioPMC = 0x6, /* power mgmt control register */
+ SioTUP = 0x7, /* tape uart and parallel register */
+ SioSID = 0x8, /* SuperIO ID register */
+ SioASC = 0x9, /* Advanced SIO Config register */
+ SioCS0CF0 = 0xA, /* Chip select 0 config register 0 */
+ SioCS0CF1 = 0xB, /* Chip select 0 config register 1 */
+ SioCS1CF0 = 0xC, /* Chip select 1 config register 0 */
+ SioCS1CF1 = 0xD, /* Chip select 1 config register 1 */
+
+ /* FER bits */
+ PPTEnable = 1<<0,
+ EnableUART1 = 1<<1,
+ EnableUART2 = 1<<2,
+ FDCEnable = 1<<3,
+ FDC4 = 1<<4,
+ FDC2ndAddr = 1<<5,
+ IDEEnable = 1<<6,
+ IDE2ndAddr = 1<<7,
+
+ /* FAR bits */
+ PPTAddr = 3<<0,
+ UART1Addr = 3<<2,
+ UART2Addr = 3<<4,
+ SelectCom3n4 = 3<<6,
+
+ /* PTR bits */
+ PWDN = 1<<0,
+ ClkPWDN = 1<<1,
+ PWDNSelect = 1<<2,
+ IRQSelect = 1<<3,
+ UART1Test = 1<<4,
+ UART2Test = 1<<5,
+ LockConfig = 1<<6,
+ XtndPPTSelect = 1<<7,
+
+ /* FCR bits */
+ MediaSense = 1<<0,
+ DatRateSelect = 1<<0,
+ IDENTSelect = 1<<1,
+ PPTFloat = 1<<3,
+ LogicalDrvXcg = 1<<4, /* logical drive exchange */
+ EnaZeroWait = 1<<5, /* zero wait state enable *.
+
+ /* PCR bits */
+ EPPEnable = 1<<0,
+ EPPVersionSel = 1<<1,
+ ECPEnable = 1<<2,
+ ECPClkFreeze = 1<<3,
+ PPTIntPolar = 1<<5,
+ PPTIntIOCtl = 1<<6,
+ RTCRamMask = 1<<7,
+
+ /* KRR bits */
+ KBCEnable = 1<<0,
+ KBCSpeedCtl = 1<<1,
+ EnaProgAccess = 1<<2,
+ RTCEnable = 1<<3,
+ RTCClkTst = 1<<4,
+ RAMSEL = 1<<5,
+ EnaChipSelect = 1<<6,
+ KBCClkSource = 1<<7,
+
+ /* PMC bits */
+ IDETriStCtl = 1<<0,
+ FDCTriStCtl = 1<<1,
+ UARTTriStCtl = 1<<2,
+ SelectiveLock = 1<<5,
+ PPTriStEna = 1<<6,
+
+ /* TUP bits */
+ EPPToutIntEna = 1<<2,
+
+ /* SID bits are just data values */
+
+ /* ASC bits */
+ IRQ5Select = 1<<0,
+ DRATE0Select = 1<<0,
+ DRV2Select = 1<<1,
+ DR23Select = 1<<1,
+ EnhancedTDR = 1<<2,
+ ECPCnfgABit3 = 1<<5,
+ SystemOpMode0 = 1<<6,
+ SystemOpMode1 = 1<<7,
+
+ /* CS0CF0 bits are LA0-LA7 */
+ /* CS1CF0 bits are LA0-LA7 */
+ /* CSxCF1 bits (x=0,1) */
+ HA8 = 1<<0,
+ HA9 = 1<<1,
+ HA10 = 1<<2,
+ EnaCSWr = 1<<4,
+ EnaCSRd = 1<<5,
+ CSAdrDcode = 1<<6, /* enable full addr decode */
+ CSSelectPin = 1<<7, /* CS/CS0 and SYSCLK/CS1 select pin */
+};
+
+typedef struct SuperIO SuperIO;
+
+struct SuperIO
+{
+ ulong va;
+ uchar *index; /* superio index register */
+ uchar *data; /* superio data register */
+
+ uchar *mkctl; /* superio mouse/kbd control register */
+ uchar *mkdata; /* superio mouse/kbd data register */
+};
+
+
+static SuperIO sio;
+
+static void printstatus(uchar status);
+
+void
+superioinit(ulong va, uchar *sindex, uchar *sdata, uchar *mkctl, uchar *mkdata)
+{
+ sio.va = va;
+
+ sio.index = sindex;
+ sio.data = sdata;
+
+ sio.mkctl = mkctl;
+ sio.mkdata = mkdata;
+}
+
+
+ulong
+superiova(void)
+{
+ return sio.va;
+}
+
+enum
+{
+ OBF = 1<<0,
+ IBF = 1<<1,
+ SysFlag = 1<<2,
+ LastWrWasCmd = 1<<3,
+ KbdEnabled = 1<<4,
+ FromMouse = 1<<5,
+ Timeout = 1<<6,
+ ParityError = 1<<7
+};
+
+uchar
+superio_readctl(void)
+{
+ return *sio.mkctl;
+}
+
+uchar
+superio_readdata(void)
+{
+ return *sio.mkdata;
+}
+
+void
+superio_writectl(uchar val)
+{
+ *sio.mkctl = val;
+}
+
+void
+superio_writedata(uchar val)
+{
+ *sio.mkdata = val;
+}
+
+
+static void
+printstatus(uchar status)
+{
+ print("0x%2.2ux = <",status);
+ if(status & OBF) print("OBF|");
+ if(status & IBF) print("IBF|");
+ if(status & SysFlag) print("SysFlag|");
+ if(status & LastWrWasCmd) print("LastWrWasCmd|");
+ if(status & KbdEnabled) print("KbdEnabled|");
+ if(status & FromMouse) print("FromMouse|");
+ if(status & Timeout) print("Timeout|");
+ if(status & ParityError) print("ParityErr|");
+ print(">");
+}
+
+void
+testit()
+{
+ uchar status;
+ uchar val;
+
+ for(;;) {
+ status = *sio.mkctl;
+ if(status&OBF) {
+ printstatus(status);
+ val = *sio.mkdata;
+ print(", data = 0x%2.2ux\n",val);
+ }
+ }
+}
diff --git a/os/js/trap.c b/os/js/trap.c
new file mode 100644
index 00000000..b9117bfe
--- /dev/null
+++ b/os/js/trap.c
@@ -0,0 +1,472 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "ureg.h"
+#include "io.h"
+#include "../port/error.h"
+
+void noted(Ureg**, ulong);
+void rfnote(Ureg**);
+int domuldiv(ulong, Ureg*);
+
+extern Label catch;
+extern void traplink(void);
+extern void syslink(void);
+static void faultsparc(Ureg *ur);
+static void faultasync(Ureg *ur);
+
+ long ticks;
+static char excbuf[64]; /* BUG: not reentrant! */
+
+char *trapname[]={
+ "reset",
+ "instruction access exception",
+ "illegal instruction",
+ "privileged instruction",
+ "fp: disabled",
+ "window overflow",
+ "window underflow",
+ "unaligned address",
+ "fp: exception",
+ "data access exception",
+ "tag overflow",
+ "watchpoint detected",
+};
+
+char *fptrapname[]={
+ "none",
+ "IEEE 754 exception",
+ "unfinished FP op",
+ "unimplemented FP op",
+ "sequence error",
+ "hardware error",
+ "invalid FP register",
+ "reserved",
+}
+;
+
+char*
+excname(ulong tbr)
+{
+ char xx[64];
+ char *t;
+
+ switch(tbr){
+ case 8:
+ if(up == 0)
+ panic("fptrap in kernel\n");
+ else{
+panic("fptrap not implemented\n");
+#ifdef notdef
+ if(m->fpunsafe==0 && up->p->fpstate!=FPactive)
+ panic("fptrap not active\n"); fsr = up->fpsave.env;
+ sprint(excbuf, "fp: %s fppc=0x%lux",
+ fptrapname[(fsr>>14)&7],
+ up->fpsave.q[0].a, fsr);
+#endif
+ }
+ return excbuf;
+ case 36:
+ return "trap: cp disabled";
+ case 37:
+ return "trap: unimplemented instruction";
+ case 40:
+ return "trap: cp exception";
+ case 42:
+ return "trap: divide by zero";
+ case 128:
+ return "syscall";
+ case 129:
+ return "breakpoint";
+ }
+ t = 0;
+ if(tbr < sizeof trapname/sizeof(char*))
+ t = trapname[tbr];
+ if(t == 0){
+ if(tbr >= 130)
+ sprint(xx, "trap instruction %ld", tbr-128);
+ else if(17<=tbr && tbr<=31)
+ sprint(xx, "interrupt level %ld", tbr-16);
+ else
+ sprint(xx, "unknown trap %ld", tbr);
+ t = xx;
+ }
+ if(strncmp(t, "fp: ", 4) == 0)
+ strcpy(excbuf, t);
+ else
+ sprint(excbuf, "trap: %s", t);
+ return excbuf;
+
+}
+
+void
+trap(Ureg *ur)
+{
+ int user;
+ ulong tbr, iw;
+
+ tbr = (ur->tbr&0xFFF)>>4;
+ /*
+ * Hack to catch bootstrap fault during probe
+ */
+ if(catch.pc)
+ gotolabel(&catch);
+
+ if(up)
+ up->dbgreg = ur;
+
+ user = !(ur->psr&PSRPSUPER);
+ if(user) {
+ panic("how did we get to user mode???");
+ }
+ if(tbr > 16){ /* interrupt */
+ switch(tbr-16) {
+ case 15: /* asynch mem err */
+ faultasync(ur);
+ break;
+ case 14: /* processor counter */
+ clock(ur);
+ break;
+ case 13: /* keyboard/mouse */
+ ns16552intr(0);
+ kbdintr();
+ break;
+ case 6: /* lance */
+ lanceintr();
+ break;
+ default:
+ print("unexp intr lev %ld\n", tbr-16);
+ goto Error;
+ }
+ }else{
+ switch(tbr){
+ case 1: /* instr. access */
+ case 9: /* data access */
+ if(up && up->fpstate==FPACTIVE) {
+ fpquiet();
+ fpsave(&up->fpsave);
+ up->fpstate = FPINACTIVE;
+ }
+ faultsparc(ur);
+ goto Return;
+ case 2: /* illegal instr, maybe mul */
+ iw = *(ulong*)ur->pc;
+ if((iw&0xC1500000) == 0x80500000){
+ if(domuldiv(iw, ur))
+ goto Return;
+ tbr = ur->tbr;
+ }
+ break;
+ case 4: /* floating point disabled */
+panic("some more floating point crapola");
+break;
+#ifdef notdef
+ if(u && u->p){
+ if(up->p->fpstate == FPINIT)
+ restfpregs(initfpp, up->fpsave.fsr);
+ else if(u->p->fpstate == FPinactive)
+ restfpregs(&u->fpsave, u->fpsave.fsr);
+ else
+ break;
+ u->p->fpstate = FPactive;
+ ur->psr |= PSREF;
+ return;
+ }
+ break;
+#endif
+ case 8: /* floating point exception */
+panic("floating point crapola #3");
+break;
+#ifdef notdef
+ /* if unsafe, trap happened shutting down FPU; just return */
+ if(m->fpunsafe){
+ m->fptrap = (fptrap()==0);
+ return;
+ }
+ if(fptrap())
+ goto Return; /* handled the problem */
+ break;
+#endif
+ default:
+ break;
+ }
+ Error:
+ panic("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc);
+ }
+ Return:
+ return;
+}
+
+void
+trapinit(void)
+{
+ int i;
+ long t, a;
+
+ a = ((ulong)traplink-TRAPS)>>2;
+ a += 0x40000000; /* CALL traplink(SB) */
+ t = TRAPS;
+ for(i=0; i<256; i++){
+ *(ulong*)(t+0) = a; /* CALL traplink(SB) */
+ *(ulong*)(t+4) = 0xa7480000; /* MOVW PSR, R19 */
+ a -= 16/4;
+ t += 16;
+ }
+
+#ifdef notdef
+ flushpage(TRAPS);
+#else
+ flushicache();
+#endif
+
+ puttbr(TRAPS);
+ setpsr(getpsr()|PSRET|SPL(15)); /* enable traps, not interrupts */
+}
+
+void
+mulu(ulong u1, ulong u2, ulong *lop, ulong *hip)
+{
+ ulong lo1, lo2, hi1, hi2, lo, hi, t1, t2, t;
+
+ lo1 = u1 & 0xffff;
+ lo2 = u2 & 0xffff;
+ hi1 = u1 >> 16;
+ hi2 = u2 >> 16;
+
+ lo = lo1 * lo2;
+ t1 = lo1 * hi2;
+ t2 = lo2 * hi1;
+ hi = hi1 * hi2;
+ t = lo;
+ lo += t1 << 16;
+ if(lo < t)
+ hi++;
+ t = lo;
+ lo += t2 << 16;
+ if(lo < t)
+ hi++;
+ hi += (t1 >> 16) + (t2 >> 16);
+ *lop = lo;
+ *hip = hi;
+}
+
+void
+muls(long l1, long l2, long *lop, long *hip)
+{
+ ulong t, lo, hi;
+ ulong mlo, mhi;
+ int sign;
+
+ sign = 0;
+ if(l1 < 0){
+ sign ^= 1;
+ l1 = -l1;
+ }
+ if(l2 < 0){
+ sign ^= 1;
+ l2 = -l2;
+ }
+ mulu(l1, l2, &mlo, &mhi);
+ lo = mlo;
+ hi = mhi;
+ if(sign){
+ t = lo = ~lo;
+ hi = ~hi;
+ lo++;
+ if(lo < t)
+ hi++;
+ }
+ *lop = lo;
+ *hip = hi;
+}
+
+int
+domuldiv(ulong iw, Ureg *ur)
+{
+ long op1, op2;
+ long *regp;
+ long *regs;
+
+ regs = (long*)ur;
+ if(iw & (1<<13)){ /* signed immediate */
+ op2 = iw & 0x1FFF;
+ if(op2 & 0x1000)
+ op2 |= ~0x1FFF;
+ }else
+ op2 = regs[iw&0x1F];
+ op1 = regs[(iw>>14)&0x1F];
+ regp = &regs[(iw>>25)&0x1F];
+
+ if(iw & (4<<19)){ /* divide */
+ if(ur->y!=0 && ur->y!=~0){
+ unimp:
+ ur->tbr = 37; /* "unimplemented instruction" */
+ return 0; /* complex Y is too hard */
+ }
+ if(op2 == 0){
+ ur->tbr = 42; /* "zero divide" */
+ return 0;
+ }
+ if(iw & (1<<19)){
+ if(ur->y && (op1&(1<<31))==0)
+ goto unimp; /* Y not sign extension */
+ *regp = op1 / op2;
+ }else{
+ if(ur->y)
+ goto unimp;
+ *regp = (ulong)op1 / (ulong)op2;
+ }
+ }else{
+ if(iw & (1<<19))
+ muls(op1, op2, regp, (long*)&ur->y);
+ else
+ mulu(op1, op2, (ulong*)regp, &ur->y);
+ }
+ if(iw & (16<<19)){ /* set CC */
+ ur->psr &= ~(0xF << 20);
+ if(*regp & (1<<31))
+ ur->psr |= 8 << 20; /* N */
+ if(*regp == 0)
+ ur->psr |= 4 << 20; /* Z */
+ /* BUG: don't get overflow right on divide */
+ }
+ ur->pc += 4;
+ ur->npc = ur->pc+4;
+ return 1;
+}
+
+void
+dumpregs(Ureg *ur)
+{
+ int i;
+ ulong *l;
+
+ if(up) {
+ print("registers for %s %ld\n",up->text,up->pid);
+ if(ur->usp < (ulong)up->kstack ||
+ ur->usp > (ulong)up->kstack+KSTACK-8)
+ print("invalid stack pointer\n");
+ } else
+ print("registers for kernel\n");
+
+ print("PSR=%lux PC=%lux TBR=%lux\n", ur->psr, ur->pc, ur->tbr);
+ l = &ur->r0;
+ for(i=0; i<32; i+=2, l+=2)
+ print("R%d\t%.8lux\tR%d\t%.8lux\n", i, l[0], i+1, l[1]);
+}
+
+
+/* This routine must save the values of registers the user is not permitted to
+ * write from devproc and the restore the saved values before returning
+ */
+void
+setregisters(Ureg *xp, char *pureg, char *uva, int n)
+{
+ ulong psr;
+
+ psr = xp->psr;
+ memmove(pureg, uva, n);
+ xp->psr = psr;
+}
+
+void
+dumpstack(void)
+{
+}
+
+/*
+ * Must only be called splhi() when it is safe to spllo(). Because the FP unit
+ * traps if you touch it when an exception is pending, and because if you
+ * trap with ET==0 you halt, this routine sets some global flags to enable
+ * the rest of the system to handle the trap that might occur here without
+ * upsetting the kernel. Shouldn't be necessary, but safety first.
+ */
+int
+fpquiet(void)
+{
+ int i, notrap;
+ ulong fsr;
+ char buf[128];
+
+ i = 0;
+ notrap = 1;
+ up->fpstate = FPINACTIVE;
+ for(;;){
+ m->fptrap = 0;
+ fsr = getfsr();
+ if(m->fptrap){
+ /* trap occurred and up->fpsave contains state */
+ sprint(buf, "sys: %s", excname(8));
+#ifdef notdef
+ postnote(u->p, 1, buf, NDebug);
+#else
+ panic(buf);
+#endif
+ notrap = 0;
+ break;
+ }
+ if((fsr&(1<<13)) == 0)
+ break;
+ if(++i > 1000){
+ print("fp not quiescent\n");
+ break;
+ }
+ }
+ up->fpstate = FPACTIVE;
+ return notrap;
+}
+
+enum
+{
+ SE_WRITE = 4<<5,
+ SE_PROT = 2<<2,
+};
+
+static void
+faultsparc(Ureg *ur)
+{
+ ulong addr;
+ char buf[ERRMAX];
+ int read;
+ ulong tbr, ser;
+
+ tbr = (ur->tbr&0xFFF)>>4;
+ addr = ur->pc; /* assume instr. exception */
+ read = 1;
+ if(tbr == 9){ /* data access exception */
+ addr = getrmmu(SFAR);
+ ser = getrmmu(SFSR);
+ if(ser&(SE_WRITE)) /* is SE_PROT needed? */
+ read = 0;
+ }
+
+ up->dbgreg = ur; /* for remote acid */
+ spllo();
+ sprint(buf, "sys: trap: fault %s addr=0x%lux",
+ read? "read" : "write", addr);
+
+ if(up->type == Interp)
+ disfault(ur,buf);
+ dumpregs(ur);
+ panic("fault: %s", buf);
+}
+
+static void
+faultasync(Ureg *ur)
+{
+ int user;
+
+ print("interrupt 15 AFSR %lux AFAR %lux MFSR %lux MFAR %lux\n",
+ getphys(AFSR), getphys(AFAR), getphys(MFSR), getphys(MFAR));
+ dumpregs(ur);
+ /*
+ * Clear interrupt
+ */
+ putphys(PROCINTCLR, 1<<15);
+ user = !(ur->psr&PSRPSUPER);
+ if(user)
+ pexit("Suicide", 0);
+ panic("interrupt 15");
+}
diff --git a/os/js/ureg.h b/os/js/ureg.h
new file mode 100644
index 00000000..8433eec9
--- /dev/null
+++ b/os/js/ureg.h
@@ -0,0 +1,45 @@
+struct Ureg
+{
+ ulong r0; /* unnecessary; just for symmetry */
+ union{
+ ulong sp; /* r1 */
+ ulong usp; /* r1 */
+ ulong r1;
+ };
+ ulong r2;
+ ulong r3;
+ ulong r4;
+ ulong r5;
+ ulong r6;
+ ulong r7;
+ ulong r8;
+ ulong r9;
+ ulong r10;
+ ulong r11;
+ ulong r12;
+ ulong r13;
+ ulong r14;
+ ulong r15;
+ ulong r16;
+ ulong r17;
+ ulong r18;
+ ulong r19;
+ ulong r20;
+ ulong r21;
+ ulong r22;
+ ulong r23;
+ ulong r24;
+ ulong r25;
+ ulong r26;
+ ulong r27;
+ ulong r28;
+ ulong r29;
+ ulong r30;
+ ulong r31;
+ ulong y;
+ ulong tbr;
+ ulong psr;
+ ulong npc;
+ ulong pc;
+ ulong pad; /* so structure is double word aligned */
+};