diff options
author | aiju <devnull@localhost> | 2020-01-22 13:09:09 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2020-01-22 13:09:09 +0000 |
commit | 6f80913ac72490cca7645b85b64de5ed52a7ce91 (patch) | |
tree | 65d09fadb0abc42bb7788021c21602ed414dc111 /sys/src/games | |
parent | 1ecdf09aeeb16dd359251e3e698c8ea7798bd285 (diff) |
add v8e
Diffstat (limited to 'sys/src/games')
-rw-r--r-- | sys/src/games/mkfile | 1 | ||||
-rw-r--r-- | sys/src/games/v8e/cpu.c | 1166 | ||||
-rw-r--r-- | sys/src/games/v8e/cpubcd.c | 516 | ||||
-rw-r--r-- | sys/src/games/v8e/cpufp.c | 521 | ||||
-rw-r--r-- | sys/src/games/v8e/dat.h | 57 | ||||
-rw-r--r-- | sys/src/games/v8e/fns.h | 16 | ||||
-rw-r--r-- | sys/src/games/v8e/mem.c | 74 | ||||
-rw-r--r-- | sys/src/games/v8e/mkfile | 14 | ||||
-rw-r--r-- | sys/src/games/v8e/sys.c | 660 | ||||
-rw-r--r-- | sys/src/games/v8e/v8e.c | 205 |
10 files changed, 3230 insertions, 0 deletions
diff --git a/sys/src/games/mkfile b/sys/src/games/mkfile index 7add7a98a..48f720677 100644 --- a/sys/src/games/mkfile +++ b/sys/src/games/mkfile @@ -48,6 +48,7 @@ DIRS=\ sokoban\ sudoku\ timmy\ + v8e\ 4s.$O 5s.$O xs.$O: xs.h $O.4s $O.5s: xs.$O diff --git a/sys/src/games/v8e/cpu.c b/sys/src/games/v8e/cpu.c new file mode 100644 index 000000000..2e1fe8fba --- /dev/null +++ b/sys/src/games/v8e/cpu.c @@ -0,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); + } +} diff --git a/sys/src/games/v8e/cpubcd.c b/sys/src/games/v8e/cpubcd.c new file mode 100644 index 000000000..b5969c388 --- /dev/null +++ b/sys/src/games/v8e/cpubcd.c @@ -0,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; +} diff --git a/sys/src/games/v8e/cpufp.c b/sys/src/games/v8e/cpufp.c new file mode 100644 index 000000000..2e29ac647 --- /dev/null +++ b/sys/src/games/v8e/cpufp.c @@ -0,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) +{ +} diff --git a/sys/src/games/v8e/dat.h b/sys/src/games/v8e/dat.h new file mode 100644 index 000000000..5a07dd6f2 --- /dev/null +++ b/sys/src/games/v8e/dat.h @@ -0,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, +}; diff --git a/sys/src/games/v8e/fns.h b/sys/src/games/v8e/fns.h new file mode 100644 index 000000000..6cd0c9ab0 --- /dev/null +++ b/sys/src/games/v8e/fns.h @@ -0,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 **); diff --git a/sys/src/games/v8e/mem.c b/sys/src/games/v8e/mem.c new file mode 100644 index 000000000..5286d597b --- /dev/null +++ b/sys/src/games/v8e/mem.c @@ -0,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; +} diff --git a/sys/src/games/v8e/mkfile b/sys/src/games/v8e/mkfile new file mode 100644 index 000000000..dc4d45d40 --- /dev/null +++ b/sys/src/games/v8e/mkfile @@ -0,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 diff --git a/sys/src/games/v8e/sys.c b/sys/src/games/v8e/sys.c new file mode 100644 index 000000000..23032a3e8 --- /dev/null +++ b/sys/src/games/v8e/sys.c @@ -0,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; +} diff --git a/sys/src/games/v8e/v8e.c b/sys/src/games/v8e/v8e.c new file mode 100644 index 000000000..f367be2cf --- /dev/null +++ b/sys/src/games/v8e/v8e.c @@ -0,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(); +} |