0328-Chip8-延迟和声音定时器

环境

  • Time 2023-07-27
  • Zig 0.11.0-dev.4191+1bf16b172
  • SLD2 2.28.1

前言

说明

参考资料:

  1. https://en.wikipedia.org/wiki/CHIP-8
  2. https://austinmorlan.com/posts/chip8_emulator/
  3. https://rsj217.github.io/chip8-py/
  4. https://github.com/Timendus/chip8-test-suite

其中最后一个提供了测试的套件,实现的过程中,可以检测哪些指令有问题,帮助很大。

目标

实现其中的延迟和声音定时器,包含 F 指令中的 FX07、FX15、FX18。

定时器

其它无关代码已省略,新增了 tick 方法,每一帧将两个定时器减一。

pub const CPU = struct {
    instruct: Instruct = undefined,
    register: [16]u8 = std.mem.zeroes([16]u8),
    index: u16 = 0,
    pc: u16,
    prng: std.rand.DefaultPrng,
    delay: u8 = 0,
    sound: u8 = 0,

    pub fn tick(self: *CPU) void {
        if (self.delay > 0) self.delay -= 1;
        if (self.sound > 0) self.sound -= 1;
    }
}

F 指令

    fn codef(self: *CPU, ins: *Instruct, memory: *Memory) void {
        switch (ins.nn) {
            0x07 => self.register[ins.x] = self.delay,
            0x0A => if (memory.getPress()) |index| {
                self.register[ins.x] = index;
            } else self.back(),
            0x15 => self.delay = self.register[ins.x],
            0x18 => self.sound = self.register[ins.x],
            0x1E => self.index += self.register[ins.x],
            0x29 => self.index = self.register[ins.x] * 5,
            0x33 => {
                var num = self.register[ins.x];
                memory.set(self.index + 2, num % 10);
                num /= 10;
                memory.set(self.index + 1, num % 10);
                num /= 10;
                memory.set(self.index, num % 10);
            },
            0x55 => {
                for (0..ins.x + 1) |i| {
                    memory.set(self.index + i, self.register[i]);
                }
            },
            0x65 => {
                for (0..ins.x + 1) |i| {
                    self.register[i] = memory.get(self.index + i);
                }
            },
            else => std.log.info("unknown opcode: 0x{X:0>4}", .{ins.opcode}),
        }
    }

chip8.zig

每一帧,将定时器减一。

const cpu = @import("cpu.zig");
const memory = @import("memory.zig");
const screen = @import("screen.zig");
const keypad = @import("keypad.zig");

const ENTRY = 0x200;
const HZ = 500;
const FPS = 60;

pub const Emulator = struct {
    cpu: cpu.CPU,
    memory: memory.Memory,
    screen: screen.Screen,
    keypad: keypad.Keypad,

    pub fn new(rom: []const u8) Emulator {
        return Emulator{
            .cpu = cpu.CPU.new(ENTRY),
            .memory = memory.Memory.new(rom, ENTRY),
            .screen = screen.Screen{},
            .keypad = keypad.Keypad{},
        };
    }

    pub fn run(self: *Emulator) void {
        self.screen.init();
        defer self.screen.deinit();
        self.memory.screen = &self.screen;
        self.memory.keypad = &self.keypad;

        var index: usize = 0;
        while (self.keypad.poll()) : (index += 1) {
            for (0..(HZ / FPS)) |_|
                self.cpu.cycle(&self.memory);

            self.screen.update(FPS);
            self.cpu.tick();
        }
    }
};

启动

zig build run

效果

窗口

总结

实现了两个定时器的功能,包含 FX07、FX15、FX18 指令。

附录

posted @ 2025-12-04 10:07  jiangbo4444  阅读(5)  评论(0)    收藏  举报