From 73265f9d1e4a7edc020b5bad5b00017414ba40ea Mon Sep 17 00:00:00 2001 From: Toni Date: Wed, 11 Mar 2026 17:03:22 +0100 Subject: [PATCH] finish porting the chip8 emulator --- examples/chip8.zr | 246 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 239 insertions(+), 7 deletions(-) diff --git a/examples/chip8.zr b/examples/chip8.zr index 4822b17..dca970c 100644 --- a/examples/chip8.zr +++ b/examples/chip8.zr @@ -6,44 +6,276 @@ extern BeginDrawing extern ClearBackground extern DrawRectangle extern EndDrawing +extern IsKeyDown +extern printf // TODO: replace with std +extern rand // TODO: replace with std struct CHIP8 memory: ptr pc: i64 stack: array sp: i64 - reg: array + reg: ptr I: i64 delay_timer: i64 sound_timer: i64 keyboard: array display: ptr + keyboard_map: array func chip8_create[] : CHIP8 - let fonts: array = [0xf0, 0x90, 0x90, 0x90, 0xf0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xf0, 0x10, 0xf0, 0x80, 0xf0, 0xf0, 0x10, 0xf0, 0x10, 0xf0, 0x90, 0x90, 0xf0, 0x10, 0x10, 0xf0, 0x80, 0xf0, 0x10, 0xf0, 0xf0, 0x80, 0xf0, 0x90, 0xf0, 0xf0, 0x10, 0x20, 0x40, 0x40, 0xf0, 0x90, 0xf0, 0x90, 0xf0, 0xf0, 0x90, 0xf0, 0x10, 0xf0, 0xf0, 0x90, 0xf0, 0x90, 0x90, 0xe0, 0x90, 0xe0, 0x90, 0xe0, 0xf0, 0x80, 0x80, 0x80, 0xf0, 0xe0, 0x90, 0x90, 0x90, 0xe0, 0xf0, 0x80, 0xf0, 0x80, 0xf0, 0xf0, 0x80, 0xf0, 0x80, 0x80] - let c: CHIP8 = new CHIP8 c->memory = mem.alloc(4096) mem.zero(c->memory, 4096) c->display = mem.alloc(64*32) mem.zero(c->display, 64*32) + c->reg = mem.alloc(16) + mem.zero(c->reg, 16) c->stack = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - c->reg = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] c->keyboard = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + let fonts: array = [0xf0, 0x90, 0x90, 0x90, 0xf0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xf0, 0x10, 0xf0, 0x80, 0xf0, 0xf0, 0x10, 0xf0, 0x10, 0xf0, 0x90, 0x90, 0xf0, 0x10, 0x10, 0xf0, 0x80, 0xf0, 0x10, 0xf0, 0xf0, 0x80, 0xf0, 0x90, 0xf0, 0xf0, 0x10, 0x20, 0x40, 0x40, 0xf0, 0x90, 0xf0, 0x90, 0xf0, 0xf0, 0x90, 0xf0, 0x10, 0xf0, 0xf0, 0x90, 0xf0, 0x90, 0x90, 0xe0, 0x90, 0xe0, 0x90, 0xe0, 0xf0, 0x80, 0x80, 0x80, 0xf0, 0xe0, 0x90, 0x90, 0x90, 0xe0, 0xf0, 0x80, 0xf0, 0x80, 0xf0, 0xf0, 0x80, 0xf0, 0x80, 0x80] for i in 0..80 c->memory[i] = array.nth(fonts, i) mem.free(fonts) c->pc = 0x200 + + // see KeyboardKey in raylib.h + c->keyboard_map = [49, 50, 51, 52, 53, 265, 32, 263, 264, 262, 87, 69, 82, 84, 89, 85] + return c func chip8_disassemble[c: CHIP8, ins_count: i64] : void - return 0 + for i in 0..ins_count + printf("0x%x: ", c->pc) + + let high: i64 = c->memory[c->pc] + let low: i64 = c->memory[c->pc + 1] + c->pc = c->pc + 2 + + let ins: i64 = (high << 8) | low + let nnn: i64 = ins & 0x0fff + let kk: i64 = ins & 0x00ff + let n: i64 = ins & 0x000f + let x: i64 = (ins >> 8) & 0x0f + let y: i64 = (ins >> 4) & 0x0f + + let op: i64 = (ins >> 12) & 0x0f + if op == 0x0 + if nnn == 0x0e0 + io.println("CLS") + else if nnn == 0x0ee + io.println("RET") + else + io.print("SYS ") + io.println_i64(nnn) + else if op == 0x1 + printf("JP 0x%x\n", nnn) + else if op == 0x2 + io.print("CALL ") + io.println_i64(nnn) + else if op == 0x3 + printf("SE V%x, %u\n", x, kk) + else if op == 0x4 + printf("SNE V%x, %u\n", x, kk) + else if op == 0x5 + printf("SE V%x, V%x\n", x, y) + else if op == 0x6 + printf("LD V%x, %u\n", x, kk) + else if op == 0x7 + printf("ADD V%x, %u\n", x, kk) + else if op == 0x8 + if n == 0x0 + printf("LD V%x, V%x\n", x, y) + else if n == 0x1 + printf("OR V%x, V%x\n", x, y) + else if n == 0x2 + printf("AND V%x, V%x\n", x, y) + else if n == 0x3 + printf("XOR V%x, V%x\n", x, y) + else if n == 0x4 + printf("ADD V%x, V%x\n", x, y) + else if n == 0x5 + printf("SUB V%x, V%x\n", x, y) + else if n == 0x6 + printf("SHR V%x\n", x) + else if n == 0x7 + printf("SUBN V%x, V%x\n", x, y) + else if n == 0xE + printf("SHL V%x\n", x) + else + printf("??? (%x)\n", ins) + else if op == 0x9 + printf("SNE V%x, V%x\n", x, y) + else if op == 0xa + printf("LD I, 0x%x\n", nnn) + else if op == 0xb + printf("JP V0, %u\n", nnn) + else if op == 0xc + printf("RND V%x, %u\n", x, kk) + else if op == 0xd + printf("DRW V%x, V%x, %u\n", x, y, n) + else if op == 0xe + if kk == 0x9e + printf("SKP V%x\n", x) + else if kk == 0xa1 + printf("SKNP V%x\n", x) + else + printf("??? (%x)\n", ins) + else if op == 0xf + if kk == 0x07 + printf("LD V%x, DT\n", x) + else if kk == 0x0A + printf("LD V%x, K\n", x) + else if kk == 0x15 + printf("LD DT, V%x\n", x) + else if kk == 0x18 + printf("LD ST, V%x\n", x) + else if kk == 0x1E + printf("ADD I, V%x\n", x) + else if kk == 0x29 + printf("LD F, V%x\n", x) + else if kk == 0x33 + printf("LD B, V%x\n", x) + else if kk == 0x55 + printf("LD [I], V%x\n", x) + else if kk == 0x65 + printf("LD V%x, [I]\n", x) + else + printf("??? (%x)\n", ins) + else + printf("??? (%x)\n", ins) func chip8_step[c: CHIP8] : void - return 0 + let high: i64 = c->memory[c->pc] + let low: i64 = c->memory[c->pc + 1] + c->pc = c->pc + 2 + + let ins: i64 = (high << 8) | low + let nnn: i64 = ins & 0x0fff + let kk: i64 = ins & 0x00ff + let n: i64 = ins & 0x000f + let x: i64 = (ins >> 8) & 0x0f + let y: i64 = (ins >> 4) & 0x0f + + let op: i64 = (ins >> 12) & 0x0f + if op == 0x0 + if nnn == 0x0e0 + mem.zero(c->display, 64 * 32) + else if nnn == 0x0ee + c->pc = array.nth(c->stack, c->sp) + c->sp = c->sp - 1 + else if op == 0x1 + c->pc = nnn + else if op == 0x2 + c->sp = c->sp + 1 + array.set(c->stack, c->sp, c->pc) + c->pc = nnn + else if op == 0x3 + if c->reg[x] == kk + c->pc = c->pc + 2 + else if op == 0x4 + if c->reg[x] != kk + c->pc = c->pc + 2 + else if op == 0x5 + if c->reg[x] == c->reg[y] + c->pc = c->pc + 2 + else if op == 0x6 + c->reg[x] = kk + else if op == 0x7 + c->reg[x] = c->reg[x] + kk + else if op == 0x8 + if n == 0x0 + c->reg[x] = c->reg[y] + else if n == 0x1 + c->reg[x] = c->reg[x] | c->reg[y] + else if n == 0x2 + c->reg[x] = c->reg[x] & c->reg[y] + else if n == 0x3 + c->reg[x] = c->reg[x] ^ c->reg[y] + else if n == 0x4 + let res: i64 = c->reg[x] + c->reg[y] + c->reg[0xf] = res > 0xff + c->reg[x] = res + else if n == 0x5 + c->reg[0xf] = c->reg[x] > c->reg[y] + c->reg[x] = c->reg[x] - c->reg[y] + else if n == 0x6 + c->reg[0xf] = c->reg[x] & 0x1 + c->reg[x] = c->reg[x] >> 1 + else if n == 0x7 + c->reg[0xf] = c->reg[y] > c->reg[x] + c->reg[x] = c->reg[y] - c->reg[x] + else if n == 0xE + c->reg[0xf] = (c->reg[x] & 0x80) >> 7 + c->reg[x] = c->reg[x] << 1 + else if op == 0x9 + if c->reg[x] != c->reg[y] + c->pc = c->pc + 2 + else if op == 0xa + c->I = nnn + else if op == 0xb + c->pc = nnn + c->reg[0] + else if op == 0xc + c->reg[x] = (rand() % 256) & kk + else if op == 0xd + c->reg[0xf] = 0 + for row in 0..n + for col in 0..8 + if (c->memory[c->I + row] & (0x80 >> col)) != 0 + let pixel_x: i64 = (c->reg[x] + col) % 64 + let pixel_y: i64 = (c->reg[y] + row) % 32 + let offset: i64 = pixel_x + (pixel_y * 64) + + if c->display[offset] == 1 + c->reg[0xf] = 1 + c->display[offset] = c->display[offset] ^ 1 + else if op == 0xe + if kk == 0x9e + if IsKeyDown(array.nth(c->keyboard_map, c->reg[x])) + c->pc = c->pc + 2 + else if kk == 0xa1 + if !IsKeyDown(array.nth(c->keyboard_map, c->reg[x])) + c->pc = c->pc + 2 + else if op == 0xf + if kk == 0x07 + c->reg[x] = c->delay_timer + else if kk == 0x0A + let key_pressed: bool = false + while !key_pressed && !WindowShouldClose() + for i in 0..16 + if IsKeyDown(array.nth(c->keyboard_map, i)) + key_pressed = true + break + else if kk == 0x15 + c->delay_timer = c->reg[x] + else if kk == 0x18 + c->sound_timer = c->reg[x] + else if kk == 0x1E + c->I = c->I + c->reg[x] + else if kk == 0x29 + c->I = c->reg[x] * 5 + else if kk == 0x33 + c->memory[c->I] = c->reg[x] / 100 + c->memory[c->I + 1] = (c->reg[x] / 10) % 10 + c->memory[c->I + 2] = c->reg[x] % 10 + else if kk == 0x55 + for i in 0..x+1 + c->memory[c->I + i] = c->reg[i] + else if kk == 0x65 + for i in 0..x+1 + c->reg[i] = c->memory[c->I + i] + +func chip8_free[c: CHIP8] : void + mem.free(c->memory) + array.free(c->stack) + mem.free(c->reg) + array.free(c->keyboard) + mem.free(c->display) + array.free(c->keyboard_map) + mem.free(c) func main[argc: i64, argv: ptr] : i64 let path: str = 0 @@ -91,6 +323,6 @@ func main[argc: i64, argv: ptr] : i64 for y in 0..32 for x in 0..64 if c->display[x + y * 64] == 1 - DrawRectangle(x * 10, y * 10, 10, 10, 0x000000ff) + DrawRectangle(x * 10, y * 10, 10, 10, 0xff000000) EndDrawing() \ No newline at end of file