Add a GUI to ZBA #7

Merged
paoda merged 24 commits from imgui into main 2023-03-11 03:18:15 +00:00
15 changed files with 131 additions and 30 deletions
Showing only changes of commit d985eac0fc - Show all commits

View File

@ -102,6 +102,32 @@ pub fn deinit(self: *Self) void {
self.* = undefined; self.* = undefined;
} }
pub fn reset(self: *Self) void {
self.bios.reset();
// TODO: deinit ppu
self.apu.reset();
self.iwram.reset();
self.ewram.reset();
// https://github.com/ziglang/zig/issues/14705
{
comptime var i: usize = 0;
inline while (i < self.dma.len) : (i += 1) {
self.dma[0].reset();
}
}
// https://github.com/ziglang/zig/issues/14705
{
comptime var i: usize = 0;
inline while (i < self.tim.len) : (i += 1) {
self.tim[0].reset();
}
}
self.io.reset();
}
fn fillReadTable(self: *Self, table: *[table_len]?*const anyopaque) void { fn fillReadTable(self: *Self, table: *[table_len]?*const anyopaque) void {
const vramMirror = @import("ppu/Vram.zig").mirror; const vramMirror = @import("ppu/Vram.zig").mirror;

View File

@ -289,7 +289,28 @@ pub const Apu = struct {
return apu; return apu;
} }
fn reset(self: *Self) void { /// Used when resetting the emulator
pub fn reset(self: *Self) void {
// FIXME: These reset functions are meant to emulate obscure APU behaviour. Write proper emu reset fns
self.ch1.reset();
self.ch2.reset();
self.ch3.reset();
self.ch4.reset();
self.chA.reset();
self.chB.reset();
self.psg_cnt = .{ .raw = 0 };
self.dma_cnt = .{ .raw = 0 };
self.cnt = .{ .raw = 0 };
self.bias = .{ .raw = 0x200 };
self.sampling_cycle = 0;
self.fs.reset();
}
/// Emulates the reset behaviour of the APU
fn _reset(self: *Self) void {
// All PSG Registers between 0x0400_0060..0x0400_0081 are zeroed // All PSG Registers between 0x0400_0060..0x0400_0081 are zeroed
// 0x0400_0082 and 0x0400_0088 retain their values // 0x0400_0082 and 0x0400_0088 retain their values
self.ch1.reset(); self.ch1.reset();
@ -351,7 +372,7 @@ pub const Apu = struct {
// Rest Noise // Rest Noise
self.ch4.lfsr.reset(); self.ch4.lfsr.reset();
} else { } else {
self.reset(); self._reset();
} }
} }
@ -528,6 +549,11 @@ pub fn DmaSound(comptime kind: DmaSoundKind) type {
}; };
} }
/// Used when resetting hte emulator (not emulation code)
fn reset(self: *Self) void {
self.* = Self.init();
}
pub fn push(self: *Self, value: u32) void { pub fn push(self: *Self, value: u32) void {
if (!self.enabled) self.enable(); if (!self.enabled) self.enable();
@ -562,10 +588,14 @@ pub const FrameSequencer = struct {
const Self = @This(); const Self = @This();
pub const interval = (1 << 24) / 512; pub const interval = (1 << 24) / 512;
step: u3, step: u3 = 0,
pub fn init() Self { pub fn init() Self {
return .{ .step = 0 }; return .{};
}
pub fn reset(self: *Self) void {
self.* = .{};
} }
pub fn tick(self: *Self) void { pub fn tick(self: *Self) void {

View File

@ -3,17 +3,16 @@ const io = @import("../../bus/io.zig");
const Self = @This(); const Self = @This();
/// Period Timer /// Period Timer
timer: u3, timer: u3 = 0,
/// Current Volume /// Current Volume
vol: u4, vol: u4 = 0,
pub fn create() Self { pub fn create() Self {
return .{ .timer = 0, .vol = 0 }; return .{};
} }
pub fn reset(self: *Self) void { pub fn reset(self: *Self) void {
self.timer = 0; self.* = .{};
self.vol = 0;
} }
pub fn tick(self: *Self, nrx2: io.Envelope) void { pub fn tick(self: *Self, nrx2: io.Envelope) void {

View File

@ -1,13 +1,13 @@
const Self = @This(); const Self = @This();
timer: u9, timer: u9 = 0,
pub fn create() Self { pub fn create() Self {
return .{ .timer = 0 }; return .{};
} }
pub fn reset(self: *Self) void { pub fn reset(self: *Self) void {
self.timer = 0; self.* = .{};
} }
pub fn tick(self: *Self, enabled: bool, ch_enable: *bool) void { pub fn tick(self: *Self, enabled: bool, ch_enable: *bool) void {

View File

@ -3,26 +3,18 @@ const ToneSweep = @import("../ToneSweep.zig");
const Self = @This(); const Self = @This();
timer: u8, timer: u8 = 0,
enabled: bool, enabled: bool = false,
shadow: u11, shadow: u11 = 0,
calc_performed: bool, calc_performed: bool = false,
pub fn create() Self { pub fn create() Self {
return .{ return .{};
.timer = 0,
.enabled = false,
.shadow = 0,
.calc_performed = false,
};
} }
pub fn reset(self: *Self) void { pub fn reset(self: *Self) void {
self.timer = 0; self.* = .{};
self.enabled = false;
self.shadow = 0;
self.calc_performed = false;
} }
pub fn tick(self: *Self, ch1: *ToneSweep) void { pub fn tick(self: *Self, ch1: *ToneSweep) void {

View File

@ -77,6 +77,10 @@ pub fn init(allocator: Allocator, maybe_path: ?[]const u8) !Self {
return Self{ .buf = buf, .allocator = allocator }; return Self{ .buf = buf, .allocator = allocator };
} }
pub fn reset(self: *Self) void {
self.addr_latch = 0;
}
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
if (self.buf) |buf| self.allocator.free(buf); if (self.buf) |buf| self.allocator.free(buf);
self.* = undefined; self.* = undefined;

View File

@ -35,6 +35,10 @@ pub fn init(allocator: Allocator) !Self {
}; };
} }
pub fn reset(self: *Self) void {
std.mem.set(u8, self.buf, 0);
}
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
self.allocator.free(self.buf); self.allocator.free(self.buf);
self.* = undefined; self.* = undefined;

View File

@ -35,6 +35,10 @@ pub fn init(allocator: Allocator) !Self {
}; };
} }
pub fn reset(self: *Self) void {
std.mem.set(u8, self.buf, 0);
}
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
self.allocator.free(self.buf); self.allocator.free(self.buf);
self.* = undefined; self.* = undefined;

View File

@ -195,6 +195,10 @@ fn DmaController(comptime id: u2) type {
}; };
} }
pub fn reset(self: *Self) void {
self.* = Self.init();
}
pub fn setDmasad(self: *Self, addr: u32) void { pub fn setDmasad(self: *Self, addr: u32) void {
self.sad = addr & sad_mask; self.sad = addr & sad_mask;
} }

View File

@ -38,6 +38,10 @@ pub const Io = struct {
}; };
} }
pub fn reset(self: *Self) void {
self.* = Self.init();
}
fn setIrqs(self: *Io, word: u32) void { fn setIrqs(self: *Io, word: u32) void {
self.ie.raw = @truncate(u16, word); self.ie.raw = @truncate(u16, word);
self.irq.raw &= ~@truncate(u16, word >> 16); self.irq.raw &= ~@truncate(u16, word >> 16);

View File

@ -128,6 +128,12 @@ fn Timer(comptime id: u2) type {
}; };
} }
pub fn reset(self: *Self) void {
const scheduler = self.sched;
self.* = Self.init(scheduler);
}
/// TIMCNT_L Getter /// TIMCNT_L Getter
pub fn timcntL(self: *const Self) u16 { pub fn timcntL(self: *const Self) u16 {
if (self.cnt.cascade.read() or !self.cnt.enabled.read()) return self._counter; if (self.cnt.cascade.read() or !self.cnt.enabled.read()) return self._counter;

View File

@ -314,6 +314,14 @@ pub const Arm7tdmi = struct {
}; };
} }
// FIXME: Resetting disables logging (if enabled)
pub fn reset(self: *Self) void {
const bus_ptr = self.bus;
const scheduler_ptr = self.sched;
self.* = Self.init(scheduler_ptr, bus_ptr, null);
}
pub inline fn hasSPSR(self: *const Self) bool { pub inline fn hasSPSR(self: *const Self) bool {
const mode = getModeChecked(self, self.cpsr.mode.read()); const mode = getModeChecked(self, self.cpsr.mode.read());
return switch (mode) { return switch (mode) {

View File

@ -222,3 +222,10 @@ pub const EmuThing = struct {
} }
} }
}; };
pub fn reset(cpu: *Arm7tdmi) void {
// @breakpoint();
cpu.sched.reset(); // Yes this is order sensitive, see the PPU reset for why
cpu.bus.reset();
cpu.reset();
}

View File

@ -11,11 +11,11 @@ const log = std.log.scoped(.Scheduler);
pub const Scheduler = struct { pub const Scheduler = struct {
const Self = @This(); const Self = @This();
tick: u64, tick: u64 = 0,
queue: PriorityQueue(Event, void, lessThan), queue: PriorityQueue(Event, void, lessThan),
pub fn init(allocator: Allocator) Self { pub fn init(allocator: Allocator) Self {
var sched = Self{ .tick = 0, .queue = PriorityQueue(Event, void, lessThan).init(allocator, {}) }; var sched = Self{ .queue = PriorityQueue(Event, void, lessThan).init(allocator, {}) };
sched.queue.add(.{ .kind = .HeatDeath, .tick = std.math.maxInt(u64) }) catch unreachable; sched.queue.add(.{ .kind = .HeatDeath, .tick = std.math.maxInt(u64) }) catch unreachable;
return sched; return sched;
@ -26,6 +26,17 @@ pub const Scheduler = struct {
self.* = undefined; self.* = undefined;
} }
pub fn reset(self: *Self) void {
// `std.PriorityQueue` provides no reset function, so we will just create a new one
const allocator = self.queue.allocator;
self.queue.deinit();
var new_queue = PriorityQueue(Event, void, lessThan).init(allocator, {});
new_queue.add(.{ .kind = .HeatDeath, .tick = std.math.maxInt(u64) }) catch unreachable;
self.* = .{ .queue = new_queue };
}
pub inline fn now(self: *const Self) u64 { pub inline fn now(self: *const Self) u64 {
return self.tick; return self.tick;
} }

View File

@ -48,7 +48,7 @@ pub const State = struct {
} }
}; };
pub fn draw(state: *State, tex_id: GLuint, cpu: *const Arm7tdmi) void { pub fn draw(state: *State, tex_id: GLuint, cpu: *Arm7tdmi) void {
const win_scale = config.config().host.win_scale; const win_scale = config.config().host.win_scale;
{ {
@ -77,7 +77,9 @@ pub fn draw(state: *State, tex_id: GLuint, cpu: *const Arm7tdmi) void {
if (zgui.beginMenu("Emulation", true)) { if (zgui.beginMenu("Emulation", true)) {
defer zgui.endMenu(); defer zgui.endMenu();
if (zgui.menuItem("Restart", .{})) log.warn("TODO: Restart Emulator", .{}); if (zgui.menuItem("Restart", .{})) {
emu.reset(cpu);
}
} }
} }