Compare commits

..

2 Commits

3 changed files with 54 additions and 15 deletions

View File

@ -9,6 +9,9 @@ const Bit = @import("bitfield").Bit;
const Bitfield = @import("bitfield").Bitfield;
const Bus = @import("../Bus.zig");
const getHalf = util.getHalf;
const setHalf = util.setHalf;
const log = std.log.scoped(.@"I/O");
pub const Io = struct {
@ -19,6 +22,7 @@ pub const Io = struct {
ie: InterruptEnable,
irq: InterruptRequest,
postflg: PostFlag,
waitcnt: WaitControl,
haltcnt: HaltControl,
keyinput: KeyInput,
@ -28,6 +32,7 @@ pub const Io = struct {
.ie = .{ .raw = 0x0000 },
.irq = .{ .raw = 0x0000 },
.keyinput = .{ .raw = 0x03FF },
.waitcnt = .{ .raw = 0x0000_0000 },
.postflg = .FirstBoot,
.haltcnt = .Execute,
};
@ -64,8 +69,10 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) ?T {
0x0400_0150 => util.io.read.todo(log, "Read {} from JOY_RECV", .{T}),
// Interrupts
0x0400_0200 => @as(T, bus.io.irq.raw) << 16 | bus.io.ie.raw,
0x0400_0200 => @as(u32, bus.io.irq.raw) << 16 | bus.io.ie.raw,
0x0400_0204 => bus.io.waitcnt.raw,
0x0400_0208 => @boolToInt(bus.io.ime),
else => util.io.read.undef(T, log, "Tried to perform a {} read to 0x{X:0>8}", .{ T, address }),
},
u16 => switch (address) {
@ -93,8 +100,10 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) ?T {
// Interrupts
0x0400_0200 => bus.io.ie.raw,
0x0400_0202 => bus.io.irq.raw,
0x0400_0204 => util.io.read.todo(log, "Read {} from WAITCNT", .{T}),
0x0400_0204 => @truncate(T, bus.io.waitcnt.raw),
0x0400_0206 => null,
0x0400_0208 => @boolToInt(bus.io.ime),
0x0400_020A => null,
else => util.io.read.undef(T, log, "Tried to perform a {} read to 0x{X:0>8}", .{ T, address }),
},
u8 => return switch (address) {
@ -120,7 +129,13 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) ?T {
0x0400_0135 => util.io.read.todo(log, "Read {} from RCNT_H", .{T}),
// Interrupts
0x0400_0200 => @truncate(T, bus.io.ie.raw),
0x0400_0200, 0x0400_0201 => @truncate(T, bus.io.ie.raw >> getHalf(@truncate(u8, address))),
0x0400_0202, 0x0400_0203 => @truncate(T, bus.io.irq.raw >> getHalf(@truncate(u8, address))),
0x0400_0204, 0x0400_0205 => @truncate(T, bus.io.waitcnt.raw >> getHalf(@truncate(u8, address))),
0x0400_0206, 0x0400_0207 => null,
0x0400_0208, 0x0400_0209 => @truncate(T, @as(u16, @boolToInt(bus.io.ime)) >> getHalf(@truncate(u8, address))),
0x0400_020A, 0x0400_020B => null,
0x0400_0300 => @enumToInt(bus.io.postflg),
else => util.io.read.undef(T, log, "Tried to perform a {} read to 0x{X:0>8}", .{ T, address }),
},
@ -168,9 +183,8 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
// Interrupts
0x0400_0200 => bus.io.setIrqs(value),
0x0400_0204 => log.debug("Wrote 0x{X:0>8} to WAITCNT", .{value}),
0x0400_0204 => bus.io.waitcnt.raw = value,
0x0400_0208 => bus.io.ime = value & 1 == 1,
0x0400_020C...0x0400_021C => {}, // Unused
else => util.io.write.undef(log, "Tried to write 0x{X:0>8}{} to 0x{X:0>8}", .{ value, T, address }),
},
u16 => switch (address) {
@ -210,9 +224,11 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
// Interrupts
0x0400_0200 => bus.io.ie.raw = value,
0x0400_0202 => bus.io.irq.raw &= ~value,
0x0400_0204 => log.debug("Wrote 0x{X:0>4} to WAITCNT", .{value}),
0x0400_0204 => bus.io.waitcnt.raw = value,
0x0400_0206 => {},
0x0400_0208 => bus.io.ime = value & 1 == 1,
0x0400_0206, 0x0400_020A => {}, // Not Used
0x0400_020A => {},
else => util.io.write.undef(log, "Tried to write 0x{X:0>4}{} to 0x{X:0>8}", .{ value, T, address }),
},
u8 => switch (address) {
@ -237,8 +253,15 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
0x0400_0140 => log.debug("Wrote 0x{X:0>2} to JOYCNT_L", .{value}),
// Interrupts
0x0400_0200, 0x0400_0201 => bus.io.ie.raw = setHalf(u16, bus.io.ie.raw, @truncate(u8, address), value),
0x0400_0202 => bus.io.irq.raw &= ~@as(u16, value),
0x0400_0203 => bus.io.irq.raw &= ~@as(u16, value) << 8, // TODO: Is this good?
0x0400_0204, 0x0400_0205 => bus.io.waitcnt.raw = setHalf(u16, @truncate(u16, bus.io.waitcnt.raw), @truncate(u8, address), value),
0x0400_0206, 0x0400_0207 => {},
0x0400_0208 => bus.io.ime = value & 1 == 1,
0x0400_0209 => {},
0x0400_020A, 0x0400_020B => {},
0x0400_0300 => bus.io.postflg = std.meta.intToEnum(PostFlag, value & 1) catch unreachable,
0x0400_0301 => bus.io.haltcnt = if (value >> 7 & 1 == 0) .Halt else std.debug.panic("TODO: Implement STOP", .{}),
@ -576,3 +599,19 @@ pub const SoundBias = extern union {
sampling_cycle: Bitfield(u16, 14, 2),
raw: u16,
};
/// Read / Write
pub const WaitControl = extern union {
sram_cnt: Bitfield(u32, 0, 2),
s0_first: Bitfield(u32, 2, 2),
s0_second: Bit(u32, 4),
s1_first: Bitfield(u32, 5, 2),
s1_second: Bit(u32, 7),
s2_first: Bitfield(u32, 8, 2),
s2_second: Bit(u32, 10),
phi_out: Bitfield(u32, 11, 2),
prefetch_enable: Bit(u32, 14),
pak_kind: Bit(u32, 15),
raw: u32,
};

View File

@ -105,8 +105,8 @@ pub fn runFrame(sched: *Scheduler, cpu: *Arm7tdmi) void {
}
fn audioSync(audio_sync: bool, stream: *SDL.SDL_AudioStream, is_buffer_full: *bool) void {
comptime std.debug.assert(@import("../platform.zig").sample_format == SDL.AUDIO_F32);
const sample_size = 2 * @sizeOf(f32);
comptime std.debug.assert(@import("../platform.zig").sample_format == SDL.AUDIO_U16);
const sample_size = 2 * @sizeOf(u16);
const max_buf_size: c_int = 0x400;
// Determine whether the APU is busy right at this moment

View File

@ -14,8 +14,8 @@ const span = @import("util.zig").span;
const gba_width = @import("core/ppu.zig").width;
const gba_height = @import("core/ppu.zig").height;
pub const sample_rate = 44100;
pub const sample_format = SDL.AUDIO_F32;
pub const sample_rate = 1 << 15;
pub const sample_format = SDL.AUDIO_U16;
const default_title: []const u8 = "ZBA";
@ -203,8 +203,8 @@ pub const Gui = struct {
SDL.SDLK_RETURN => io.keyinput.start.set(),
SDL.SDLK_RSHIFT => io.keyinput.select.set(),
SDL.SDLK_i => {
comptime std.debug.assert(sample_format == SDL.AUDIO_F32);
log.err("Sample Count: {}", .{@intCast(u32, SDL.SDL_AudioStreamAvailable(cpu.bus.apu.stream)) / (2 * @sizeOf(f32))});
comptime std.debug.assert(sample_format == SDL.AUDIO_U16);
log.err("Sample Count: {}", .{@intCast(u32, SDL.SDL_AudioStreamAvailable(cpu.bus.apu.stream)) / (2 * @sizeOf(u16))});
},
SDL.SDLK_j => log.err("Scheduler Capacity: {} | Scheduler Event Count: {}", .{ scheduler.queue.capacity(), scheduler.queue.count() }),
SDL.SDLK_k => {
@ -271,8 +271,8 @@ const Audio = struct {
want.callback = Self.callback;
want.userdata = apu;
std.debug.assert(sample_format == SDL.AUDIO_F32);
log.info("Host Sample Rate: {}Hz, Host Format: SDL.AUDIO_F32", .{sample_rate});
std.debug.assert(sample_format == SDL.AUDIO_U16);
log.info("Host Sample Rate: {}Hz, Host Format: SDL.AUDIO_U16", .{sample_rate});
const device = SDL.SDL_OpenAudioDevice(null, 0, &want, &have, 0);
if (device == 0) panic();