Compare commits
	
		
			2 Commits
		
	
	
		
			76789aa8bc
			...
			c100d64fcb
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c100d64fcb | |||
| 5da84aff36 | 
| @@ -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 | ||||||
|   | |||||||
| @@ -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]), | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								src/cpu.zig
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/cpu.zig
									
									
									
									
									
								
							| @@ -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 { | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								src/ppu.zig
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/ppu.zig
									
									
									
									
									
								
							| @@ -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); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -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 | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user