diff options
Diffstat (limited to 'main.myr')
| -rw-r--r-- | main.myr | 578 |
1 files changed, 318 insertions, 260 deletions
@@ -12,277 +12,335 @@ const memsz = 4096 const stksz = 16 const regsz = 16 +const fntoff = 0x50 +const fntsz = 80 +const fnt = [ + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80 // F +]; + const clrscr = {b, n - var i - for i = 0; i < n; i++; - b#[i] = 0 - ;; + var i + for i = 0; i < n; i++; + b#[i] = 0 + ;; } const loadprg = {b, fname - var fd, i, buf - match std.open(fname, std.Oread) - | `std.Ok(n): fd = n - | `std.Err(errno): - std.fatal("could not open {}\n", fname) - ;; + var fd, i, buf + match std.open(fname, std.Oread) + | `std.Ok(n): fd = n + | `std.Err(errno): + std.fatal("could not open {}\n", fname) + ;; - buf = std.slalloc(0xfff - 0x200) - match std.read(fd, buf) - | `std.Ok(n): - for i = 0; i < 0xfff - 0x200; i++; - b#[i + 0x200] = (buf[i] : uint8) - ;; - | `std.Err(n): - std.fatal("could not read {}\n", fname) - ;; + buf = std.slalloc(0xfff - 0x200) + match std.read(fd, buf) + | `std.Ok(n): + for i = 0; i < 0xfff - 0x200; i++; + b#[i + 0x200] = (buf[i] : uint8) + ;; + | `std.Err(n): + std.fatal("could not read {}\n", fname) + ;; } -const main = { - var win, r, tex - sdl.init(sdl.INIT_VIDEO) - win = sdl.mkwin(("chip\0" : byte#), - sdl.WIN_POS_UNSPEC, - sdl.WIN_POS_UNSPEC, - winwidth, - winheight, - sdl.WIN_OPENGL) - r = sdl.mkrenderer(win, -1, sdl.RENDERER_ACCEL) - tex = sdl.mktexture(r, sdl.PIXFMT_RGB332, sdl.TEXACCESS_STREAM, 64, 32) +const loadfnt = {b + var i + for i = 0; i < fntsz; i++; + b#[i+fntoff] = fnt[i] + ;; +} - var gfx : uint8[scrsz] - var mem : uint8[memsz] - var reg : uint8[regsz] - var stk : uint16[stksz] - var pc : uint16 = 0x200 - var sp : uint16 = 0 - var I : uint16 = 0 - var delay : uint8 = 0 - var sound : uint8 = 0 +const getkeys = { + var state = sdl.getkbd() + -> [ + state#[sdl.SCANCODE_1], + state#[sdl.SCANCODE_2], + state#[sdl.SCANCODE_3], + state#[sdl.SCANCODE_4], + state#[sdl.SCANCODE_Q], + state#[sdl.SCANCODE_W], + state#[sdl.SCANCODE_E], + state#[sdl.SCANCODE_R], + state#[sdl.SCANCODE_A], + state#[sdl.SCANCODE_S], + state#[sdl.SCANCODE_D], + state#[sdl.SCANCODE_F], + state#[sdl.SCANCODE_Z], + state#[sdl.SCANCODE_X], + state#[sdl.SCANCODE_C], + state#[sdl.SCANCODE_V], + state#[sdl.SCANCODE_ESC], + ] +} + +const main = { + var win, r, tex + sdl.init(sdl.INIT_VIDEO) + win = sdl.mkwin(("chip\0" : byte#), + sdl.WIN_POS_UNSPEC, + sdl.WIN_POS_UNSPEC, + winwidth, + winheight, + sdl.WIN_OPENGL) + r = sdl.mkrenderer(win, -1, sdl.RENDERER_ACCEL) + tex = sdl.mktexture(r, sdl.PIXFMT_RGB332, sdl.TEXACCESS_STREAM, 64, 32) - clrscr(&gfx, scrsz) - loadprg(&mem, "/tmp/UFO") + var gfx : uint8[scrsz] + var mem : uint8[memsz] + var reg : uint8[regsz] + var stk : uint16[stksz] + var pc : uint16 = 0x200 + var sp : uint16 = 0 + var I : uint16 = 0 + var delay : uint8 = 0 + var sound : uint8 = 0 + var keys - var opcode, arg + clrscr(&gfx, scrsz) + loadprg(&mem, "/tmp/UFO") + loadfnt(&mem) - while true - sdl.delay(1000) - opcode = mem[pc] - arg = mem[pc + 1] - std.put("\x1b[H\x1b[2J") - std.put("v0: {}\n", reg[0]) - std.put("v1: {}\n", reg[1]) - std.put("v2: {}\n", reg[2]) - std.put("v3: {}\n", reg[3]) - std.put("v4: {}\n", reg[4]) - std.put("v5: {}\n", reg[5]) - std.put("v6: {}\n", reg[6]) - std.put("v7: {}\n", reg[7]) - std.put("v8: {}\n", reg[8]) - std.put("v9: {}\n", reg[9]) - std.put("va: {}\n", reg[10]) - std.put("vb: {}\n", reg[11]) - std.put("vc: {}\n", reg[12]) - std.put("vd: {}\n", reg[13]) - std.put("ve: {}\n", reg[14]) - std.put("vf: {}\n", reg[15]) - std.put("\n") - std.put("I: {}, d: {}, s: {}\n", I, delay, sound) - std.put("sp: {}, stk: {}\n", sp, stk) - std.put("{p=0,x}: {p=0,x} {p=0,x}\n", pc, opcode, arg) - match (opcode & 0xf0) >> 4 - | 0x0: - // CLS - if (opcode & 0x0f) == 0 && (arg & 0x0f) == 0 - clrscr(&gfx, scrsz) - // RET - elif (opcode & 0x0f) == 0 - if sp == 0 - std.die("stack underflow") - ;; - pc = stk[sp] - sp-- - // SYS - else - std.die("RCA 1802 SYS unimplemted") - ;; - // JP - | 0x1: - pc = (opcode & 0x0f : uint16) - pc <<= 8 - pc |= (arg : uint16) - pc -= 2 - // CALL - | 0x2: - sp++ - if sp >= stksz - std.die("stack overflow") - ;; - stk[sp] = pc - pc = (opcode & 0x0f : uint16) - pc <<= 8 - pc |= (arg : uint16) - pc -= 2 - // SE - | 0x3: - if reg[opcode & 0x0f] == arg - pc += 2 - ;; - // SNE - | 0x4: - if reg[opcode & 0x0f] != arg - pc += 2 - ;; - // SE - | 0x5: - if reg[opcode & 0x0f] == reg[(arg & 0xf0) >> 4] - pc += 2 - ;; - // LD - | 0x6: - reg[opcode & 0x0f] = arg - // ADD (without overflow) - | 0x7: - reg[opcode & 0x0f] += arg - | 0x8: - match arg & 0x0f - // LD - | 0x0: - reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 8] - // OR - | 0x1: - reg[opcode & 0x0f] |= reg[(arg & 0xf0) >> 8] - // AND - | 0x2: - reg[opcode & 0x0f] &= reg[(arg & 0xf0) >> 8] - // XOR - | 0x3: - reg[opcode & 0x0f] ^= reg[(arg & 0xf0) >> 8] - // ADD - | 0x4: - if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 8] - reg[0xf] = 1 - else - reg[0xf] = 0 - ;; - reg[opcode & 0x0f] += reg[(arg & 0xf0) >> 8] - // SUB - | 0x5: - if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 8] - reg[0xf] = 1 - else - reg[0xf] = 0 - ;; - reg[opcode & 0x0f] -= reg[(arg & 0xf0) >> 8] - // SHR - | 0x6: - reg[0xf] = reg[opcode & 0x0f] & 1 - reg[opcode & 0x0f] >>= 1 - // SUBN - | 0x7: - if (0xff - reg[(arg & 0xf0) >> 8]) < reg[opcode & 0x0f] - reg[0xf] = 1 - else - reg[0xf] = 0 - ;; - reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 8] - reg[opcode & 0x0f] - // SHL - | 0xe: - reg[0xf] = reg[opcode & 0x0f] & (1 << 7) - reg[opcode & 0x0f] <<= 1 - | _: std.die("unimplemented opcode") - ;; - // SNE - | 0x9: - if reg[opcode & 0x0f] != reg[(arg & 0xf0) >> 4] - pc += 2 - ;; - // LD (I) - | 0xa: - I = (opcode & 0x0f : uint16) - I <<= 8 - I |= (arg : uint16) - // JP + V0 - | 0xb: - pc = (opcode & 0x0f : uint16) - pc <<= 8 - pc |= (arg : uint16) - pc += (reg[0] : uint16) - pc -= 2 - // RND - | 0xc: - // HACK: SIGFPE when calling std.rand(0, 256) - reg[opcode & 0x0f] = (std.rand(0, 255) + std.rand(0, 2)) & arg - // DRW - | 0xd: - var x = (reg[opcode & 0x0f] : uint16) - var y = (reg[(arg & 0xf0) >> 8] : uint16) - var n = (arg & 0x0f : uint16) - var i, j - for i = 0; i < n; i++; - for j = 0; j < 8; j++ - if (y + i) * scrwidth + x + j < scrsz - if mem[I + i * 8 + j] != 0 - gfx[(y + i) * scrwidth + x + j] = 0xff - else - gfx[(y + i) * scrwidth + x + j] = 0x00 - ;; - ;; - ;; - ;; - sdl.update(tex, (gfx[:] : void#), 64) - sdl.copy(r, tex) - sdl.present(r) - | 0xe: - // SKP - if arg == 0x9e - // SKNP - elif arg == 0xa1 - pc += 2 - else - std.die("unimplemented opcode") - ;; - | 0xf: - match arg - | 0x07: - reg[opcode & 0x0f] = delay - | 0x0a: - std.die("unimplemented opcode") - | 0x15: - delay = reg[opcode & 0x0f] - | 0x18: - sound = reg[opcode & 0x0f] - | 0x1e: - // TODO: Deal with overflow - I += (reg[opcode & 0x0f] : uint16) - | 0x29: - // TODO - I = 0 - | 0x33: - // TODO - | 0x55: - // TODO - | 0x65: - // TODO - | _: - std.die("unimplemented opcode") - ;; - | _ : std.die("unimplemented opcode") - ;; - pc += 2 - if delay > 0 - delay-- - ;; - if sound > 0 - sound-- - ;; - ;; + var opcode, arg - /* sdl.update(tex, (gfx[:] : void#), 64) */ - /* sdl.copy(r, tex) */ - /* sdl.present(r) */ + while true + opcode = mem[pc] + arg = mem[pc + 1] + keys = getkeys() + sdl.delay(2) + if keys[0x10] != 0 + break + ;; + match (opcode & 0xf0) >> 4 + | 0x0: + // CLS + if (opcode & 0x0f) == 0 && (arg & 0x0f) == 0 + clrscr(&gfx, scrsz) + // RET + elif (opcode & 0x0f) == 0 + if sp == 0 + std.die("stack underflow") + ;; + sp-- + pc = stk[sp] + // SYS + else + std.die("RCA 1802 SYS unimplented") + ;; + // JP + | 0x1: + pc = (opcode & 0x0f : uint16) + pc <<= 8 + pc |= (arg : uint16) + pc -= 2 + // CALL + | 0x2: + if sp >= stksz + std.die("stack overflow") + ;; + stk[sp] = pc + sp++ + pc = (opcode & 0x0f : uint16) + pc <<= 8 + pc |= (arg : uint16) + pc -= 2 + // SE + | 0x3: + if reg[opcode & 0x0f] == arg + pc += 2 + ;; + // SNE + | 0x4: + if reg[opcode & 0x0f] != arg + pc += 2 + ;; + // SE + | 0x5: + if reg[opcode & 0x0f] == reg[(arg & 0xf0) >> 4] + pc += 2 + ;; + // LD + | 0x6: + reg[opcode & 0x0f] = arg + // ADD (without overflow) + | 0x7: + reg[opcode & 0x0f] += arg + | 0x8: + match arg & 0x0f + // LD + | 0x0: + reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 4] + // OR + | 0x1: + reg[opcode & 0x0f] |= reg[(arg & 0xf0) >> 4] + // AND + | 0x2: + reg[opcode & 0x0f] &= reg[(arg & 0xf0) >> 4] + // XOR + | 0x3: + reg[opcode & 0x0f] ^= reg[(arg & 0xf0) >> 4] + // ADD + | 0x4: + if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 4] + reg[0xf] = 1 + else + reg[0xf] = 0 + ;; + reg[opcode & 0x0f] += reg[(arg & 0xf0) >> 4] + // SUB + | 0x5: + if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 4] + reg[0xf] = 1 + else + reg[0xf] = 0 + ;; + reg[opcode & 0x0f] -= reg[(arg & 0xf0) >> 4] + // SHR + | 0x6: + reg[0xf] = reg[opcode & 0x0f] & 1 + reg[opcode & 0x0f] >>= 1 + // SUBN + | 0x7: + if (0xff - reg[(arg & 0xf0) >> 4]) < reg[opcode & 0x0f] + reg[0xf] = 1 + else + reg[0xf] = 0 + ;; + reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 4] - reg[opcode & 0x0f] + // SHL + | 0xe: + reg[0xf] = reg[opcode & 0x0f] & (1 << 7) + reg[opcode & 0x0f] <<= 1 + | _: std.die("unimplemented opcode") + ;; + // SNE + | 0x9: + if reg[opcode & 0x0f] != reg[(arg & 0xf0) >> 4] + pc += 2 + ;; + // LD (I) + | 0xa: + I = (opcode & 0x0f : uint16) + I <<= 8 + I |= (arg : uint16) + // JP + V0 + | 0xb: + pc = (opcode & 0x0f : uint16) + pc <<= 8 + pc |= (arg : uint16) + pc += (reg[0] : uint16) + pc -= 2 + // RND + | 0xc: + // HACK: SIGFPE when calling std.rand(0, 256) + reg[opcode & 0x0f] = (std.rand(0, 255) + std.rand(0, 2)) & arg + // DRW + | 0xd: + var x = (reg[opcode & 0x0f] : uint16) + var y = (reg[(arg & 0xf0) >> 4] : uint16) + var n = (arg & 0x0f : uint16) + var i, j + reg[0xf] = 0 + for i = 0; i < n; i++; + for j = 0; j < 8; j++; + if (y + i) * scrwidth + x + j < scrsz + if mem[I + i] & ((0x80 >> j) : uint8) != 0 + if gfx[(y + i) * scrwidth + x + j] != 0 + reg[0xf] = 1 + ;; + gfx[(y + i) * scrwidth + x + j] ^= 0xff + ;; + ;; + ;; + ;; + sdl.update(tex, (gfx[:] : void#), 64) + sdl.copy(r, tex) + sdl.present(r) + | 0xe: + // SKP + if arg == 0x9e + if keys[reg[opcode & 0x0f]] != 0 + pc += 2 + ;; + // SKNP + elif arg == 0xa1 + if keys[reg[opcode & 0x0f]] == 0 + pc += 2 + ;; + else + std.die("unimplemented opcode") + ;; + | 0xf: + match arg + // LD + | 0x07: + reg[opcode & 0x0f] = delay + // LD + | 0x0a: + std.die("unimplemented opcode") + // LD + | 0x15: + delay = reg[opcode & 0x0f] + // LD + | 0x18: + sound = reg[opcode & 0x0f] + // ADD + | 0x1e: + I += (reg[opcode & 0x0f] : uint16) + if I > 0xfff + reg[0xf] = 1 + ;; + // LD + | 0x29: + I = fntoff + 5 * (reg[opcode & 0x0f] : uint16) + // BCD + | 0x33: + mem[I] = reg[(opcode & 0x0f)] / 100 + mem[I + 1] = (reg[(opcode & 0x0f)] % 100) / 10 + // HACK: Assembler error on (opcode & 0x0f) % 10 + mem[I + 2] = reg[(opcode & 0x0f)] - mem[I + 1] * 10 - mem[I] * 100 + // LD + | 0x55: + var i + for i = 0; i <= ((opcode & 0x0f) : uint16); i++; + mem[I + i] = reg[i] + ;; + // LD + | 0x65: + var i + for i = 0; i <= ((opcode & 0x0f) : uint16); i++; + reg[i] = mem[I + i] + ;; + | _: + std.die("unimplemented opcode") + ;; + | _ : std.die("unimplemented opcode") + ;; + pc += 2 + if delay > 0 + delay-- + ;; + if sound > 0 + sound-- + ;; + ;; - sdl.freerenderer(r) - sdl.freewin(win) - sdl.quit() + sdl.freerenderer(r) + sdl.freewin(win) + sdl.quit() } |