0319-Chip8-完善内存结构定义

环境

  • Time 2023-07-26
  • 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

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

目标

  1. 将屏幕和键盘映射到内存中。
  2. 内存支持栈结构,可以入栈和出栈。
  3. 定义屏幕的清屏和设置像素操作。

memory.zig

  1. 定义了 16 级的栈结构和栈指针。
  2. 映射屏幕和键盘到内存中。
  3. 实现了入栈 push 和出栈 pop 方法。
  4. 实现了清屏 clearScreen 和 绘制像素 drawPixel 方法。
const Screen = @import("screen.zig").Screen;
const Keypad = @import("keypad.zig").Keypad;

pub const Memory = struct {
    ram: [4096]u8 = undefined,
    stack: [16]u16 = undefined,
    sp: u8 = 0,
    screen: *Screen = undefined,
    keypad: *Keypad = undefined,

    pub fn new(rom: []const u8, entry: u16) Memory {
        var memory = Memory{};
        @memcpy(memory.ram[0..fonts.len], &fonts);
        @memcpy(memory.ram[entry .. entry + rom.len], rom);
        return memory;
    }

    pub fn load(self: *Memory, pc: u16) u16 {
        const high: u8 = self.ram[pc];
        return (@as(u16, high) << 8) | self.ram[pc + 1];
    }

    pub fn get(self: *Memory, index: usize) u8 {
        return self.ram[index];
    }

    pub fn set(self: *Memory, index: usize, value: u8) void {
        self.ram[index] = value;
    }

    pub fn clearScreen(self: *Memory) void {
        var screen1 = self.screen;
        screen1.clear();
    }

    pub fn drawPixel(self: *Memory, x: usize, y: usize) bool {
        return self.screen.setPixel(x, y);
    }

    pub fn push(self: *Memory, value: u16) void {
        self.stack[self.sp] = value;
        self.sp += 1;
    }

    pub fn pop(self: *Memory) u16 {
        self.sp -= 1;
        return self.stack[self.sp];
    }
};

const fonts = [_]u8{
    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
};

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{ .pc = 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);
            if (index % 44 == 0) self.screen.clear();
            _ = self.screen.setIndex(index);
            self.screen.update(FPS);
        }
    }
};

启动

zig build run

效果

窗口

总结

完善了内存结构的定义,新增了栈操作和屏幕的操作。

附录

posted @ 2025-12-04 09:54  jiangbo4444  阅读(2)  评论(0)    收藏  举报