use std use sdl const winwidth = 960 const winheight = 480 const scrwidth = 64 const scrheight = 32 const scrsz = scrwidth * scrheight const memsz = 4096 const stksz = 16 const regsz = 16 const clrscr = {b, n 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) ;; 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) 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 clrscr(&gfx, scrsz) loadprg(&mem, "/tmp/UFO") var opcode, arg 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-- ;; ;; /* sdl.update(tex, (gfx[:] : void#), 64) */ /* sdl.copy(r, tex) */ /* sdl.present(r) */ sdl.freerenderer(r) sdl.freewin(win) sdl.quit() }