Compare commits

...

2 Commits

7 changed files with 39 additions and 34 deletions

View File

@ -29,9 +29,10 @@ dma: DmaControllers,
tim: Timers, tim: Timers,
iwram: Iwram, iwram: Iwram,
ewram: Ewram, ewram: Ewram,
io: Io, io: Io,
sched: *Scheduler,
pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, bios_path: ?[]const u8, save_path: ?[]const u8) !Self { pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, bios_path: ?[]const u8, save_path: ?[]const u8) !Self {
return Self{ return Self{
.pak = try GamePak.init(alloc, rom_path, save_path), .pak = try GamePak.init(alloc, rom_path, save_path),
@ -43,6 +44,7 @@ pub fn init(alloc: Allocator, sched: *Scheduler, rom_path: []const u8, bios_path
.dma = DmaControllers.init(), .dma = DmaControllers.init(),
.tim = Timers.init(sched), .tim = Timers.init(sched),
.io = Io.init(), .io = Io.init(),
.sched = sched,
}; };
} }
@ -57,6 +59,7 @@ pub fn deinit(self: Self) void {
pub fn read(self: *const Self, comptime T: type, address: u32) T { pub fn read(self: *const Self, comptime T: type, address: u32) T {
const page = @truncate(u8, address >> 24); const page = @truncate(u8, address >> 24);
const align_addr = alignAddress(T, address); const align_addr = alignAddress(T, address);
self.sched.tick += 1;
return switch (page) { return switch (page) {
// General Internal Memory // General Internal Memory
@ -91,6 +94,7 @@ pub fn read(self: *const Self, comptime T: type, address: u32) T {
pub fn write(self: *Self, comptime T: type, address: u32, value: T) void { pub fn write(self: *Self, comptime T: type, address: u32, value: T) void {
const page = @truncate(u8, address >> 24); const page = @truncate(u8, address >> 24);
const align_addr = alignAddress(T, address); const align_addr = alignAddress(T, address);
self.sched.tick += 1;
switch (page) { switch (page) {
// General Internal Memory // General Internal Memory

View File

@ -29,6 +29,11 @@ pub fn deinit(self: Self) void {
pub fn read(self: *const Self, comptime T: type, addr: usize) T { pub fn read(self: *const Self, comptime T: type, addr: usize) T {
if (self.buf) |buf| { if (self.buf) |buf| {
if (addr > buf.len) {
log.err("Tried to read {} from {X:0>8} (open bus)", .{ T, addr });
return 0;
}
return switch (T) { return switch (T) {
u32 => (@as(u32, buf[addr + 3]) << 24) | (@as(u32, buf[addr + 2]) << 16) | (@as(u32, buf[addr + 1]) << 8) | (@as(u32, buf[addr])), u32 => (@as(u32, buf[addr + 3]) << 24) | (@as(u32, buf[addr + 2]) << 16) | (@as(u32, buf[addr + 1]) << 8) | (@as(u32, buf[addr])),
u16 => (@as(u16, buf[addr + 1]) << 8) | @as(u16, buf[addr]), u16 => (@as(u16, buf[addr + 1]) << 8) | @as(u16, buf[addr]),

View File

@ -81,13 +81,13 @@ fn Timer(comptime id: u2) type {
// Reload on Rising edge // Reload on Rising edge
self._counter = self._reload; self._counter = self._reload;
if (!new.cascade.read()) self.scheduleOverflow(); if (!new.cascade.read()) self.scheduleOverflow(0);
} }
self.cnt.raw = halfword; self.cnt.raw = halfword;
} }
pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi) void { pub fn handleOverflow(self: *Self, cpu: *Arm7tdmi, late: u64) void {
// Fire IRQ if enabled // Fire IRQ if enabled
const io = &cpu.bus.io; const io = &cpu.bus.io;
const tim = &cpu.bus.tim; const tim = &cpu.bus.tim;
@ -107,21 +107,15 @@ fn Timer(comptime id: u2) type {
switch (id) { switch (id) {
0 => if (tim._1.cnt.cascade.read()) { 0 => if (tim._1.cnt.cascade.read()) {
tim._1._counter +%= 1; tim._1._counter +%= 1;
if (tim._1._counter == 0) tim._1.handleOverflow(cpu, late);
if (tim._1._counter == 0)
tim._1.handleOverflow(cpu);
}, },
1 => if (tim._2.cnt.cascade.read()) { 1 => if (tim._2.cnt.cascade.read()) {
tim._2._counter +%= 1; tim._2._counter +%= 1;
if (tim._2._counter == 0) tim._2.handleOverflow(cpu, late);
if (tim._2._counter == 0)
tim._2.handleOverflow(cpu);
}, },
2 => if (tim._3.cnt.cascade.read()) { 2 => if (tim._3.cnt.cascade.read()) {
tim._3._counter +%= 1; tim._3._counter +%= 1;
if (tim._3._counter == 0) tim._3.handleOverflow(cpu, late);
if (tim._3._counter == 0)
tim._3.handleOverflow(cpu);
}, },
3 => {}, // There is no Timer for TIM3 to "cascade" to, 3 => {}, // There is no Timer for TIM3 to "cascade" to,
} }
@ -129,15 +123,15 @@ fn Timer(comptime id: u2) type {
// Reschedule Timer if we're not cascading // Reschedule Timer if we're not cascading
if (!self.cnt.cascade.read()) { if (!self.cnt.cascade.read()) {
self._counter = self._reload; self._counter = self._reload;
self.scheduleOverflow(); self.scheduleOverflow(late);
} }
} }
fn scheduleOverflow(self: *Self) void { fn scheduleOverflow(self: *Self, late: u64) void {
const when = (@as(u64, 0x10000) - self._counter) * self.frequency(); const when = (@as(u64, 0x10000) - self._counter) * self.frequency();
self._start_timestamp = self.sched.now(); self._start_timestamp = self.sched.now();
self.sched.push(.{ .TimerOverflow = id }, self.sched.now() + when); self.sched.push(.{ .TimerOverflow = id }, self.sched.now() + when - late);
} }
fn frequency(self: *const Self) u16 { fn frequency(self: *const Self) u16 {

View File

@ -245,12 +245,15 @@ pub const Arm7tdmi = struct {
self.cpsr.raw = 0x6000001F; self.cpsr.raw = 0x6000001F;
} }
pub fn step(self: *Self) u64 { pub fn step(self: *Self) void {
// If we're processing a DMA (not Sound or Blanking) the CPU is disabled // If we're processing a DMA (not Sound or Blanking) the CPU is disabled
if (self.handleDMATransfers()) return 1; if (self.handleDMATransfers()) return;
// If we're halted, the cpu is disabled // If we're halted, the cpu is disabled
if (self.bus.io.haltcnt == .Halt) return 1; if (self.bus.io.haltcnt == .Halt) {
self.sched.tick += 1;
return;
}
if (self.cpsr.t.read()) { if (self.cpsr.t.read()) {
const opcode = self.thumbFetch(); const opcode = self.thumbFetch();
@ -265,8 +268,6 @@ pub const Arm7tdmi = struct {
arm_lut[armIdx(opcode)](self, self.bus, opcode); arm_lut[armIdx(opcode)](self, self.bus, opcode);
} }
} }
return 1;
} }
pub fn handleInterrupt(self: *Self) void { pub fn handleInterrupt(self: *Self) void {

View File

@ -46,8 +46,7 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi, bus: *Bus) void {
const frame_end = sched.tick + cycles_per_frame; const frame_end = sched.tick + cycles_per_frame;
while (sched.tick < frame_end) { while (sched.tick < frame_end) {
sched.tick += 1; cpu.step();
_ = cpu.step();
while (sched.tick >= sched.nextTimestamp()) { while (sched.tick >= sched.nextTimestamp()) {
sched.handleEvent(cpu, bus); sched.handleEvent(cpu, bus);

View File

@ -358,7 +358,7 @@ pub const Ppu = struct {
}; };
} }
pub fn handleHDrawEnd(self: *Self, cpu: *Arm7tdmi) void { pub fn handleHDrawEnd(self: *Self, cpu: *Arm7tdmi, late: u64) void {
// Transitioning to a Hblank // Transitioning to a Hblank
if (self.dispstat.hblank_irq.read()) { if (self.dispstat.hblank_irq.read()) {
cpu.bus.io.irq.hblank.set(); cpu.bus.io.irq.hblank.set();
@ -369,10 +369,10 @@ pub const Ppu = struct {
pollBlankingDma(cpu.bus, .HBlank); pollBlankingDma(cpu.bus, .HBlank);
self.dispstat.hblank.set(); self.dispstat.hblank.set();
self.sched.push(.HBlank, self.sched.now() + (68 * 4)); self.sched.push(.HBlank, self.sched.now() + (68 * 4) - late);
} }
pub fn handleHBlankEnd(self: *Self, cpu: *Arm7tdmi) void { pub fn handleHBlankEnd(self: *Self, cpu: *Arm7tdmi, late: u64) void {
// The End of a Hblank (During Draw or Vblank) // The End of a Hblank (During Draw or Vblank)
const old_scanline = self.vcount.scanline.read(); const old_scanline = self.vcount.scanline.read();
const scanline = (old_scanline + 1) % 228; const scanline = (old_scanline + 1) % 228;
@ -391,7 +391,7 @@ pub const Ppu = struct {
if (scanline < 160) { if (scanline < 160) {
// Transitioning to another Draw // Transitioning to another Draw
self.sched.push(.Draw, self.sched.now() + (240 * 4)); self.sched.push(.Draw, self.sched.now() + (240 * 4) - late);
} else { } else {
// Transitioning to a Vblank // Transitioning to a Vblank
if (scanline == 160) { if (scanline == 160) {
@ -407,7 +407,7 @@ pub const Ppu = struct {
} }
if (scanline == 227) self.dispstat.vblank.unset(); if (scanline == 227) self.dispstat.vblank.unset();
self.sched.push(.VBlank, self.sched.now() + (240 * 4)); self.sched.push(.VBlank, self.sched.now() + (240 * 4) - late);
} }
} }
}; };

View File

@ -31,6 +31,8 @@ pub const Scheduler = struct {
pub fn handleEvent(self: *Self, cpu: *Arm7tdmi, bus: *Bus) void { pub fn handleEvent(self: *Self, cpu: *Arm7tdmi, bus: *Bus) void {
if (self.queue.removeOrNull()) |event| { if (self.queue.removeOrNull()) |event| {
const late = self.tick - event.tick;
switch (event.kind) { switch (event.kind) {
.HeatDeath => { .HeatDeath => {
log.err("A u64 overflowered. This *actually* should never happen.", .{}); log.err("A u64 overflowered. This *actually* should never happen.", .{});
@ -39,18 +41,18 @@ pub const Scheduler = struct {
.Draw => { .Draw => {
// The end of a VDraw // The end of a VDraw
bus.ppu.drawScanline(); bus.ppu.drawScanline();
bus.ppu.handleHDrawEnd(cpu); bus.ppu.handleHDrawEnd(cpu, late);
}, },
.TimerOverflow => |id| { .TimerOverflow => |id| {
switch (id) { switch (id) {
0 => bus.tim._0.handleOverflow(cpu), 0 => bus.tim._0.handleOverflow(cpu, late),
1 => bus.tim._1.handleOverflow(cpu), 1 => bus.tim._1.handleOverflow(cpu, late),
2 => bus.tim._2.handleOverflow(cpu), 2 => bus.tim._2.handleOverflow(cpu, late),
3 => bus.tim._3.handleOverflow(cpu), 3 => bus.tim._3.handleOverflow(cpu, late),
} }
}, },
.HBlank => bus.ppu.handleHBlankEnd(cpu), // The end of a HBlank .HBlank => bus.ppu.handleHBlankEnd(cpu, late), // The end of a HBlank
.VBlank => bus.ppu.handleHDrawEnd(cpu), // The end of a VBlank .VBlank => bus.ppu.handleHDrawEnd(cpu, late), // The end of a VBlank
} }
} }
} }