ref: 6f80913ac72490cca7645b85b64de5ed52a7ce91
parent: 1ecdf09aeeb16dd359251e3e698c8ea7798bd285
author: aiju <devnull@localhost>
date: Wed Jan 22 08:09:09 EST 2020
add v8e
--- a/sys/src/games/mkfile
+++ b/sys/src/games/mkfile
@@ -48,6 +48,7 @@
sokoban\
sudoku\
timmy\
+ v8e\
4s.$O 5s.$O xs.$O: xs.h
$O.4s $O.5s: xs.$O
--- /dev/null
+++ b/sys/src/games/v8e/cpu.c
@@ -1,0 +1,1166 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+u32int r[16];
+u32int curpc;
+u32int ps;
+int trace;
+
+enum {
+ ADD,
+ SUB,
+ MUL,
+ DIV,
+ CMP,
+ TST,
+ BIC,
+ BIS,
+ XOR,
+ BIT,
+};
+
+#define fetch8() memread8(r[15]++)
+
+static u16int
+fetch16(void)
+{
+ u16int v;
+ v = memread16(r[15]);
+ r[15] += 2;
+ return v;
+}
+
+static u32int
+fetch32(void)
+{
+ u32int v;
+ v = memread32(r[15]);
+ r[15] += 4;
+ return v;
+}
+
+static u32int
+sxt(u32int v, int s)
+{
+ switch(s){
+ case 0: return (s8int) v;
+ case 1: return (s16int) v;
+ default: return v;
+ }
+}
+
+static void
+nz(u32int v, int s)
+{
+ int i;
+
+ i = sxt(v, s);
+ ps &= ~(FLAGN|FLAGZ);
+ if(i == 0) ps |= FLAGZ;
+ if(i < 0) ps |= FLAGN;
+}
+
+static void
+nz64(u64int v, int s)
+{
+ if(s < 3)
+ nz(v, s);
+ else{
+ if(v == 0) ps |= FLAGZ;
+ else if((s64int)v < 0) ps |= FLAGN;
+ }
+}
+
+static void
+nzv(u32int v, int s)
+{
+ nz(v, s);
+ ps &= ~FLAGV;
+}
+
+u32int
+addrof(vlong v)
+{
+ if(v < 0) sysfatal("addr of register or literal (pc=%.8ux)", curpc);
+ return v;
+}
+
+vlong
+amode(int s)
+{
+ u8int c;
+ u32int v;
+
+ s &= 0xf;
+ c = fetch8();
+ switch(c >> 4){
+ case 0: case 1: case 2: case 3: return ~(vlong)(64 | c & 63);
+ case 4: v = addrof(amode(s)); v += r[c & 15] << s; return v;
+ case 5: return ~(vlong)(c & 15);
+ case 6: return r[c & 15];
+ case 7: return r[c & 15] -= 1<<s;
+ case 8: v = r[c & 15]; r[c & 15] += 1<<s; return v;
+ case 9: v = r[c & 15]; r[c & 15] += 4; return memread32(v);
+ case 10: v = fetch8(); return (u32int)(r[c & 15] + (s8int) v);
+ case 11: v = fetch8(); return memread32(r[c & 15] + (s8int) v);
+ case 12: v = fetch16(); return (u32int)(r[c & 15] + (s16int) v);
+ case 13: v = fetch16(); return memread32(r[c & 15] + (s16int) v);
+ case 14: v = fetch32(); return (u32int)(r[c & 15] + v);
+ case 15: v = fetch32(); return memread32(r[c & 15] + v);
+ default: sysfatal("unimplemented addressing mode %.2x", c); return -1;
+ }
+}
+
+u32int
+readm(vlong a, int s)
+{
+ vlong v;
+
+ if(a < 0){
+ if(a <= ~64LL){
+ if(s >= 0x10)
+ return (~a & 63) << 4 | 0x4000;
+ return ~a & 63;
+ }
+ assert(a >= ~15LL);
+ v = r[~a];
+ switch(s & 0xf){
+ case 0: return (uchar) v;
+ case 1: return (ushort) v;
+ case 2: return v;
+ }
+ }
+ switch(s & 0xf){
+ case 0: return memread8(a);
+ case 1: return memread16(a);
+ case 2: return memread32(a);
+ default: sysfatal("readm: unimplemented size %d (a=%.llx, pc=%.8x)", s, a, curpc); return -1;
+ }
+}
+
+static vlong
+highw(vlong v)
+{
+ if(v >= 0)
+ return (u32int)(v + 4);
+ if(v <= ~64LL)
+ return ~64LL;
+ return v - 1 | ~15LL;
+}
+
+u64int
+readm64(vlong a, int s)
+{
+ u64int v;
+
+ if((s & 0xf) == 3){
+ v = readm(a, s - 1);
+ if(a > ~64LL)
+ v |= (u64int)readm(highw(a), 2) << 32;
+ return v;
+ }
+ return readm(a, s);
+}
+
+void
+writem(vlong a, u32int v, int s)
+{
+ int n;
+
+ assert(a >= ~15LL);
+ s &= 0xf;
+ if(a < 0){
+ switch(s){
+ case 0: r[~a] = r[~a] & ~0xff | v & 0xff; break;
+ case 1: r[~a] = r[~a] & ~0xffff | v & 0xffff; break;
+ case 2: r[~a] = v; break;
+ default: sysfatal("writem: unimplemented size %d", s);
+ }
+ return;
+ }
+ switch(s){
+ case 0:
+ n = (a & 3) << 3;
+ memwrite(a & -4, v << n, 0xff << n);
+ break;
+ case 1:
+ n = (a & 3) << 3;
+ memwrite(a & -4, v << n, 0xffff << n);
+ if(n == 24) memwrite(-(-a & -4), v >> 8, 0xff);
+ break;
+ case 2:
+ n = (a & 3) << 3;
+ memwrite(a & -4, v << n, -1 << n);
+ if(n != 0) memwrite(-(-a & -4), v >> 32 - n, (u32int)-1 >> 32 - n);
+ break;
+ default: sysfatal("writem: unimplemented size %d", s);
+ }
+}
+
+void
+writem64(vlong a, u64int v, int s)
+{
+ if((s & 0xf) == 3){
+ writem(a, v, 2);
+ writem(highw(a), v >> 32, 2);
+ }else
+ writem(a, v, s);
+}
+
+static u32int
+add(u32int a, u32int b, int s)
+{
+ int v;
+
+ ps &= ~(FLAGC|FLAGV);
+ switch(s){
+ case 0:
+ v = (u8int)a + (u8int)b;
+ if(v >= 0x100) ps |= FLAGC;
+ if(((a ^ ~b) & (v ^ a) & 0x80) != 0) ps |= FLAGV;
+ return v;
+ case 1:
+ v = (u16int)a + (u16int)b;
+ if(v >= 0x10000) ps |= FLAGC;
+ if(((a ^ ~b) & (v ^ a) & 0x8000) != 0) ps |= FLAGV;
+ return v;
+ case 2:
+ v = a + b;
+ if((u32int)v < a) ps |= FLAGC;
+ if(((a ^ ~b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
+ return v;
+ default:
+ sysfatal("subtract: unimplemented size %d", s);
+ return 0;
+ }
+}
+
+static void
+adwc(void)
+{
+ vlong ad;
+ u32int a, b, v;
+ u8int c;
+
+ a = readm(amode(2), 2);
+ ad = amode(2);
+ b = readm(ad, 2);
+ c = ps & FLAGC;
+ ps &= ~15;
+ v = a + b + c;
+ if(v < a || c && v == a) ps |= FLAGC;
+ if(((a ^ ~b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
+ writem(ad, v, 2);
+ nzv(v, 2);
+}
+
+static u32int
+subtract(u32int a, u32int b, int s)
+{
+ int v;
+
+ ps &= ~(FLAGC|FLAGV);
+ switch(s){
+ case 0:
+ v = (u8int)b - (u8int)a;
+ if(v < 0) ps |= FLAGC;
+ if(((a ^ b) & (v ^ a) & 0x80) != 0) ps |= FLAGV;
+ return v;
+ case 1:
+ v = (u16int)b - (u16int)a;
+ if(v < 0) ps |= FLAGC;
+ if(((a ^ b) & (v ^ a) & 0x8000) != 0) ps |= FLAGV;
+ return v;
+ case 2:
+ v = b - a;
+ if((u32int)v > b) ps |= FLAGC;
+ if(((a ^ b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
+ return v;
+ default:
+ sysfatal("subtract: unimplemented size %d", s);
+ return 0;
+ }
+}
+
+static void
+sbwc(void)
+{
+ vlong ad;
+ u32int a, b, v;
+ u8int c;
+
+ a = readm(amode(2), 2);
+ ad = amode(2);
+ b = readm(ad, 2);
+ c = ps & FLAGC;
+ ps &= ~15;
+ v = a - b - c;
+ if(v > a || c && v == a) ps |= FLAGC;
+ if(((a ^ b) & (v ^ a) & 0x80000000) != 0) ps |= FLAGV;
+ writem(ad, v, 2);
+ nzv(v, 2);
+}
+
+static void
+cmp(u32int a, u32int b, int s)
+{
+ ps &= ~15;
+ switch(s){
+ case 0:
+ if((s8int) a < (s8int) b) ps |= FLAGN;
+ if((u8int) a == (u8int) b) ps |= FLAGZ;
+ if((u8int) a < (u8int) b) ps |= FLAGC;
+ break;
+ case 1:
+ if((s16int) a < (s16int) b) ps |= FLAGN;
+ if((u16int) a == (u16int) b) ps |= FLAGZ;
+ if((u16int) a < (u16int) b) ps |= FLAGC;
+ break;
+ case 2:
+ if((s32int) a < (s32int) b) ps |= FLAGN;
+ if(a == b) ps |= FLAGZ;
+ if(a < b) ps |= FLAGC;
+ break;
+ default:
+ sysfatal("cmp: unimplemented size %d", s);
+ }
+}
+
+static u32int
+mul(u32int a, u32int b, int s)
+{
+ vlong v;
+
+ ps &= ~(FLAGC|FLAGV);
+ switch(s){
+ case 0:
+ v = (s8int) a * (s8int) b;
+ if((uvlong)(v + 0x80) > 0xff) ps |= FLAGV;
+ return v;
+ case 1:
+ v = (s16int) a * (s16int) b;
+ if((uvlong)(v + 0x8000) > 0xffff) ps |= FLAGV;
+ return v;
+ case 2:
+ v = (s32int)a * (s32int) b;
+ if((uvlong)(v + 0x80000000) > 0xffffffff) ps |= FLAGV;
+ return v;
+ default:
+ sysfatal("mul: unimplemented size %d", s);
+ return 0;
+ }
+}
+
+static u32int
+div(u32int a, u32int b, int s)
+{
+ vlong v;
+
+ ps &= ~(FLAGC|FLAGV);
+ switch(s){
+ case 0:
+ if((s8int) a == 0 || (s8int) b == -0x80 && (s8int) a == -1){
+ ps |= FLAGV;
+ return b;
+ }
+ v = (s8int) b / (s8int) a;
+ return v;
+ case 1:
+ if((s16int) b == 0 || (s16int) b == -0x8000 && (s16int) a == -1){
+ ps |= FLAGV;
+ return b;
+ }
+ v = (s16int) b / (s16int) a;
+ return v;
+ case 2:
+ if(b == 0 || (s32int) b == -0x8000 && (s32int) a == -1){
+ ps |= FLAGV;
+ return b;
+ }
+ v = (s32int) b / (s32int) a;
+ return v;
+ default:
+ sysfatal("div: unimplemented size %d", s);
+ return 0;
+ }
+}
+
+static void
+alu(int o, int r, int s)
+{
+ u32int a, b, v;
+ vlong c;
+
+ switch(r){
+ case 1:
+ c = amode(s);
+ if(o == ADD || o == SUB)
+ a = 1;
+ else
+ a = 0;
+ b = readm(c, s);
+ break;
+ case 2:
+ a = readm(amode(s), s);
+ c = amode(s);
+ b = readm(c, s);
+ break;
+ case 3:
+ a = readm(amode(s), s);
+ b = readm(amode(s), s);
+ c = amode(s);
+ break;
+ case 4:
+ a = readm(amode(s), s);
+ if(o == XOR)
+ b = -1;
+ else
+ b = 0;
+ c = amode(s);
+ break;
+ default:
+ sysfatal("alu: unimplemented %d", r);
+ return;
+ }
+ switch(o){
+ case ADD: v = add(a, b, s); break;
+ case SUB: v = subtract(a, b, s); break;
+ case MUL: v = mul(a, b, s); break;
+ case DIV: v = div(a, b, s); break;
+ case CMP: cmp(a, b, s); return;
+ case TST: cmp(b, 0, s); return;
+ case BIC: v = ~a & b; ps &= ~FLAGV; break;
+ case BIS: v = a | b; ps &= ~FLAGV; break;
+ case XOR: v = a ^ b; ps &= ~FLAGV; break;
+ case BIT: nzv(a & b, s); return;
+ default: sysfatal("unimplemented %d in alu", o); v = 0;
+ }
+ nz(v, s);
+ writem(c, v, s);
+}
+
+static void
+ediv(void)
+{
+ s32int divr;
+ vlong divd;
+ vlong q;
+ s32int r;
+ vlong quo, rem;
+
+ divr = readm(amode(2), 2);
+ divd = readm64(amode(3), 3);
+ quo = amode(2);
+ rem = amode(2);
+ ps &= ~15;
+ if(divr == 0){
+ nope:
+ writem(quo, divd, 2);
+ writem(rem, 0, 2);
+ nz(divd, 2);
+ return;
+ }
+ q = divd / divr;
+ r = divd % divr;
+ if((uvlong)(q + 0x80000000) > 0xffffffff)
+ goto nope;
+ writem(quo, q, 2);
+ writem(rem, r, 2);
+ nz(q, 2);
+}
+
+static void
+move(int s)
+{
+ u32int v, w;
+ vlong src, dst;
+
+ src = amode(s);
+ dst = amode(s);
+ if(s != 3){
+ v = readm(src, s);
+ writem(dst, v, s);
+ nzv(v, s);
+ }else{
+ v = readm(src, 2);
+ w = readm(highw(src), 2);
+ writem(dst, v, 2);
+ writem(highw(dst), w, 2);
+ nzv(w, 2);
+ if(v != 0) ps &= ~FLAGZ;
+ }
+}
+
+static void
+cvt(int s, int t)
+{
+ u32int v;
+
+ v = readm(amode(s), s);
+ v = sxt(v, s);
+ writem(amode(t), v, t);
+ nzv(v, t);
+ switch(t){
+ case 0: if((uvlong)(v + 0x80) > 0xff) ps |= FLAGV; break;
+ case 1: if((uvlong)(v + 0x8000) > 0xffff) ps |= FLAGV; break;
+ }
+ ps &= ~FLAGC;
+}
+
+static void
+movez(int s, int t)
+{
+ u32int v;
+
+ v = readm(amode(s), s);
+ writem(amode(t), v, t);
+ nzv(v, t);
+}
+
+static void
+movea(int s)
+{
+ vlong v;
+
+ v = amode(s);
+ if(v < 0) sysfatal("invalid movea (pc=%.8x)", curpc);
+ writem(amode(2), v, 2);
+ nzv(v, 2);
+}
+
+static void
+pusha(int s)
+{
+ vlong v;
+
+ v = amode(s);
+ if(v < 0) sysfatal("invalid pusha (pc=%.8x)", curpc);
+ writem(r[14] -= 4, v, 2);
+ nzv(v, 2);
+}
+
+static void
+pushl(void)
+{
+ u32int v;
+
+ v = readm(amode(2), 2);
+ writem(r[14] -= 4, v, 2);
+ nzv(v, 2);
+}
+
+static void
+branch(int s, int c)
+{
+ int off;
+
+ if(s == 0)
+ off = (s8int) fetch8();
+ else
+ off = (s16int) fetch16();
+ if(c)
+ r[15] += off;
+}
+
+static void
+calls(void)
+{
+ u32int narg, sp;
+ vlong dst;
+ u16int m;
+ int i;
+
+ narg = readm(amode(2), 2);
+ dst = amode(0);
+ if(dst < 0) sysfatal("call to illegal location pc=%.8ux", curpc);
+ writem(r[14] -= 4, narg, 2);
+ sp = r[14];
+ r[14] &= -4;
+ m = readm(dst, 1);
+ for(i = 12; --i >= 0; )
+ if((m & 1<<i) != 0)
+ writem(r[14] -= 4, r[i], 2);
+ writem(r[14] -= 4, r[15], 2);
+ writem(r[14] -= 4, r[13], 2);
+ writem(r[14] -= 4, r[12], 2);
+ ps &= ~0xf;
+ writem(r[14] -= 4, (sp & 3)<<30|1<<29|(m & 0xfff)<<16|ps&~0x10, 2);
+ ps &= ~0xc0;
+ if((m & 0x8000) != 0) ps |= 0x80;
+ if((m & 0x4000) != 0) ps |= 0x40;
+ writem(r[14] -= 4, 0, 2);
+ r[13] = r[14];
+ r[12] = sp;
+ r[15] = dst + 2;
+}
+
+static void
+ret(void)
+{
+ u32int m;
+ u8int n;
+ int i;
+
+ r[14] = r[13] + 4;
+ m = readm(r[14], 2);
+ r[14] += 4;
+ r[12] = readm(r[14], 2); r[14] += 4;
+ r[13] = readm(r[14], 2); r[14] += 4;
+ r[15] = readm(r[14], 2); r[14] += 4;
+ for(i = 0; i < 12; i++)
+ if((m & 1<<16+i) != 0){
+ r[i] = readm(r[14], 2);
+ r[14] += 4;
+ }
+ r[14] += m >> 30;
+ ps = (u16int) m;
+ if((m & 1<<29) != 0){
+ n = readm(r[14], 2);
+ r[14] += 4 + 4 * n;
+ }
+}
+
+static void
+bbs(int inv, int new)
+{
+ u32int pos;
+ vlong base;
+ s8int displ;
+ u32int val;
+
+ pos = readm(amode(2), 2);
+ base = amode(0);
+ displ = fetch8();
+ if(base < 0){
+ if(pos >= 32) sysfatal("invalid bbs (pc=%.8ux)", curpc);
+ val = readm(base, 2);
+ if((val >> pos & 1) != inv)
+ r[15] += displ;
+ if(new != 0){
+ if(new > 0) val |= 1<<pos;
+ else val &= ~(1<<pos);
+ writem(base, val, 2);
+ }
+ }else{
+ base += pos >> 3;
+ pos &= 7;
+ val = readm(base, 0);
+ if((val >> pos & 1) != inv)
+ r[15] += displ;
+ if(new != 0){
+ if(new > 0) val |= 1<<pos;
+ else val &= ~(1<<pos);
+ writem(base, val, 0);
+ }
+ }
+}
+
+static void
+ashl(void)
+{
+ s8int cnt;
+ s32int v;
+
+ cnt = readm(amode(0), 0);
+ v = readm(amode(2), 2);
+ ps &= ~15;
+ if(cnt >= 32){
+ if(v != 0) ps |= FLAGV;
+ v = 0;
+ }else if(cnt >= 0){
+ if(v + (v & 1<<31 >> cnt) != 0)
+ ps |= FLAGV;
+ v <<= cnt;
+ }else if(cnt > -32)
+ v >>= -cnt;
+ else
+ v >>= 31;
+ nz(v, 2);
+ writem(amode(2), v, 2);
+}
+
+static void
+rotl(void)
+{
+ s8int cnt;
+ s32int v;
+
+ cnt = readm(amode(0), 0);
+ v = readm(amode(2), 2);
+ ps &= ~FLAGV;
+ cnt &= 31;
+ v = v << cnt | v >> 32 - cnt;
+ nz(v, 2);
+ writem(amode(2), v, 2);
+}
+
+static void
+ashq(void)
+{
+ s8int cnt;
+ s64int v;
+
+ cnt = readm(amode(0), 0);
+ v = readm64(amode(3), 3);
+ ps &= ~15;
+ if(cnt >= 64){
+ if(v != 0) ps |= FLAGV;
+ v = 0;
+ }else if(cnt >= 0){
+ if(v + (v & 1ULL<<63 >> cnt) != 0)
+ ps |= FLAGV;
+ v <<= cnt;
+ }else if(cnt > -64)
+ v >>= -cnt;
+ else
+ v >>= 63;
+ nz64(v, 3);
+ writem64(amode(3), v, 3);
+}
+
+static void
+blb(int val)
+{
+ u32int v;
+ s8int disp;
+
+ v = readm(amode(2), 2);
+ disp = fetch8();
+ if((v & 1) == val)
+ r[15] += disp;
+}
+
+static void
+sob(int geq)
+{
+ vlong v;
+ s32int i;
+ s8int disp;
+
+ v = amode(2);
+ disp = fetch8();
+ i = readm(v, 2) - 1;
+ writem(v, i, 2);
+ nzv(i, 2);
+ if(i == 0x7fffffff) ps |= FLAGV;
+ if(i > 0 || i == 0 && geq)
+ r[15] += disp;
+}
+
+static void
+aob(int leq)
+{
+ s32int l, v;
+ vlong a;
+ s8int disp;
+
+ l = readm(amode(2), 2);
+ a = amode(2);
+ disp = fetch8();
+ v = readm(a, 2) + 1;
+ writem(a, v, 2);
+ nzv(v, 2);
+ if(v == 0x80000000) ps |= FLAGV;
+ if(v < l || v == l && leq)
+ r[15] += disp;
+}
+
+static void
+bsb(int s)
+{
+ u32int v;
+
+ switch(s){
+ case 0:
+ v = fetch8();
+ writem(r[14] -= 4, r[15], 2);
+ r[15] += (s8int) v;
+ break;
+ case 1:
+ v = fetch16();
+ writem(r[14] -= 4, r[15], 2);
+ r[15] += (s16int) v;
+ break;
+ case 2:
+ v = addrof(amode(0));
+ writem(r[14] -= 4, r[15], 2);
+ r[15] = v;
+ break;
+ }
+}
+
+static void
+casei(int s)
+{
+ u32int sel, base, lim;
+
+ sel = readm(amode(s), s);
+ base = readm(amode(s), s);
+ lim = readm(amode(s), s);
+ sel -= base;
+ if(sel <= lim)
+ r[15] += (s16int) readm(r[15] + 2 * sel, 1);
+ else
+ r[15] += 2 * (lim + 1);
+}
+
+static void
+pushr(void)
+{
+ u16int m;
+ u32int sp;
+ int i;
+
+ m = readm(amode(1), 1);
+ sp = r[14];
+ for(i = 15; --i >= 0; )
+ if((m & 1<<i) != 0)
+ writem(sp -= 4, r[i], 2);
+ r[14] = sp;
+}
+
+static void
+popr(void)
+{
+ u16int m;
+ u32int sp;
+ int i;
+
+ m = readm(amode(1), 1);
+ sp = r[14];
+ for(i = 0; i < 15; i++)
+ if((m & 1<<i) != 0){
+ r[i] = readm(sp, 2);
+ sp += 4;
+ }
+ if((m & 1<<14) == 0)
+ r[14] = sp;
+}
+
+static void
+acb(int s)
+{
+ vlong a;
+ s32int lim, n, v;
+ s16int disp;
+ int c;
+
+ lim = readm(amode(s), s);
+ n = readm(amode(s), s);
+ a = amode(s);
+ v = readm(a, s);
+ disp = fetch16();
+
+ c = ps & FLAGC;
+ v = add(v, n, s);
+ nz(v, s);
+ ps |= c;
+ writem(a, v, s);
+
+ if(n >= 0 && v <= lim || n < 0 && v >= lim)
+ r[15] += disp;
+}
+
+static void
+extv(int sx)
+{
+ u32int pos, v;
+ u8int c;
+ u8int size;
+ int i, s;
+ vlong base;
+ vlong dst;
+
+ pos = readm(amode(2), 2);
+ size = readm(amode(0), 0);
+ base = amode(0);
+ dst = amode(2);
+ if(size > 32 || pos >= 32 && base < 0) sysfatal("extv size=%d pos=%d (pc=%#.8ux)", size, pos, curpc);
+ if(base < 0){
+ v = readm(base, 2) >> pos;
+ if(size < 32)
+ v &= (1<<size) - 1;
+ }else{
+ base += pos >> 3;
+ pos &= 7;
+ v = 0;
+ for(i = 0; i < size; i += s){
+ c = readm(base, 0);
+ c >>= pos;
+ s = 8 - pos;
+ if(s > size) s = size;
+ v |= (c & (1<<s) - 1) << i;
+ base++;
+ pos = 0;
+ }
+ }
+ if(sx)
+ v = (s32int)(v << 32 - size) >> 32 - size;
+ writem(dst, v, 2);
+ ps &= ~FLAGC;
+ nzv(v, 2);
+}
+
+static void
+insv(void)
+{
+ u32int src, pos;
+ u8int size;
+ vlong base;
+ u32int v, m;
+ int i, s;
+
+ src = readm(amode(2), 2);
+ pos = readm(amode(2), 2);
+ size = readm(amode(0), 0);
+ base = amode(0);
+ if(size > 32 || pos >= 32 && base < 0) sysfatal("extv");
+ if(base < 0){
+ v = readm(base, 2);
+ m = (size == 32 ? 0 : 1<<size) - 1 << pos;
+ v = v & ~m | src << pos & m;
+ writem(base, v, 2);
+ }else{
+ base += pos >> 3;
+ pos &= 7;
+ for(i = 0; i < size; i += s){
+ v = readm(base, 0);
+ s = 8 - pos;
+ if(s > size) s = size;
+ m = (1<<s) - 1 << pos;
+ v = v & ~m | src << pos & m;
+ writem(base, v, 0);
+ src >>= s;
+ base++;
+ }
+ }
+ ps &= ~15;
+}
+
+void addp(int, int);
+void editpc(void);
+void cvtlp(void);
+void movp(void);
+void cmpp(int);
+void ashp(void);
+void alufp(int, int, int);
+void movefp(int, int);
+void cvtfp(int, int, int);
+void locc(int);
+void cmpc(int);
+void movc(int);
+void emod(int);
+
+void
+step(void)
+{
+ uchar op;
+
+ curpc = r[15];
+ op = fetch8();
+ if(trace || 0 && op >= 0x40 && op < 0x78)
+ print("%.8ux %.2ux %.2ux %.8ux %.8ux %.8ux %.8ux\n", curpc, op, ps, r[14], r[0], r[1], r[5]);
+ switch(op){
+ case 0x04: ret(); break;
+ case 0x05: r[15] = readm(r[14], 2); r[14] += 4; break;
+ case 0x10: bsb(0); break;
+ case 0x11: branch(0, 1); break;
+ case 0x12: branch(0, (ps & FLAGZ) == 0); break;
+ case 0x13: branch(0, (ps & FLAGZ) != 0); break;
+ case 0x14: branch(0, (ps & (FLAGZ|FLAGN)) == 0); break;
+ case 0x15: branch(0, (ps & (FLAGZ|FLAGN)) != 0); break;
+ case 0x16: bsb(2); break;
+ case 0x17: r[15] = amode(0); break;
+ case 0x18: branch(0, (ps & FLAGN) == 0); break;
+ case 0x19: branch(0, (ps & FLAGN) != 0); break;
+ case 0x1a: branch(0, (ps & (FLAGZ|FLAGC)) == 0); break;
+ case 0x1b: branch(0, (ps & (FLAGZ|FLAGC)) != 0); break;
+ case 0x1c: branch(0, (ps & FLAGV) == 0); break;
+ case 0x1d: branch(0, (ps & FLAGV) != 0); break;
+ case 0x1e: branch(0, (ps & FLAGC) == 0); break;
+ case 0x1f: branch(0, (ps & FLAGC) != 0); break;
+ case 0x20: addp(4, 0); break;
+ case 0x21: addp(6, 0); break;
+ case 0x22: addp(4, 1); break;
+ case 0x23: addp(6, 1); break;
+ case 0x28: movc(0); break;
+ case 0x29: cmpc(0); break;
+ case 0x2c: movc(1); break;
+ case 0x2d: cmpc(1); break;
+ case 0x30: bsb(1); break;
+ case 0x31: branch(1, 1); break;
+ case 0x32: cvt(1, 2); break;
+ case 0x33: cvt(1, 0); break;
+ case 0x34: movp(); break;
+ case 0x35: cmpp(3); break;
+ case 0x37: cmpp(4); break;
+ case 0x38: editpc(); break;
+ case 0x3a: locc(0); break;
+ case 0x3b: locc(1); break;
+ case 0x3c: movez(1, 2); break;
+ case 0x3d: acb(1); break;
+ case 0x3e: movea(1); break;
+ case 0x3f: pusha(1); break;
+ case 0x40: alufp(ADD, 2, 0x12); break;
+ case 0x41: alufp(ADD, 3, 0x12); break;
+ case 0x42: alufp(SUB, 2, 0x12); break;
+ case 0x43: alufp(SUB, 3, 0x12); break;
+ case 0x44: alufp(MUL, 2, 0x12); break;
+ case 0x45: alufp(MUL, 3, 0x12); break;
+ case 0x46: alufp(DIV, 2, 0x12); break;
+ case 0x47: alufp(DIV, 3, 0x12); break;
+ case 0x48: cvtfp(0x12, 0, 0); break;
+ case 0x49: cvtfp(0x12, 1, 0); break;
+ case 0x4a: cvtfp(0x12, 2, 0); break;
+ case 0x4b: cvtfp(0x12, 2, 1); break;
+ case 0x4c: cvtfp(0, 0x12, 0); break;
+ case 0x4d: cvtfp(1, 0x12, 0); break;
+ case 0x4e: cvtfp(2, 0x12, 0); break;
+ case 0x50: movefp(0x12, 0); break;
+ case 0x51: alufp(CMP, 2, 0x12); break;
+ case 0x52: movefp(0x12, 1); break;
+ case 0x53: alufp(CMP, 1, 0x12); break;
+ case 0x54: emod(0x12); break;
+ case 0x56: cvtfp(0x12, 0x13, 0); break;
+ case 0x60: alufp(ADD, 2, 0x13); break;
+ case 0x61: alufp(ADD, 3, 0x13); break;
+ case 0x62: alufp(SUB, 2, 0x13); break;
+ case 0x63: alufp(SUB, 3, 0x13); break;
+ case 0x64: alufp(MUL, 2, 0x13); break;
+ case 0x65: alufp(MUL, 3, 0x13); break;
+ case 0x66: alufp(DIV, 2, 0x13); break;
+ case 0x67: alufp(DIV, 3, 0x13); break;
+ case 0x68: cvtfp(0x13, 0, 0); break;
+ case 0x69: cvtfp(0x13, 1, 0); break;
+ case 0x6a: cvtfp(0x13, 2, 0); break;
+ case 0x6b: cvtfp(0x13, 2, 1); break;
+ case 0x6c: cvtfp(0, 0x13, 0); break;
+ case 0x6d: cvtfp(1, 0x13, 0); break;
+ case 0x6e: cvtfp(2, 0x13, 0); break;
+ case 0x70: movefp(0x13, 0); break;
+ case 0x71: alufp(CMP, 2, 0x13); break;
+ case 0x72: movefp(0x13, 1); break;
+ case 0x73: alufp(CMP, 1, 0x13); break;
+ case 0x74: emod(0x13); break;
+ case 0x76: cvtfp(0x13, 0x12, 0); break;
+ case 0x78: ashl(); break;
+ case 0x79: ashq(); break;
+ case 0x7b: ediv(); break;
+ case 0x7c: writem64(amode(3), 0, 3); nzv(0, 0); break;
+ case 0x7d: move(3); break;
+ case 0x7e: movea(3); break;
+ case 0x7f: pusha(3); break;
+ case 0x80: alu(ADD, 2, 0); break;
+ case 0x81: alu(ADD, 3, 0); break;
+ case 0x82: alu(SUB, 2, 0); break;
+ case 0x83: alu(SUB, 3, 0); break;
+ case 0x84: alu(MUL, 2, 0); break;
+ case 0x85: alu(MUL, 3, 0); break;
+ case 0x86: alu(DIV, 2, 0); break;
+ case 0x87: alu(DIV, 3, 0); break;
+ case 0x88: alu(BIS, 2, 0); break;
+ case 0x89: alu(BIS, 3, 0); break;
+ case 0x8a: alu(BIC, 2, 0); break;
+ case 0x8b: alu(BIC, 3, 0); break;
+ case 0x8c: alu(XOR, 2, 0); break;
+ case 0x8d: alu(XOR, 3, 0); break;
+ case 0x8e: alu(SUB, 4, 0); break;
+ case 0x8f: casei(0); break;
+ case 0x90: move(0); break;
+ case 0x91: alu(CMP, 2, 0); break;
+ case 0x92: alu(XOR, 4, 0); break;
+ case 0x93: alu(BIT, 2, 0); break;
+ case 0x94: writem(amode(0), 0, 0); nzv(0, 0); break;
+ case 0x95: alu(TST, 1, 0); break;
+ case 0x96: alu(ADD, 1, 0); break;
+ case 0x97: alu(SUB, 1, 0); break;
+ case 0x98: cvt(0, 2); break;
+ case 0x99: cvt(0, 1); break;
+ case 0x9a: movez(0, 2); break;
+ case 0x9b: movez(0, 1); break;
+ case 0x9c: rotl(); break;
+ case 0x9d: acb(0); break;
+ case 0x9e: movea(0); break;
+ case 0x9f: pusha(0); break;
+ case 0xa0: alu(ADD, 2, 1); break;
+ case 0xa1: alu(ADD, 3, 1); break;
+ case 0xa2: alu(SUB, 2, 1); break;
+ case 0xa3: alu(SUB, 3, 1); break;
+ case 0xa4: alu(MUL, 2, 1); break;
+ case 0xa5: alu(MUL, 3, 1); break;
+ case 0xa6: alu(DIV, 2, 1); break;
+ case 0xa7: alu(DIV, 3, 1); break;
+ case 0xa8: alu(BIS, 2, 1); break;
+ case 0xa9: alu(BIS, 3, 1); break;
+ case 0xaa: alu(BIC, 2, 1); break;
+ case 0xab: alu(BIC, 3, 1); break;
+ case 0xac: alu(XOR, 2, 1); break;
+ case 0xad: alu(XOR, 3, 1); break;
+ case 0xae: alu(SUB, 4, 1); break;
+ case 0xaf: casei(1); break;
+ case 0xb0: move(1); break;
+ case 0xb1: alu(CMP, 2, 1); break;
+ case 0xb2: alu(XOR, 4, 1); break;
+ case 0xb3: alu(BIT, 2, 1); break;
+ case 0xb4: writem(amode(1), 0, 1); nzv(0, 1); break;
+ case 0xb5: alu(TST, 1, 1); break;
+ case 0xb6: alu(ADD, 1, 1); break;
+ case 0xb7: alu(SUB, 1, 1); break;
+ case 0xba: popr(); break;
+ case 0xbb: pushr(); break;
+ case 0xbc: syscall(readm(amode(1), 1)); break;
+ case 0xc0: alu(ADD, 2, 2); break;
+ case 0xc1: alu(ADD, 3, 2); break;
+ case 0xc2: alu(SUB, 2, 2); break;
+ case 0xc3: alu(SUB, 3, 2); break;
+ case 0xc4: alu(MUL, 2, 2); break;
+ case 0xc5: alu(MUL, 3, 2); break;
+ case 0xc6: alu(DIV, 2, 2); break;
+ case 0xc7: alu(DIV, 3, 2); break;
+ case 0xc8: alu(BIS, 2, 2); break;
+ case 0xc9: alu(BIS, 3, 2); break;
+ case 0xca: alu(BIC, 2, 2); break;
+ case 0xcb: alu(BIC, 3, 2); break;
+ case 0xcc: alu(XOR, 2, 2); break;
+ case 0xcd: alu(XOR, 3, 2); break;
+ case 0xce: alu(SUB, 4, 2); break;
+ case 0xcf: casei(2); break;
+ case 0xd0: move(2); break;
+ case 0xd1: alu(CMP, 2, 2); break;
+ case 0xd2: alu(XOR, 4, 2); break;
+ case 0xd3: alu(BIT, 2, 2); break;
+ case 0xd4: writem(amode(2), 0, 2); nzv(0, 2); break;
+ case 0xd5: alu(TST, 1, 2); break;
+ case 0xd6: alu(ADD, 1, 2); break;
+ case 0xd7: alu(SUB, 1, 2); break;
+ case 0xd8: adwc(); break;
+ case 0xd9: sbwc(); break;
+ case 0xdd: pushl(); break;
+ case 0xde: movea(2); break;
+ case 0xdf: pusha(2); break;
+ case 0xe0: bbs(0, 0); break;
+ case 0xe1: bbs(1, 0); break;
+ case 0xe2: bbs(0, 1); break;
+ case 0xe3: bbs(1, 1); break;
+ case 0xe4: bbs(0, -1); break;
+ case 0xe5: bbs(1, -1); break;
+ case 0xe8: blb(1); break;
+ case 0xe9: blb(0); break;
+ case 0xee: extv(1); break;
+ case 0xef: extv(0); break;
+ case 0xf0: insv(); break;
+ case 0xf1: acb(2); break;
+ case 0xf2: aob(0); break;
+ case 0xf3: aob(1); break;
+ case 0xf4: sob(1); break;
+ case 0xf5: sob(0); break;
+ case 0xf6: cvt(2, 0); break;
+ case 0xf7: cvt(2, 1); break;
+ case 0xf8: ashp(); break;
+ case 0xf9: cvtlp(); break;
+ case 0xfb: calls(); break;
+ default: sysfatal("unimplemented op %.2x (pc=%.8x)", op, curpc);
+ }
+}
--- /dev/null
+++ b/sys/src/games/v8e/cpubcd.c
@@ -1,0 +1,516 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static s8int
+getsign(u16int l, u32int a)
+{
+ u8int c;
+
+ if(l == 0) return 1;
+ c = readm(a + l/2, 0);
+ c &= 0xf;
+ if(c == 11 || c == 13) return -1;
+ return 1;
+}
+
+static int
+getdig(u16int l, u32int a, int i)
+{
+ u8int c;
+
+ if(i >= l) return 0;
+ i = l - 1 - i;
+ if((l & 1) == 0) i++;
+ a += i/2;
+ c = readm(a, 0);
+ if((i & 1) == 0) return c >> 4;
+ return c & 0xf;
+}
+
+static void
+putdig(u16int l, u32int a, int i, int v)
+{
+ u8int c;
+
+ if(i >= l){
+ if(v != 0)
+ ps |= FLAGV;
+ return;
+ }
+ i = l - 1 - i;
+ if((l & 1) == 0) i++;
+ a += i/2;
+ if((l & 1) == 0 && i == 1)
+ c = 0;
+ else
+ c = readm(a, 0);
+ if((i & 1) == 0) c = c & 0x0f | v << 4;
+ else c = c & 0xf0 | v;
+ writem(a, c, 0);
+}
+
+static void
+putsign(u16int l, u32int a, s8int s)
+{
+ u8int c;
+
+ a += l/2;
+ c = readm(a, 0);
+ c = c & 0xf0 | 12 | s < 0;
+ writem(a, c, 0);
+}
+
+static u32int
+sigdig(u16int l, u32int a)
+{
+ u32int e;
+
+ e = a + l/2 + 1;
+ for(; a < e; a++)
+ if(readm(a, 0) != 0)
+ return a;
+ return a;
+}
+
+void
+cvtlp(void)
+{
+ s32int x;
+ u16int l;
+ u32int a;
+ u8int v;
+ int i;
+
+ x = readm(amode(2), 2);
+ l = readm(amode(1), 1);
+ a = addrof(amode(0));
+
+ ps = ps & ~15 | FLAGZ;
+ if(x < 0){
+ x = -x;
+ ps |= FLAGN;
+ }
+ for(i = 0; i < l; i++){
+ v = x % 10;
+ x /= 10;
+ putdig(l, a, i, v);
+ if(v != 0) ps &= ~FLAGZ;
+ }
+ if(x != 0) ps |= FLAGV;
+ if((ps & (FLAGN|FLAGZ)) == 0)
+ ps &= ~FLAGN;
+ putsign(l, a, -((ps & FLAGN) != 0));
+ r[0] = 0;
+ r[1] = 0;
+ r[2] = 0;
+ r[3] = sigdig(l, a);
+}
+
+static uchar
+editread(void)
+{
+ u8int rc;
+
+ if((s32int) r[0] <= 0){
+ if(r[0] == 0)
+ sysfatal("editread");
+ r[0] += 0x10000;
+ return 0;
+ }else{
+ rc = readm(r[1], 0);
+ if((r[0] & 1) != 0)
+ rc >>= 4;
+ else
+ rc &= 0xf;
+ r[0]--;
+ if((r[0] & 1) != 0)
+ r[1]++;
+ return rc;
+ }
+}
+
+void
+editpc(void)
+{
+ u8int p, c;
+ int i;
+
+ r[0] = readm(amode(1), 1);
+ r[1] = addrof(amode(0));
+ r[2] = 0x2020;
+ r[3] = addrof(amode(0));
+ r[5] = addrof(amode(0));
+
+ ps = ps & ~15 | FLAGZ;
+ c = readm(r[1] + r[0]/2, 0) & 0xf;
+ if(c == 11 || c == 13){
+ ps |= FLAGN;
+ r[2] |= 0xd00;
+ }
+
+ for(;;){
+ p = readm(r[3]++, 0);
+ switch(p){
+ case 0x00:
+ if(r[0] != 0) sysfatal("editpc");
+ if((ps & FLAGZ) != 0)
+ ps &= ~FLAGN;
+ return;
+ case 0x01:
+ if((ps & FLAGC) == 0){
+ writem(r[5]++, r[2] >> 8, 0);
+ ps |= FLAGC;
+ }
+ break;
+ case 0x02: ps &= ~FLAGC; break;
+ case 0x03: ps |= FLAGC; break;
+ case 0x04: writem(r[5]++, r[2] >> 8, 0); break;
+ case 0x40: r[2] = r[2] & ~0xff | (u8int)readm(r[3]++, 0); break;
+ case 0x41: r[2] = r[2] & ~0xff00 | (u8int)readm(r[3]++, 0) << 8; break;
+ case 0x42:
+ p = readm(r[3]++, 0);
+ if((ps & FLAGN) == 0)
+ r[2] = r[2] & ~0xff00 | p << 8;
+ break;
+ case 0x43:
+ p = readm(r[3]++, 0);
+ if((ps & FLAGN) != 0)
+ r[2] = r[2] & ~0xff00 | p << 8;
+ break;
+ case 0x44:
+ p = readm(r[3]++, 0);
+ if((ps & FLAGC) != 0)
+ writem(r[5]++, p, 0);
+ else
+ writem(r[5]++, r[2], 0);
+ break;
+ case 0x45:
+ p = readm(r[3]++, 0);
+ if((ps & FLAGZ) != 0){
+ r[5] -= p;
+ while(p-- != 0)
+ writem(r[5]++, r[2], 0);
+ }
+ break;
+ case 0x46:
+ p = readm(r[3]++, 0);
+ if((ps & (FLAGN|FLAGZ)) == (FLAGN|FLAGZ))
+ writem(r[5] - p, r[2], 0);
+ break;
+ case 0x47:
+ p = readm(r[3]++, 0);
+ if((u16int)r[0] > p){
+ r[0] = (u16int) r[0];
+ i = r[0] - p;
+ while(i-- > 0)
+ if(editread() != 0)
+ ps = ps & ~FLAGZ | FLAGV;
+ }else
+ r[0] = (u16int) r[0] | r[0] - p << 16;
+ case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ for(; p > 0x80; p--)
+ writem(r[5]++, r[2], 0);
+ break;
+ case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ for(; p > 0x90; p--){
+ c = editread();
+ if(c != 0) ps = ps & ~FLAGZ | FLAGC;
+ if((ps & FLAGC) == 0)
+ writem(r[5]++, r[2], 0);
+ else
+ writem(r[5]++, '0' + c, 0);
+ }
+ break;
+ case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
+ case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
+ for(; p > 0xa0; p--){
+ c = editread();
+ if(c != 0){
+ if((ps & FLAGC) == 0)
+ writem(r[5]++, r[2] >> 8, 0);
+ ps = ps & ~FLAGZ | FLAGC;
+ }
+ if((ps & FLAGC) == 0)
+ writem(r[5]++, r[2], 0);
+ else
+ writem(r[5]++, '0' + c, 0);
+ }
+ break;
+ default: sysfatal("editpc: unknown pattern %.2x (pc=%.8ux)", p, curpc);
+ }
+ }
+}
+
+void
+movp(void)
+{
+ u16int l;
+ u32int sa, da;
+ u8int c, d;
+ int i, n;
+
+ l = readm(amode(1), 1);
+ sa = addrof(amode(0));
+ da = addrof(amode(1));
+ n = l/2 + 1;
+ ps = ps & ~(FLAGN|FLAGV) | FLAGZ;
+ for(i = 0; i < n-1; i++){
+ c = readm(sa++, 0);
+ writem(da++, c, 0);
+ if(c != 0) ps &= ~FLAGZ;
+ }
+ c = readm(sa, 0);
+ if((c & 0xf0) != 0) ps &= ~FLAGZ;
+ d = c & 0xf0;
+ c &= 0xf;
+ if(c == 11 || c == 13) ps |= FLAGN;
+ if((ps & (FLAGN|FLAGZ)) == (FLAGN|FLAGZ)) ps &= ~FLAGN;
+ if((ps & FLAGN) != 0) d |= 13;
+ else d |= 12;
+ writem(da, d, 0);
+}
+
+
+static int
+cmpmag(u16int l1, u32int a1, u16int l2, u32int a2)
+{
+ int i;
+ u8int c1, c2;
+
+ for(i = l1 > l2 ? l1 : l2; --i >= 0; ){
+ c1 = getdig(l1, a1, i);
+ c2 = getdig(l2, a2, i);
+ if(c1 > c2) return 1;
+ if(c1 < c2) return -1;
+ }
+ return 0;
+}
+
+void
+addp(int rn, int sub)
+{
+ u16int l1, l2, l3;
+ u32int a1, a2, a3;
+ s8int s1, s2;
+ int c, i, l, t;
+
+ l1 = readm(amode(1), 1);
+ a1 = addrof(amode(0));
+ l2 = readm(amode(1), 1);
+ a2 = addrof(amode(0));
+ if(rn == 6){
+ l3 = readm(amode(1), 1);
+ a3 = addrof(amode(0));
+ }else{
+ l3 = l2;
+ a3 = a2;
+ }
+ s1 = getsign(l1, a1);
+ s2 = getsign(l2, a2);
+ r[0] = 0;
+ r[1] = sigdig(l1, a1);
+ r[2] = 0;
+ r[3] = sigdig(l2, a2);
+ r[4] = 0;
+ if(sub) s1 ^= -2;
+ if(s1 == s2){
+ c = 0;
+ l = l1;
+ if(l2 > l) l = l2;
+ if(l3 > l) l = l3;
+ for(i = 0; i < l; i++){
+ t = c + getdig(l1, a1, i) + getdig(l2, a2, i);
+ for(c = 0; t >= 10; c++) t -= 10;
+ putdig(l3, a3, i, t);
+ }
+ }else{
+ if(cmpmag(l1, a1, l2, a2) < 0){
+ t = l1; l1 = l2; l2 = t;
+ t = a1; a1 = a2; a2 = t;
+ s1 = s2;
+ }
+ c = 0;
+ l = l3 > l1 ? l3 : l1;
+ for(i = 0; i < l; i++){
+ t = getdig(l1, a1, i) - getdig(l2, a2, i);
+ for(c = 0; t < 0; c++) t += 10;
+ putdig(l3, a3, i, t);
+ }
+ }
+ if(c != 0) ps |= FLAGV;
+ putsign(l3, a3, s1);
+ r[5] = sigdig(l3, a3);
+}
+
+void
+cmpp(int rn)
+{
+ u16int l1, l2;
+ u32int a1, a2;
+ s8int s1, s2;
+ int rc;
+
+ l1 = readm(amode(1), 1);
+ a1 = addrof(amode(0));
+ if(rn == 4)
+ l2 = readm(amode(1), 1);
+ else
+ l2 = l1;
+ a2 = addrof(amode(0));
+ s1 = getsign(l1, a1);
+ s2 = getsign(l2, a2);
+ r[0] = 0;
+ r[1] = sigdig(l1, a1);
+ r[2] = 0;
+ r[3] = sigdig(l2, a2);
+ ps &= ~15;
+ if(s1 != s2){
+ if(s1 < s2) ps |= FLAGN;
+ return;
+ }
+ rc = cmpmag(l1, a1, l2, a2);
+ if(rc == 0) ps |= FLAGZ;
+ else if(rc > 0) ps |= FLAGN;
+}
+
+void
+ashp(void)
+{
+ s8int cnt, rnd;
+ s16int sl, dl;
+ u32int sa, da;
+ int i, c, x;
+
+ cnt = readm(amode(0), 0);
+ sl = readm(amode(1), 1);
+ sa = addrof(amode(2));
+ rnd = readm(amode(0), 0);
+ dl = readm(amode(1), 1);
+ da = addrof(amode(2));
+ ps = ps & ~15 | FLAGZ;
+ x = getsign(sl, sa);
+ if(x < 0) ps |= FLAGN;
+ putsign(dl, da, x);
+ for(i = 0; i < cnt; i++)
+ putdig(dl, da, i, 0);
+ c = cnt < 0 && getdig(sl, sa, -1-cnt) >= rnd;
+ for(i = cnt >= 0 ? 0 : -cnt; i < sl; i++){
+ x = getdig(sl, sa, i) + c;
+ for(c = 0; x >= 10; c++) x -= 10;
+ putdig(dl, da, i + cnt, x);
+ if(x != 0) ps &= ~FLAGZ;
+ }
+ putdig(dl, da, i + cnt, c);
+ r[0] = 0;
+ r[1] = sigdig(sl, sa);
+ r[2] = 0;
+ r[3] = sigdig(dl, da);
+}
+
+void
+locc(int inv)
+{
+ u8int chr;
+ u16int len;
+ u32int addr;
+
+ chr = readm(amode(0), 0);
+ len = readm(amode(1), 1);
+ addr = addrof(amode(0));
+ ps &= ~15;
+ for(; len != 0; addr++, len--)
+ if(inv ^ (readm(addr, 0) == chr))
+ break;
+ if(len == 0) ps |= FLAGZ;
+ r[0] = len;
+ r[1] = addr;
+}
+
+void
+cmpc(int op5)
+{
+ u16int l1, l2;
+ u32int a1, a2;
+ u8int a, b, f;
+
+ if(op5){
+ l1 = readm(amode(1), 1);
+ a1 = addrof(amode(2));
+ f = readm(amode(0), 0);
+ l2 = readm(amode(1), 1);
+ a2 = addrof(amode(2));
+ }else{
+ l1 = l2 = readm(amode(1), 1);
+ a1 = addrof(amode(2));
+ a2 = addrof(amode(2));
+ f = 0;
+ }
+ a = b = f;
+ for(; l1 > 0 && l2 > 0; l1--, l2--, a1++, a2++){
+ a = readm(a1, 0);
+ b = readm(a2, 0);
+ if(a != b) goto ineq;
+ }
+ for(; l1 > 0; l1--, a1++){
+ a = readm(a1, 0);
+ b = f;
+ if(a != b) goto ineq;
+ }
+ for(; l2 > 0; l2--, a2++){
+ a = f;
+ b = readm(a2, 0);
+ if(a != b) goto ineq;
+ }
+ineq:
+ ps = ps & ~15;
+ if((s8int)a < (s8int)b) ps |= FLAGN;
+ if(a == b) ps |= FLAGZ;
+ if(a < b) ps |= FLAGC;
+ r[0] = l1;
+ r[1] = a1;
+ r[2] = l2;
+ r[3] = a2;
+}
+
+void
+movc(int op5)
+{
+ u16int sl, dl, l;
+ u32int sa, da;
+ int i;
+ u8int f;
+
+ sl = readm(amode(1), 1);
+ sa = addrof(amode(0));
+ if(op5){
+ f = readm(amode(0), 0);
+ dl = readm(amode(1), 1);
+ }else{
+ f = 0;
+ dl = sl;
+ }
+ da = addrof(amode(0));
+ l = sl < dl ? sl : dl;
+ if(sa < da)
+ for(i = l; --i >= 0; )
+ writem(da + i, readm(sa + i, 0), 0);
+ else
+ for(i = 0; i < l; i++)
+ writem(da + i, readm(sa + i, 0), 0);
+ for(i = l; i < dl; i++)
+ writem(da + i, f, 0);
+ r[0] = sl - l;
+ r[1] = sa + sl;
+ r[2] = 0;
+ r[3] = da + dl;
+ r[4] = 0;
+ r[5] = 0;
+ ps &= ~15;
+ if((s16int) sl < (s16int) dl) ps |= FLAGN;
+ else if(sl == dl) ps |= FLAGZ;
+ if(sl < dl) ps |= FLAGC;
+}
--- /dev/null
+++ b/sys/src/games/v8e/cpufp.c
@@ -1,0 +1,521 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+/* BUGS: Not bit accurate. */
+
+enum {
+ ADD,
+ SUB,
+ MUL,
+ DIV,
+ CMP,
+};
+
+enum {
+ EBIAS = 129
+};
+
+#define zero(x) (((x) & 0xff80) == 0)
+#define inval(x) (((x) & 0xff80) == 0x8000)
+#define expo(x) ((x) >> 7 & 0xff)
+#define mantf(x) (1<<23 | ((x) & 0x7f) << 16 | (x) >> 16)
+#define mantd(x) (1ULL<<55|((x)&0x7f)<<48|((x)&0xffff0000)<<16| \
+ (x)>>16&0xffff0000|(u16int)((x)>>48))
+#define sign(x) ((int)x << 16 >> 30 | 1)
+#define makef(s, e, m) ((s)&0x8000|(e)<<7|(m)<<16|(m)>>16&0x7f)
+#define maked(s, e, m) (s&0x8000|(e)<<7|(uvlong)(m)<<48|(uvlong)((m)&0xffff0000)<<16| \
+ (m)>>16&0xffff0000|(m)>>48&0x7f)
+
+static double
+vfc(u32int a)
+{
+ union { u32int a; float b; } u;
+
+ if(zero(a)) return 0;
+ a -= 0x100;
+ u.a = a >> 16 | a << 16;
+ return u.b;
+}
+
+static double
+vdc(u64int a)
+{
+ union { u64int a; double b; } u;
+
+ if(zero(a)) return 0;
+ u.a = mantd(a) >> 3 & (1ULL<<52)-1 | expo(a) + 894 << 52 | sign(a) & 1ULL<<63;
+ return u.b;
+}
+
+static int
+clz32(u32int a)
+{
+ int n;
+ static uchar c[16] = {4, 3, 2, 2, 1, 1, 1, 1};
+
+ n = 0;
+ if((a >> 16) == 0){n += 16; a <<= 16;}
+ if((a >> 24) == 0){n += 8; a <<= 8;}
+ if((a >> 28) == 0){n += 4; a <<= 4;}
+ return n + c[a >> 28];
+}
+
+static int
+clz64(uvlong a)
+{
+ int n;
+ static uchar c[16] = {4, 3, 2, 2, 1, 1, 1, 1};
+
+ n = 0;
+ if((a >> 32) == 0){n += 32; a <<= 32;}
+ if((a >> 48) == 0){n += 16; a <<= 16;}
+ if((a >> 56) == 0){n += 8; a <<= 8;}
+ if((a >> 60) == 0){n += 4; a <<= 4;}
+ return n + c[a >> 60];
+}
+
+static int
+magcmpd(u64int a, u64int b)
+{
+ int e;
+ s64int m;
+
+ e = expo(a) - expo(b);
+ if(e > 0) return 1;
+ if(e < 0) return -1;
+ m = mantd(a) - mantd(b);
+ if(m > 0) return 1;
+ if(m < 0) return -1;
+ return 0;
+}
+
+static int
+cmpd(u64int a, u64int b)
+{
+ int s;
+
+ if(zero(a)){
+ if(zero(b)) return 0;
+ return -sign(b);
+ }
+ if(zero(b)) return sign(a);
+ s = sign(a) - sign(b);
+ if(s > 0) return 1;
+ if(s < 0) return -1;
+ return magcmpd(a, b);
+}
+
+static u32int
+addf(u32int a, u32int b, int sub)
+{
+ int e1, e2, m1, m2, s1, s2;
+ int n;
+ u32int c;
+
+ if(inval(a) || inval(b)) return 0x8000;
+ if(zero(b)) return a;
+ if(sub) b ^= 0x8000;
+ if(zero(a)) return b;
+ if(magcmpd(a, b) < 0){
+ c = a;
+ a = b;
+ b = c;
+ }
+ e1 = expo(a); m1 = mantf(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantf(b); s2 = sign(b);
+ if(e1 - e2 >= 24) return a;
+ m2 >>= e1 - e2;
+ if(s1 == s2)
+ m1 += m2;
+ else
+ m1 -= m2;
+ if(m1 == 0) return 0;
+ n = 8 - clz32(m1);
+ e1 += n;
+ if(n > 0) m1 >>= n;
+ else m1 <<= -n;
+ return makef(s1, e1, m1);
+}
+
+static u32int
+mulf(u32int a, u32int b)
+{
+ int e1, e2, m1, m2, s1, s2, l;
+
+ if(zero(a) || zero(b)) return 0;
+ e1 = expo(a); m1 = mantf(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantf(b); s2 = sign(b);
+ s1 ^= s2 & -2;
+ e1 += e2 - EBIAS;
+ if(e1 <= 0) return 0;
+ l = (uvlong)m1 * m2 + (1<<22) >> 23;
+ if((l & 1<<24) != 0){
+ l >>= 1;
+ e1++;
+ }
+ if(e1 >= 256) return 0x8000;
+ return makef(s1, e1, l);
+}
+
+static u32int
+divf(u32int a, u32int b)
+{
+ int e1, e2, m1, m2, s1, s2;
+ uvlong l;
+
+ if(zero(a)) return 0;
+ if(zero(b)) return 0x8000;
+ e1 = expo(a); m1 = mantf(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantf(b); s2 = sign(b);
+ s1 ^= s2 & -2;
+ e1 -= e2 - EBIAS;
+ l = (uvlong) m1 << 40;
+ l /= m2;
+ l >>= 17;
+ if(l == 0) return 0;
+ while((l & 1<<23) == 0){
+ l <<= 1;
+ e1--;
+ }
+ if(e1 <= 0) return 0;
+ if(e1 >= 256) return 0x8000;
+ return makef(s1, e1, l);
+}
+
+static u64int
+addd(u64int a, u64int b, int sub)
+{
+ int e1, e2, s1, s2;
+ u64int m1, m2;
+ int n;
+ u64int c;
+
+ if(inval(a) || inval(b)) return 0x8000;
+ if(zero(b)) return a;
+ if(sub) b ^= 0x8000;
+ if(zero(a)) return b;
+ if(magcmpd(a, b) < 0){
+ c = a;
+ a = b;
+ b = c;
+ }
+ e1 = expo(a); m1 = mantd(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantd(b); s2 = sign(b);
+ if(e1 - e2 >= 56) return a;
+ m2 >>= e1 - e2;
+ if(s1 == s2)
+ m1 += m2;
+ else
+ m1 -= m2;
+ if(m1 == 0) return 0;
+ n = 8 - clz64(m1);
+ e1 += n;
+ if(n > 0) m1 >>= n;
+ else m1 <<= -n;
+ return maked(s1, e1, m1);
+}
+
+static u64int
+mul55(u64int a, u64int b)
+{
+ u64int l;
+
+ l = (uvlong)(u32int)a * (u32int)b >> 32;
+ l += (a >> 32) * (u32int)b;
+ l += (u32int)a * (b >> 32);
+ l = l + (1<<21) >> 22;
+ l += (a >> 32) * (b >> 32) << 10;
+ l = l + 1 >> 1;
+ return l;
+}
+
+static u64int
+mul62(u64int a, u64int b)
+{
+ u64int l;
+
+ l = (uvlong)(u32int)a * (u32int)b >> 32;
+ l += (a >> 32) * (u32int)b;
+ l += (u32int)a * (b >> 32);
+ l = l + (1<<28) >> 29;
+ l += (a >> 32) * (b >> 32) << 3;
+ l = l + 1 >> 1;
+ return l;
+}
+
+static u64int
+muld(u64int a, u64int b)
+{
+ int e1, e2, s1, s2;
+ uvlong m1, m2;
+ uvlong l;
+
+ if(zero(a) || zero(b)) return 0;
+ e1 = expo(a); m1 = mantd(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantd(b); s2 = sign(b);
+ s1 ^= s2 & -2;
+ e1 += e2 - EBIAS;
+ if(e1 <= 0) return 0;
+ l = mul55(m1, m2);
+ if((l & 1ULL<<56) != 0){
+ l >>= 1;
+ e1++;
+ }
+ if(e1 >= 256) return 0x8000;
+ return maked(s1, e1, l);
+}
+
+static u64int
+divd(u64int a, u64int b)
+{
+ int e1, e2, s1, s2;
+ uvlong m1, m2, l;
+
+ if(zero(a)) return 0;
+ if(zero(b)) return 0x8000;
+ e1 = expo(a); m1 = mantd(a); s1 = sign(a);
+ e2 = expo(b); m2 = mantd(b); s2 = sign(b);
+ s1 ^= s2 & -2;
+ e1 -= e2 - EBIAS;
+ l = (1ULL<<63) / (m2 >> 28) << 26;
+ m2 <<= 7;
+ l = mul62(l, (1ULL<<63) - mul62(l, m2));
+ l = mul62(l, (1ULL<<63) - mul62(l, m2));
+ l = mul62(l, (1ULL<<63) - mul62(l, m2));
+ l = mul62(l, m1 << 7);
+ l += 1<<6;
+ l >>= 7;
+ if(l == 0) return 0;
+ while((l & 1ULL<<55) == 0){
+ l <<= 1;
+ e1--;
+ }
+ if(e1 <= 0) return 0;
+ if(e1 >= 256) return 0x8000;
+ return maked(s1, e1, l);
+}
+
+void
+alufp(int o, int r, int s)
+{
+ u64int a, b, v;
+ vlong c;
+ int i;
+
+ switch(r){
+ case 2:
+ b = readm64(amode(s), s);
+ c = amode(s);
+ a = readm64(c, s);
+ break;
+ case 3:
+ b = readm64(amode(s), s);
+ a = readm64(amode(s), s);
+ c = amode(s);
+ break;
+ default: sysfatal("alufp: r==%d", r);
+ }
+ switch(o){
+ case ADD:
+ if(s == 0x13) v = addd(a, b, 0);
+ else v = addf(a, b, 0);
+ break;
+ case SUB:
+ if(s == 0x13) v = addd(a, b, 1);
+ else v = addf(a, b, 1);
+ break;
+ case MUL:
+ if(s == 0x13) v = muld(a, b);
+ else v = mulf(a, b);
+ break;
+ case DIV:
+ if(s == 0x13) v = divd(a, b);
+ else v = divf(a, b);
+ break;
+ case CMP:
+ ps &= ~15;
+ i = cmpd(b, a);
+ if(i < 0) ps |= FLAGN;
+ if(i == 0) ps |= FLAGZ;
+ return;
+ default:
+ sysfatal("alufp: unimplemented op=%d", o);
+ }
+// print("%.8ux %d %20.16g %20.16g %20.16g\n", curpc, o, vdc(a), vdc(b), vdc(v));
+ ps &= ~15;
+ if(zero(v)) ps |= FLAGZ;
+ if((v & 0x8000) != 0) ps |= FLAGN;
+ writem64(c, v, s);
+}
+
+static u64int
+itof(s32int i)
+{
+ int n;
+ u64int l;
+
+ l = 0;
+ if(i < 0){
+ l |= 0x8000;
+ i = -i;
+ }else if(i == 0)
+ return 0;
+ n = clz32(i);
+ l |= maked(0, 160 - n, (uvlong)i << 24 + n);
+ return l;
+}
+
+static s64int
+ftoi(u64int l)
+{
+ int s, e;
+
+ s = sign(l);
+ e = expo(l);
+ l = mantd(l);
+ if(e >= EBIAS + 64) return 1LL<<63;
+ if(e < EBIAS) return 0;
+ l >>= EBIAS + 55 - e;
+ if(s < 0) return -l;
+ else return l;
+}
+
+void
+cvtfp(int s, int t, int r)
+{
+ u64int l;
+ int si, e;
+
+ switch(s){
+ case 0: l = itof((s8int) readm(amode(0), 0)); break;
+ case 1: l = itof((s16int) readm(amode(1), 1)); break;
+ case 2: l = itof(readm(amode(2), 2)); break;
+ case 0x12: l = readm(amode(2), 2); break;
+ case 0x13: l = readm64(amode(3), 3); break;
+ default: sysfatal("cvtfp: s==%d", s);
+ }
+ if(r) l = addd(l, maked(sign(l), 128, 0), 0);
+ if(t < 0x10) l = ftoi(l);
+ ps &= ~15;
+ switch(t){
+ case 0:
+ if((s64int)l != (s8int)l) ps |= FLAGV;
+ l = (s8int) l;
+ break;
+ case 1:
+ if((s64int)l != (s16int)l) ps |= FLAGV;
+ l = (s16int) l;
+ break;
+ case 2:
+ if((s64int)l != (s32int)l) ps |= FLAGV;
+ l = (s32int) l;
+ break;
+ case 0x12:
+ si = sign(l);
+ e = expo(l);
+ l = mantd(l);
+ l += 1ULL<<31;
+ if((l & 1ULL<<56) != 0){
+ l >>= 1;
+ e++;
+ }
+ l = maked(si, e, l);
+ break;
+ }
+ writem64(amode(t), l, t);
+ if(t >= 0x10){
+ if(zero(l)) ps |= FLAGZ;
+ if((l & 0x8000) != 0) ps |= FLAGN;
+ }else{
+ if(l == 0) ps |= FLAGZ;
+ if((s64int)l < 0) ps |= FLAGN;
+ }
+}
+
+void
+movefp(int t, int n)
+{
+ u64int x;
+
+ x = readm64(amode(t), t);
+ if(inval(x)) sysfatal("invalid float");
+ ps &= ~(FLAGN|FLAGZ|FLAGV);
+ if(zero(x))
+ ps |= FLAGZ;
+ else{
+ if(n) x ^= 0x8000;
+ if((x & 0x8000) != 0) ps |= FLAGN;
+ }
+ writem64(amode(t), x, t);
+}
+
+void
+emod(int s)
+{
+ u64int a, b, m1, m2, l;
+ u8int a8;
+ vlong ai, af;
+ int e1, e2, s1, s2, n;
+
+ a = readm64(amode(s), s);
+ a8 = readm(amode(0), 0);
+ b = readm64(amode(s), s);
+ ai = amode(2);
+ af = amode(s);
+
+ if(zero(a) || zero(b)){
+ ps = ps & ~15 | FLAGZ;
+ writem(ai, 0, 2);
+ writem64(af, 0, s);
+ return;
+ }
+ e1 = expo(a); m1 = mantd(a) << 8 | a8; s1 = sign(a);
+ e2 = expo(b); m2 = mantd(b); s2 = sign(b);
+ s1 ^= s2 & -2;
+ e1 += e2 - EBIAS;
+ if(e1 <= 0){
+ ps = ps & ~15 | FLAGZ;
+ writem(ai, 0, 2);
+ writem64(af, 0, s);
+ return;
+ }
+ l = (uvlong)(u32int)m1 * (u32int)m2 >> 32;
+ l += (m1 >> 32) * (u32int)m2;
+ l += (u32int)m1 * (m2 >> 32);
+ l = l + (1<<29) >> 30;
+ l += (m1 >> 32) * (m2 >> 32) << 2;
+ l = l + 1 >> 1;
+ while((l & 1ULL<<56) != 0){
+ l = l + 1 >> 1;
+ e1++;
+ }
+ if(e1 >= 256){
+ ps |= FLAGV;
+ return;
+ }
+ if(e1 < EBIAS){
+ writem(ai, 0, 2);
+ writem64(af, maked(s1, e1, l), s);
+ if(s1 < 0) ps |= FLAGN;
+ return;
+ }
+ writem(ai, l >> 55+EBIAS-e1, 2);
+ l &= (1ULL<<55+EBIAS-e1) - 1;
+ if(l == 0){
+ writem64(af, 0, s);
+ ps |= FLAGZ;
+ return;
+ }
+ n = clz64(l)-8;
+ l <<= n;
+ e1 -= n;
+ writem64(af, maked(s1, e1, l), s);
+ if(s1 < 0) ps |= FLAGN;
+}
+
+void
+fptest(void)
+{
+}
--- /dev/null
+++ b/sys/src/games/v8e/dat.h
@@ -1,0 +1,57 @@
+typedef char s8int;
+typedef short s16int;
+typedef int s32int;
+typedef vlong s64int;
+
+extern u32int r[16];
+extern u32int ps;
+extern u32int curpc;
+extern int trace;
+
+#define U32(x) ((x)[0] | (x)[1] << 8 | (x)[2] << 16 | (x)[3] << 24)
+
+typedef struct Segment Segment;
+typedef struct Chan Chan;
+
+struct Segment {
+ enum {
+ SEGRO = 1,
+ } flags;
+ u32int start, size;
+ u32int *data;
+};
+
+extern Segment segs[3];
+
+enum {
+ STACKSIZE = 16*1024*1024
+};
+
+enum {
+ EPERM = 1,
+ ENOENT = 2,
+ EIO = 5,
+ EBADF = 9,
+ EINVAL = 22,
+ EMFILE = 24,
+ ENOTTY = 25,
+};
+
+struct Chan {
+ int fd;
+ enum {
+ DONTCLOSE = 1,
+ DIR = 2,
+ FAKETTY = 4,
+ } flags;
+ char *buf, *bufp, *bufe;
+};
+
+enum { NCHANS = 128 };
+
+enum {
+ FLAGN = 8,
+ FLAGZ = 4,
+ FLAGV = 2,
+ FLAGC = 1,
+};
--- /dev/null
+++ b/sys/src/games/v8e/fns.h
@@ -1,0 +1,16 @@
+void step(void);
+u8int memread8(u32int);
+u16int memread16(u32int);
+u32int memread32(u32int);
+void memwrite(u32int, u32int, u32int);
+void syscall(u16int);
+void writem(vlong, u32int, int);
+void *emalloc(ulong);
+void sysinit(void);
+u32int readm(vlong, int);
+u64int readm64(vlong, int);
+u32int addrof(vlong);
+void writem(vlong, u32int, int);
+void writem64(vlong, u64int, int);
+vlong amode(int);
+int load(char *, char **, char **);
--- /dev/null
+++ b/sys/src/games/v8e/mem.c
@@ -1,0 +1,74 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static Segment *
+seglook(u32int a, int n, u32int **lp)
+{
+ Segment *s;
+
+ for(s = segs; s < segs + nelem(segs); s++)
+ if(a >= s->start && a < s->start + s->size)
+ break;
+ if(s == segs + nelem(segs)) return nil;
+ if(a + n > s->start + s->size) return nil;
+ if(lp != nil) *lp = s->data + (a - s->start >> 2);
+ return s;
+}
+
+u8int
+memread8(u32int a)
+{
+ u32int *p;
+
+ if(seglook(a, 1, &p) == nil) sysfatal("invalid read from %.8ux (pc=%.8ux)", a, curpc);
+ switch(a & 3){
+ case 0: return *p;
+ case 1: return *p >> 8;
+ case 2: return *p >> 16;
+ case 3: return *p >> 24;
+ }
+ return 0;
+}
+
+u16int
+memread16(u32int a)
+{
+ u32int *p;
+
+ if(seglook(a, 2, &p) == nil) sysfatal("invalid read from %.8ux (pc=%.8ux)", a, curpc);
+ switch(a & 3){
+ case 0: return *p;
+ case 1: return *p >> 8;
+ case 2: return *p >> 16;
+ case 3: return *p >> 24 | p[1] << 8;
+ }
+ return 0;
+}
+
+u32int
+memread32(u32int a)
+{
+ u32int *p;
+
+ if(seglook(a, 4, &p) == nil) sysfatal("invalid read from %.8ux (pc=%.8ux)", a, curpc);
+ switch(a & 3){
+ case 0: return *p;
+ case 1: return *p >> 8 | p[1] << 24;
+ case 2: return *p >> 16 | p[1] << 16;
+ case 3: return *p >> 24 | p[1] << 8;
+ }
+ return *p;
+}
+
+void
+memwrite(u32int a, u32int v, u32int m)
+{
+ u32int *p;
+ Segment *s;
+
+ s = seglook(a, 4, &p);
+ if(s == nil || (s->flags & SEGRO) != 0) sysfatal("invalid write to %.8ux=%.8ux (mask=%.8ux, pc=%.8ux)", a, v, m, curpc);
+ *p = *p & ~m | v & m;
+}
--- /dev/null
+++ b/sys/src/games/v8e/mkfile
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=v8e
+HFILES=dat.h fns.h
+OFILES=\
+ v8e.$O \
+ cpu.$O \
+ cpubcd.$O \
+ cpufp.$O \
+ mem.$O \
+ sys.$O \
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/games/v8e/sys.c
@@ -1,0 +1,660 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+Chan chans[NCHANS];
+
+int systrace=1;
+#define dprint print
+
+static u32int
+arg(int n)
+{
+ return memread32(r[12] + (n + 1) * 4);
+}
+
+static char *
+strget(u32int addr)
+{
+ int n;
+ char *s;
+
+ for(n = 0; memread8(addr + n) != 0; n++)
+ ;
+ s = emalloc(n + 1);
+ for(n = 0; n == 0 || s[n-1] != 0; n++)
+ s[n] = memread8(addr + n);
+ return s;
+}
+
+static char **
+vecget(u32int addr)
+{
+ int n;
+ u32int u;
+ char **s;
+
+ for(n = 0; readm(addr + n, 2) != 0; n += 4)
+ ;
+ s = emalloc((n + 1) * sizeof(char *));
+ for(n = 0; u = readm(addr + n * 4, 2), u != 0; n++)
+ s[n] = strget(u);
+ return s;
+}
+
+static Chan *
+getfd(int n)
+{
+ if((unsigned)n >= NCHANS || chans[n].fd < 0)
+ return nil;
+ return &chans[n];
+}
+
+static Chan *
+newfd(void)
+{
+ Chan *c;
+
+ for(c = chans; c < chans + nelem(chans); c++)
+ if(c->fd < 0)
+ return c;
+ return nil;
+}
+
+static int
+toerrno(void)
+{
+ char buf[ERRMAX];
+
+ rerrstr(buf, sizeof(buf));
+ if(strstr(buf, "not found")) return -ENOENT;
+ print("couldn't translate %s\n", buf);
+ return -EIO;
+}
+
+static int
+toerrnoi(int rc)
+{
+ if(rc >= 0)
+ return rc;
+ return toerrno();
+}
+
+static int
+dostat(u32int buf, Dir *d)
+{
+ int m;
+
+ if(d == nil) return toerrno();
+ writem(buf, 0, 1); /* dev */
+ writem(buf + 2, d->qid.path, 1); /* ino */
+ m = d->mode & 0777;
+ if((d->mode & DMDIR) != 0) m |= 040000;
+ else m |= 010000;
+ writem(buf + 4, m, 1); /* mode */
+ writem(buf + 6, 1, 1); /* nlink */
+ writem(buf + 8, 0, 1); /* uid */
+ writem(buf + 10, 0, 1); /* gid */
+ writem(buf + 12, d->dev, 1); /* dev */
+ writem(buf + 16, d->length, 2); /* size */
+ writem(buf + 20, d->atime, 2); /* atime */
+ writem(buf + 24, d->mtime, 2); /* mtime */
+ writem(buf + 28, d->mtime, 2); /* ctime */
+ free(d);
+ return 0;
+}
+
+static int
+sysexit(void)
+{
+ int no;
+
+ no = arg(0);
+ if(no == 0) exits(nil);
+ exits(smprint("%d", no));
+ return 0;
+}
+
+static int
+dodirread(Chan *c)
+{
+ Dir *d, *dp;
+ int rc;
+
+ free(c->buf);
+ c->buf = c->bufp = c->bufe = nil;
+ rc = dirread(c->fd, &d);
+ if(rc <= 0) return rc;
+ c->bufp = c->bufe = c->buf = emalloc(16 * rc);
+ for(dp = d; --rc >= 0; dp++){
+ *c->bufe++ = dp->qid.path;
+ *c->bufe++ = dp->qid.path >> 8;
+ strncpy(c->bufe, dp->name, 14);
+ c->bufe += 14;
+ }
+ free(d);
+ return 0;
+}
+
+static int
+sysread(void)
+{
+ int fd, sz, rc, i;
+ u32int addr;
+ char *buf;
+ Chan *c;
+
+ fd = arg(0);
+ addr = arg(1);
+ sz = arg(2);
+ if(systrace) dprint("read(%d, %#ux, %d)\n", fd, addr, sz);
+ c = getfd(fd);
+ if(sz < 0) return -EINVAL;
+ if(c == nil) return -EBADF;
+ if((c->flags & DIR) != 0){
+ if(c->bufp >= c->bufe)
+ if(dodirread(c) < 0)
+ return toerrno();
+ for(rc = 0; sz > 0 && c->bufp < c->bufe; rc++, sz--)
+ writem(addr++, *c->bufp++, 0);
+ return rc;
+ }else{
+ buf = emalloc(sz);
+ rc = read(c->fd, buf, sz);
+ for(i = 0; i < rc; i++)
+ writem(addr + i, buf[i], 0);
+ free(buf);
+ if(rc < 0) return toerrno();
+ }
+ return rc;
+}
+
+static int
+syswrite(void)
+{
+ int fd, sz, rc, i;
+ u32int addr;
+ Chan *c;
+ char *buf;
+
+ fd = arg(0);
+ addr = arg(1);
+ sz = arg(2);
+ if(systrace) dprint("write(%d, %#ux, %d)\n", fd, addr, sz);
+ c = getfd(fd);
+ if(sz < 0) return -EINVAL;
+ if(c == nil) return -EBADF;
+ buf = emalloc(sz);
+ for(i = 0; i < sz; i++)
+ buf[i] = memread8(addr + i);
+ rc = write(c->fd, buf, sz);
+ free(buf);
+ return toerrnoi(rc);
+}
+
+static int
+sysopen(void)
+{
+ char *s;
+ Chan *c;
+ int m;
+ Dir *d;
+
+ s = strget(arg(0));
+ m = arg(1);
+ if(systrace) dprint("open(\"%s\", %#uo)\n", s, m);
+ switch(m){
+ case 0: m = OREAD; break;
+ case 1: m = OWRITE; break;
+ case 2: m = ORDWR; break;
+ default: free(s); return -EINVAL;
+ }
+ c = newfd();
+ if(c == nil){
+ free(s);
+ return -EMFILE;
+ }
+ c->fd = open(s, m);
+ free(s);
+ if(c->fd < 0) return toerrno();
+ d = dirfstat(c->fd);
+ if(d == nil){
+ close(c->fd);
+ return toerrno();
+ }
+ if((d->mode & DMDIR) != 0)
+ c->flags |= DIR;
+ free(d);
+ return c - chans;
+}
+
+static int
+sysclose(void)
+{
+ int fd;
+ Chan *c;
+
+ fd = arg(0);
+ if(systrace) dprint("close(%d)\n", fd);
+ c = getfd(fd);
+ if(c == nil) return -EBADF;
+ if((c->flags & DONTCLOSE) == 0)
+ close(c->fd);
+ c->fd = -1;
+ return 0;
+}
+
+static int
+sysfstat(void)
+{
+ int fd, buf;
+ Chan *c;
+ Dir *d;
+
+ fd = arg(0);
+ buf = arg(1);
+ if(systrace) dprint("fstat(%d, %#ux)\n", fd, buf);
+ c = getfd(fd);
+ if(c == nil) return -EBADF;
+ d = dirfstat(c->fd);
+ return dostat(buf, d);
+}
+
+static int
+syslstat(void)
+{
+ char *s;
+ int buf;
+ Dir *d;
+
+ s = strget(arg(0));
+ buf = arg(1);
+ if(systrace) dprint("lstat(\"%s\", %#ux)\n", s, buf);
+ d = dirstat(s);
+ free(s);
+ return dostat(buf, d);
+}
+
+static int
+sysioctl(void)
+{
+ int fd, ctl;
+ u32int addr;
+ Chan *c;
+
+ fd = arg(0);
+ ctl = arg(1);
+ addr = arg(2);
+ if(systrace) dprint("lstat(%d, %#ux, %#ux)\n", fd, ctl, addr);
+ c = getfd(fd);
+ if(c == nil) return -EBADF;
+ switch(ctl){
+ case 't'<<8|8:
+ if((c->flags & FAKETTY) != 0){
+ writem(addr, 13 | 13<<8 | '#'<<16 | '@'<<24, 2);
+ writem(addr + 4, 06010, 2);
+ return 0;
+ }
+ return -ENOTTY;
+ case 'j'<<8|3: return -EINVAL;
+ default:
+ fprint(2, "unknown ioctl %c%d\n", ctl >> 8, (u8int)ctl);
+ return -EINVAL;
+ }
+}
+
+static int
+systime(void)
+{
+ u32int addr;
+ int t;
+
+ addr = arg(0);
+ if(systrace) dprint("time(%#ux)\n", addr);
+ t = time(0);
+ if(addr != 0) writem(addr, t, 2);
+ return t;
+}
+
+static int
+sysbreak(void)
+{
+ u32int a;
+ int ns;
+
+ a = arg(0);
+ if(systrace) dprint("break(%#ux)\n", a);
+ a = -(-a & -1024);
+ ns = a - segs[1].start;
+ if(ns > segs[1].size){
+ segs[1].data = realloc(segs[1].data, ns);
+ memset((uchar *) segs[1].data + segs[1].size, 0, ns - segs[1].size);
+ segs[1].size = ns;
+ }
+ return 0;
+}
+
+static int
+sysftime(void)
+{
+ u32int p;
+ vlong n;
+ Tm *t;
+
+ p = arg(0);
+ if(systrace) dprint("ftime(%#ux)\n", p);
+ n = nsec();
+ n /= 1000000;
+ writem(p + 4, n % 1000, 1);
+ n /= 1000;
+ writem(p, n, 2);
+ t = localtime(n);
+ writem(p + 6, -t->tzoff / 60, 1);
+ writem(p + 8, 0, 1);
+ return 0;
+}
+
+static int
+syssignal(void)
+{
+ return 0;
+}
+
+static int
+sysgetpid(void)
+{
+ if(systrace) dprint("getpid()\n");
+ return getpid() & 0xffff;
+}
+
+static int
+sysaccess(void)
+{
+ char *s;
+ int m, rc;
+
+ s = strget(arg(0));
+ m = arg(1);
+ if(systrace) dprint("access(\"%s\", %#ux)\n", s, m);
+ rc = access(s, m & 7);
+ free(s);
+ return toerrnoi(rc);
+}
+
+static int
+syscreat(void)
+{
+ char *s;
+ Chan *c;
+ int m;
+
+ s = strget(arg(0));
+ m = arg(1);
+ if(systrace) dprint("creat(\"%s\", %#uo)\n", s, m);
+ c = newfd();
+ if(c == nil){
+ free(s);
+ return -EMFILE;
+ }
+ c->fd = create(s, OWRITE, m & 0777);
+ free(s);
+ if(c->fd < 0) return toerrno();
+ return c - chans;
+}
+
+static int
+sysseek(void)
+{
+ int fd, off, wh;
+ Chan *c;
+
+ fd = arg(0);
+ off = arg(1);
+ wh = arg(2);
+ if(systrace) dprint("seek(%d, %d, %d)\n", fd, off, wh);
+ c = getfd(fd);
+ if(c == nil || off < 0 || (uint)wh > 2) return -EBADF;
+ return toerrnoi(seek(c->fd, off, wh));
+}
+
+static int
+sysunlink(void)
+{
+ char *s;
+ int rc;
+
+ s = strget(arg(0));
+ if(systrace) dprint("unlink(\"%s\")\n", s);
+ rc = remove(s);
+ free(s);
+ return toerrnoi(rc);
+}
+
+static int
+syschdir(void)
+{
+ char *s;
+ int rc;
+
+ s = strget(arg(0));
+ if(systrace) dprint("chdir(\"%s\")\n", s);
+ rc = chdir(s);
+ free(s);
+ return toerrnoi(rc);
+}
+
+static int
+sysgetuid(void)
+{
+ return 0;
+}
+
+static int
+sysfork(void)
+{
+ int rc;
+
+ if(systrace) dprint("fork()\n");
+ rc = fork();
+ if(rc < 0) return toerrno();
+ if(rc == 0){
+ r[1] = 1;
+ return getppid();
+ }
+ r[1] = 0;
+ return rc;
+}
+
+static int
+sysexece(void)
+{
+ char *file, **argv, **env, **p;
+ int rc;
+
+ file = strget(arg(0));
+ argv = vecget(arg(1));
+ env = vecget(arg(2));
+ if(systrace) dprint("exece(\"%s\", ..., ...)\n", file);
+ rc = load(file, argv, env);
+ for(p = argv; *p != nil; p++)
+ free(*p);
+ for(p = env; *p != nil; p++)
+ free(*p);
+ free(file);
+ free(argv);
+ free(env);
+ return toerrnoi(rc);
+}
+
+static int
+syswait(void)
+{
+ Waitmsg *w;
+ int rc, st;
+ u32int addr;
+ char *p;
+
+ addr = arg(0);
+ if(systrace) dprint("wait(%#ux)\n", addr);
+ w = wait();
+ if(w == nil) return toerrno();
+ rc = w->pid;
+ if(addr != 0){
+ st = strtol(w->msg, &p, 10) & 255 << 8;
+ if(*p == 0) st = 127 << 8;
+ writem(addr, st, 2);
+ }
+ free(w);
+ return rc;
+}
+
+int mask = 022;
+static int
+sysumask(void)
+{
+ int rc;
+
+ rc = mask;
+ mask = arg(0);
+ if(systrace) dprint("umask(%#uo)\n", mask);
+ return rc;
+}
+
+static int
+syslink(void)
+{
+ char *a, *b;
+ int f0, f1, rc, n;
+ char buf[8192];
+
+ a = strget(arg(0));
+ b = strget(arg(1));
+ if(systrace) dprint("link(\"%s\", \"%s\")\n", a, b);
+ f0 = open(a, OREAD);
+ f1 = create(b, OWRITE | OEXCL, 0777 ^ mask);
+ if(f0 < 0 || f1 < 0) {
+ err:
+ rc = toerrno();
+ goto out;
+ }
+ for(;;){
+ n = read(f0, buf, sizeof(buf));
+ if(n < 0) goto err;
+ if(n == 0) break;
+ if(write(f1, buf, n) < n) goto err;
+ }
+ rc = 0;
+out:
+ if(f0 >= 0) close(f0);
+ if(f1 >= 0) close(f1);
+ free(a);
+ free(b);
+ return rc;
+}
+
+static int
+syschmod(void)
+{
+ char *a;
+ int mode;
+ Dir d;
+ Dir *e;
+
+ a = strget(arg(0));
+ mode = arg(1);
+ if(systrace) dprint("chmod(\"%s\", %#uo)\n", a, mode);
+ e = dirstat(a);
+ if(e == nil){
+ free(a);
+ return toerrno();
+ }
+ nulldir(&d);
+ d.mode = e->mode & ~0777 | mode & 0777;
+ free(e);
+ if(dirwstat(a, &d) < 0){
+ free(a);
+ return toerrno();
+ }
+ free(a);
+ return 0;
+}
+
+static int
+sysdup(void)
+{
+ int fd;
+ Chan *c, *d;
+
+ fd = arg(0);
+ if(systrace) dprint("dup(%d)\n", fd);
+ c = getfd(fd);
+ if(c == nil) return -EBADF;
+ d = newfd();
+ if(d == nil) return -EMFILE;
+ d->fd = c->fd;
+ d->flags = c->flags;
+ return d - chans;
+}
+
+void
+syscall(u16int c)
+{
+ int rc;
+
+ static int (*calls[])(void) = {
+ [1] sysexit,
+ [2] sysfork,
+ [3] sysread,
+ [4] syswrite,
+ [5] sysopen,
+ [6] sysclose,
+ [7] syswait,
+ [8] syscreat,
+ [9] syslink,
+ [10] sysunlink,
+ [12] syschdir,
+ [13] systime,
+ [15] syschmod,
+ [17] sysbreak,
+ [18] syslstat,
+ [19] sysseek,
+ [20] sysgetpid,
+ [24] sysgetuid,
+ [28] sysfstat,
+ [33] sysaccess,
+ [35] sysftime,
+ [40] syslstat,
+ [41] sysdup,
+ [48] syssignal,
+ [54] sysioctl,
+ [59] sysexece,
+ [60] sysumask,
+ [66] sysfork,
+ };
+
+ if(c >= nelem(calls) || calls[c] == nil) sysfatal("unknown syscall %d", c);
+ rc = calls[c]();
+ if(rc < 0){
+ r[0] = -rc;
+ ps |= 1;
+ }else{
+ r[0] = rc;
+ ps &= ~1;
+ }
+}
+
+void
+sysinit(void)
+{
+ int i;
+
+ for(i = 0; i < NCHANS; i++)
+ chans[i].fd = -1;
+ chans[0].fd = 0;
+ chans[0].flags = DONTCLOSE|FAKETTY;
+ chans[1].fd = 1;
+ chans[1].flags = DONTCLOSE|FAKETTY;
+ chans[2].fd = 2;
+ chans[2].flags = DONTCLOSE|FAKETTY;
+}
--- /dev/null
+++ b/sys/src/games/v8e/v8e.c
@@ -1,0 +1,205 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+Segment segs[3];
+
+void *
+emalloc(ulong n)
+{
+ void *v;
+
+ v = malloc(n);
+ if(v == nil) sysfatal("malloc: %r");
+ memset(v, 0, n);
+ setmalloctag(v, getcallerpc(&n));
+ return v;
+}
+
+enum {
+ OMAGIC = 0407,
+ NMAGIC = 0410,
+ ZMAGIC = 0413,
+};
+
+static int
+readn32(int fd, u32int *l, int sz)
+{
+ static uchar buf[8192];
+ uchar *p;
+ int n, rc;
+
+ while(sz > 0){
+ n = 8192;
+ if(n > sz) n = sz;
+ rc = readn(fd, buf, n);
+ if(rc < 0) return -1;
+ if(rc < n){
+ werrstr("unexpected eof");
+ return -1;
+ }
+ sz -= n;
+ p = buf;
+ for(; n >= 4; n -= 4){
+ *l++ = U32(p);
+ p += 4;
+ }
+ switch(n){
+ case 1: *l = p[0]; break;
+ case 2: *l = p[0] | p[1] << 8; break;
+ case 3: *l = p[0] | p[1] << 8 | p[2] << 16; break;
+ }
+ }
+ return 0;
+}
+
+static void
+setupstack(char **argv)
+{
+ u32int *nargv;
+ int i, j;
+ int argc;
+
+ r[14] = 0x7ffff400;
+ #define push32(x) { r[14] -= 4; memwrite(r[14], x, -1); }
+ for(argc = 0; argv[argc] != nil; argc++)
+ ;
+ nargv = emalloc(sizeof(u32int) * argc);
+ for(i = argc; --i >= 0; ){
+ r[14] -= strlen(argv[i]) + 1;
+ nargv[i] = r[14];
+ for(j = 0; argv[i][j] != 0; j++)
+ writem(r[14] + j, argv[i][j], 0);
+ }
+ r[14] &= -4;
+ push32(0);
+ push32(0);
+ push32(0);
+ for(i = argc; --i >= 0; )
+ push32(nargv[i]);
+ push32(argc);
+ free(nargv);
+}
+
+static int
+shload(int fd, char *file, char **argv, char **envp)
+{
+ char buf[256];
+ char *s, *a;
+ char *p;
+ int rc;
+ char **nargv, **pp;
+ int n;
+
+ rc = read(fd, buf, sizeof(buf) - 1);
+ if(rc <= 0){
+ werrstr("invalid magic");
+ return -1;
+ }
+ close(fd);
+ buf[rc] = 0;
+ p = strchr(buf, '\n');
+ if(p == nil) *p = 0;
+ p = buf;
+ while(isspace(*p)) p++;
+ s = p;
+ while(*p != 0 && !isspace(*p)) p++;
+ if(*p != 0){
+ *p = 0;
+ while(isspace(*p)) p++;
+ if(*p != 0){
+ a = p;
+ while(*p != 0 && !isspace(*p)) p++;
+ }else a = nil;
+ }else a = nil;
+ for(n = 0; argv[n] != nil; n++)
+ ;
+ nargv = emalloc((n + 3) * sizeof(char *));
+ pp = nargv;
+ *pp++ = s;
+ if(a != nil) *pp++ = a;
+ while(n--)
+ *pp++ = *argv++;
+ load(s, nargv, envp);
+ free(nargv);
+ return 0;
+}
+
+int
+load(char *file, char **argv, char **envp)
+{
+ uchar hdr[32];
+ int fd;
+ u32int hmagic, htext, hdata, hbss, hentry;
+
+ fd = open(file, OREAD);
+ if(fd < 0) return -1;
+ if(readn(fd, hdr, 2) < 2) return -1;
+ if(hdr[0] == '#' && hdr[1] == '!')
+ return shload(fd, file, argv, envp);
+ if(readn(fd, hdr + 2, 30) < 30) return -1;
+ hmagic = U32(&hdr[0]);
+ htext = U32(&hdr[4]);
+ hdata = U32(&hdr[8]);
+ hbss = U32(&hdr[12]);
+ hentry = U32(&hdr[20]);
+ switch(hmagic){
+ case ZMAGIC: case OMAGIC: case NMAGIC: break;
+ default:
+ werrstr("invalid magic %.6o", hmagic);
+ return -1;
+ }
+ free(segs[0].data);
+ free(segs[1].data);
+ free(segs[2].data);
+ segs[0].start = 0;
+ segs[0].size = htext;
+ segs[0].data = emalloc(-(-htext & -4));
+ segs[1].start = -(-htext & -1024);
+ segs[1].size = hdata + hbss;
+ segs[1].data = emalloc(-(-(hdata + hbss) & -4));
+ segs[2].start = 0x7ffff400 - STACKSIZE;
+ segs[2].size = STACKSIZE;
+ segs[2].data = emalloc(STACKSIZE);
+ if(hmagic != OMAGIC)
+ segs[0].flags = SEGRO;
+ if(hmagic == ZMAGIC)
+ seek(fd, 1024, 0);
+ if(readn32(fd, segs[0].data, htext) < 0) exits(smprint("%r"));
+ if(readn32(fd, segs[1].data, hdata) < 0) exits(smprint("%r"));
+ close(fd);
+ memset(r, 0, sizeof(r));
+ r[15] = hentry + 2;
+ setupstack(argv);
+ return 0;
+}
+
+static void
+usage(void)
+{
+ sysfatal("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ extern void fptest(void);
+
+ rfork(RFNAMEG);
+ fptest();
+ ARGBEGIN{
+ case 'N':
+ if(addns(nil, EARGF(usage())) < 0)
+ sysfatal("addns: %r");
+ break;
+ default: usage();
+ }ARGEND;
+
+ if(argc < 1) usage();
+ sysinit();
+ if(load(argv[0], argv, nil) < 0) sysfatal("load: %r");
+ for(;;) step();
+}