summaryrefslogtreecommitdiff
path: root/main.myr
diff options
context:
space:
mode:
Diffstat (limited to 'main.myr')
-rw-r--r--main.myr578
1 files changed, 318 insertions, 260 deletions
diff --git a/main.myr b/main.myr
index feac70c..9d22f46 100644
--- a/main.myr
+++ b/main.myr
@@ -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()
}