feat(timer): implement all timer i/o writes
This commit is contained in:
parent
6154585e77
commit
13710a3236
|
@ -19,10 +19,10 @@ pub fn create() DmaTuple {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(comptime T: type, dma: *const DmaTuple, addr: u32) ?T {
|
pub fn read(comptime T: type, dma: *const DmaTuple, addr: u32) ?T {
|
||||||
const byte = @truncate(u8, addr);
|
const byte_addr = @truncate(u8, addr);
|
||||||
|
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
u32 => switch (byte) {
|
u32 => switch (byte_addr) {
|
||||||
0xB0, 0xB4 => null, // DMA0SAD, DMA0DAD,
|
0xB0, 0xB4 => null, // DMA0SAD, DMA0DAD,
|
||||||
0xB8 => @as(T, dma.*[0].dmacntH()) << 16, // DMA0CNT_L is write-only
|
0xB8 => @as(T, dma.*[0].dmacntH()) << 16, // DMA0CNT_L is write-only
|
||||||
0xBC, 0xC0 => null, // DMA1SAD, DMA1DAD
|
0xBC, 0xC0 => null, // DMA1SAD, DMA1DAD
|
||||||
|
@ -33,7 +33,7 @@ pub fn read(comptime T: type, dma: *const DmaTuple, addr: u32) ?T {
|
||||||
0xDC => @as(T, dma.*[3].dmacntH()) << 16, // DMA3CNT_L is write-only
|
0xDC => @as(T, dma.*[3].dmacntH()) << 16, // DMA3CNT_L is write-only
|
||||||
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
||||||
},
|
},
|
||||||
u16 => switch (byte) {
|
u16 => switch (byte_addr) {
|
||||||
0xB0, 0xB2, 0xB4, 0xB6 => null, // DMA0SAD, DMA0DAD
|
0xB0, 0xB2, 0xB4, 0xB6 => null, // DMA0SAD, DMA0DAD
|
||||||
0xB8 => 0x0000, // DMA0CNT_L, suite.gba expects 0x0000 instead of 0xDEAD
|
0xB8 => 0x0000, // DMA0CNT_L, suite.gba expects 0x0000 instead of 0xDEAD
|
||||||
0xBA => dma.*[0].dmacntH(),
|
0xBA => dma.*[0].dmacntH(),
|
||||||
|
@ -51,22 +51,22 @@ pub fn read(comptime T: type, dma: *const DmaTuple, addr: u32) ?T {
|
||||||
0xDE => dma.*[3].dmacntH(),
|
0xDE => dma.*[3].dmacntH(),
|
||||||
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
||||||
},
|
},
|
||||||
u8 => switch (byte) {
|
u8 => switch (byte_addr) {
|
||||||
0xB0...0xB7 => null, // DMA0SAD, DMA0DAD
|
0xB0...0xB7 => null, // DMA0SAD, DMA0DAD
|
||||||
0xB8, 0xB9 => 0x00, // DMA0CNT_L
|
0xB8, 0xB9 => 0x00, // DMA0CNT_L
|
||||||
0xBA, 0xBB => @truncate(T, dma.*[0].dmacntH() >> getHalf(byte)),
|
0xBA, 0xBB => @truncate(T, dma.*[0].dmacntH() >> getHalf(byte_addr)),
|
||||||
|
|
||||||
0xBC...0xC3 => null, // DMA1SAD, DMA1DAD
|
0xBC...0xC3 => null, // DMA1SAD, DMA1DAD
|
||||||
0xC4, 0xC5 => 0x00, // DMA1CNT_L
|
0xC4, 0xC5 => 0x00, // DMA1CNT_L
|
||||||
0xC6, 0xC7 => @truncate(T, dma.*[1].dmacntH() >> getHalf(byte)),
|
0xC6, 0xC7 => @truncate(T, dma.*[1].dmacntH() >> getHalf(byte_addr)),
|
||||||
|
|
||||||
0xC8...0xCF => null, // DMA2SAD, DMA2DAD
|
0xC8...0xCF => null, // DMA2SAD, DMA2DAD
|
||||||
0xD0, 0xD1 => 0x00, // DMA2CNT_L
|
0xD0, 0xD1 => 0x00, // DMA2CNT_L
|
||||||
0xD2, 0xD3 => @truncate(T, dma.*[2].dmacntH() >> getHalf(byte)),
|
0xD2, 0xD3 => @truncate(T, dma.*[2].dmacntH() >> getHalf(byte_addr)),
|
||||||
|
|
||||||
0xD4...0xDB => null, // DMA3SAD, DMA3DAD
|
0xD4...0xDB => null, // DMA3SAD, DMA3DAD
|
||||||
0xDC, 0xDD => 0x00, // DMA3CNT_L
|
0xDC, 0xDD => 0x00, // DMA3CNT_L
|
||||||
0xDE, 0xDF => @truncate(T, dma.*[3].dmacntH() >> getHalf(byte)),
|
0xDE, 0xDF => @truncate(T, dma.*[3].dmacntH() >> getHalf(byte_addr)),
|
||||||
else => util.io.read.err(T, log, "unexpected {} read from 0x{X:0>8}", .{ T, addr }),
|
else => util.io.read.err(T, log, "unexpected {} read from 0x{X:0>8}", .{ T, addr }),
|
||||||
},
|
},
|
||||||
else => @compileError("DMA: Unsupported read width"),
|
else => @compileError("DMA: Unsupported read width"),
|
||||||
|
|
|
@ -225,6 +225,9 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
|
||||||
// Dma Transfers
|
// Dma Transfers
|
||||||
0x0400_00B0...0x0400_00DF => dma.write(T, &bus.dma, address, value),
|
0x0400_00B0...0x0400_00DF => dma.write(T, &bus.dma, address, value),
|
||||||
|
|
||||||
|
// Timers
|
||||||
|
0x0400_0100...0x0400_010F => timer.write(T, &bus.tim, address, value),
|
||||||
|
|
||||||
// Serial Communication 1
|
// Serial Communication 1
|
||||||
0x0400_0120 => log.debug("Wrote 0x{X:0>2} to SIODATA32_L_L", .{value}),
|
0x0400_0120 => log.debug("Wrote 0x{X:0>2} to SIODATA32_L_L", .{value}),
|
||||||
0x0400_0128 => log.debug("Wrote 0x{X:0>2} to SIOCNT_L", .{value}),
|
0x0400_0128 => log.debug("Wrote 0x{X:0>2} to SIOCNT_L", .{value}),
|
||||||
|
|
|
@ -8,71 +8,93 @@ const Arm7tdmi = @import("../cpu.zig").Arm7tdmi;
|
||||||
pub const TimerTuple = std.meta.Tuple(&[_]type{ Timer(0), Timer(1), Timer(2), Timer(3) });
|
pub const TimerTuple = std.meta.Tuple(&[_]type{ Timer(0), Timer(1), Timer(2), Timer(3) });
|
||||||
const log = std.log.scoped(.Timer);
|
const log = std.log.scoped(.Timer);
|
||||||
|
|
||||||
const shift = util.shift;
|
const getHalf = util.shift;
|
||||||
|
const setHalf = util.setHalf;
|
||||||
|
|
||||||
pub fn create(sched: *Scheduler) TimerTuple {
|
pub fn create(sched: *Scheduler) TimerTuple {
|
||||||
return .{ Timer(0).init(sched), Timer(1).init(sched), Timer(2).init(sched), Timer(3).init(sched) };
|
return .{ Timer(0).init(sched), Timer(1).init(sched), Timer(2).init(sched), Timer(3).init(sched) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(comptime T: type, tim: *const TimerTuple, addr: u32) ?T {
|
pub fn read(comptime T: type, tim: *const TimerTuple, addr: u32) ?T {
|
||||||
const nybble = @truncate(u4, addr);
|
const nybble_addr = @truncate(u4, addr);
|
||||||
|
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
u32 => switch (nybble) {
|
u32 => switch (nybble_addr) {
|
||||||
0x0 => @as(T, tim.*[0].cnt.raw) << 16 | tim.*[0].timcntL(),
|
0x0 => @as(T, tim.*[0].cnt.raw) << 16 | tim.*[0].timcntL(),
|
||||||
0x4 => @as(T, tim.*[1].cnt.raw) << 16 | tim.*[1].timcntL(),
|
0x4 => @as(T, tim.*[1].cnt.raw) << 16 | tim.*[1].timcntL(),
|
||||||
0x8 => @as(T, tim.*[2].cnt.raw) << 16 | tim.*[2].timcntL(),
|
0x8 => @as(T, tim.*[2].cnt.raw) << 16 | tim.*[2].timcntL(),
|
||||||
0xC => @as(T, tim.*[3].cnt.raw) << 16 | tim.*[3].timcntL(),
|
0xC => @as(T, tim.*[3].cnt.raw) << 16 | tim.*[3].timcntL(),
|
||||||
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
||||||
},
|
},
|
||||||
u16 => switch (nybble) {
|
u16 => switch (nybble_addr) {
|
||||||
0x0 => tim.*[0].timcntL(),
|
0x0 => tim.*[0].timcntL(),
|
||||||
0x2 => tim.*[0].cnt.raw,
|
0x2 => tim.*[0].cnt.raw,
|
||||||
|
|
||||||
0x4 => tim.*[1].timcntL(),
|
0x4 => tim.*[1].timcntL(),
|
||||||
0x6 => tim.*[1].cnt.raw,
|
0x6 => tim.*[1].cnt.raw,
|
||||||
|
|
||||||
0x8 => tim.*[2].timcntL(),
|
0x8 => tim.*[2].timcntL(),
|
||||||
0xA => tim.*[2].cnt.raw,
|
0xA => tim.*[2].cnt.raw,
|
||||||
|
|
||||||
0xC => tim.*[3].timcntL(),
|
0xC => tim.*[3].timcntL(),
|
||||||
0xE => tim.*[3].cnt.raw,
|
0xE => tim.*[3].cnt.raw,
|
||||||
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
else => util.io.read.err(T, log, "unaligned {} read from 0x{X:0>8}", .{ T, addr }),
|
||||||
},
|
},
|
||||||
u8 => switch (nybble) {
|
u8 => switch (nybble_addr) {
|
||||||
0x0, 0x1 => @truncate(T, tim.*[0].timcntL() >> shift(nybble)),
|
0x0, 0x1 => @truncate(T, tim.*[0].timcntL() >> getHalf(nybble_addr)),
|
||||||
0x2, 0x3 => @truncate(T, tim.*[0].cnt.raw >> shift(nybble)),
|
0x2, 0x3 => @truncate(T, tim.*[0].cnt.raw >> getHalf(nybble_addr)),
|
||||||
0x4, 0x5 => @truncate(T, tim.*[1].timcntL() >> shift(nybble)),
|
|
||||||
0x6, 0x7 => @truncate(T, tim.*[1].cnt.raw >> shift(nybble)),
|
0x4, 0x5 => @truncate(T, tim.*[1].timcntL() >> getHalf(nybble_addr)),
|
||||||
0x8, 0x9 => @truncate(T, tim.*[2].timcntL() >> shift(nybble)),
|
0x6, 0x7 => @truncate(T, tim.*[1].cnt.raw >> getHalf(nybble_addr)),
|
||||||
0xA, 0xB => @truncate(T, tim.*[2].cnt.raw >> shift(nybble)),
|
|
||||||
0xC, 0xD => @truncate(T, tim.*[3].timcntL() >> shift(nybble)),
|
0x8, 0x9 => @truncate(T, tim.*[2].timcntL() >> getHalf(nybble_addr)),
|
||||||
0xE, 0xF => @truncate(T, tim.*[3].cnt.raw >> shift(nybble)),
|
0xA, 0xB => @truncate(T, tim.*[2].cnt.raw >> getHalf(nybble_addr)),
|
||||||
|
|
||||||
|
0xC, 0xD => @truncate(T, tim.*[3].timcntL() >> getHalf(nybble_addr)),
|
||||||
|
0xE, 0xF => @truncate(T, tim.*[3].cnt.raw >> getHalf(nybble_addr)),
|
||||||
},
|
},
|
||||||
else => @compileError("TIM: Unsupported read width"),
|
else => @compileError("TIM: Unsupported read width"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(comptime T: type, tim: *TimerTuple, addr: u32, value: T) void {
|
pub fn write(comptime T: type, tim: *TimerTuple, addr: u32, value: T) void {
|
||||||
const nybble = @truncate(u4, addr);
|
const nybble_addr = @truncate(u4, addr);
|
||||||
|
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
u32 => switch (nybble) {
|
u32 => switch (nybble_addr) {
|
||||||
0x0 => tim.*[0].setTimcnt(value),
|
0x0 => tim.*[0].setTimcnt(value),
|
||||||
0x4 => tim.*[1].setTimcnt(value),
|
0x4 => tim.*[1].setTimcnt(value),
|
||||||
0x8 => tim.*[2].setTimcnt(value),
|
0x8 => tim.*[2].setTimcnt(value),
|
||||||
0xC => tim.*[3].setTimcnt(value),
|
0xC => tim.*[3].setTimcnt(value),
|
||||||
else => util.io.write.undef(log, "Tried to write 0x{X:0>8}{} to 0x{X:0>8}", .{ value, T, addr }),
|
else => util.io.write.undef(log, "Tried to write 0x{X:0>8}{} to 0x{X:0>8}", .{ value, T, addr }),
|
||||||
},
|
},
|
||||||
u16 => switch (nybble) {
|
u16 => switch (nybble_addr) {
|
||||||
0x0 => tim.*[0].setTimcntL(value),
|
0x0 => tim.*[0].setTimcntL(value),
|
||||||
0x2 => tim.*[0].setTimcntH(value),
|
0x2 => tim.*[0].setTimcntH(value),
|
||||||
|
|
||||||
0x4 => tim.*[1].setTimcntL(value),
|
0x4 => tim.*[1].setTimcntL(value),
|
||||||
0x6 => tim.*[1].setTimcntH(value),
|
0x6 => tim.*[1].setTimcntH(value),
|
||||||
|
|
||||||
0x8 => tim.*[2].setTimcntL(value),
|
0x8 => tim.*[2].setTimcntL(value),
|
||||||
0xA => tim.*[2].setTimcntH(value),
|
0xA => tim.*[2].setTimcntH(value),
|
||||||
|
|
||||||
0xC => tim.*[3].setTimcntL(value),
|
0xC => tim.*[3].setTimcntL(value),
|
||||||
0xE => tim.*[3].setTimcntH(value),
|
0xE => tim.*[3].setTimcntH(value),
|
||||||
else => util.io.write.undef(log, "Tried to write 0x{X:0>4}{} to 0x{X:0>8}", .{ value, T, addr }),
|
else => util.io.write.undef(log, "Tried to write 0x{X:0>4}{} to 0x{X:0>8}", .{ value, T, addr }),
|
||||||
},
|
},
|
||||||
u8 => util.io.write.undef(log, "Tried to write 0x{X:0>2}{} to 0x{X:0>8}", .{ value, T, addr }),
|
u8 => switch (nybble_addr) {
|
||||||
|
0x0, 0x1 => tim.*[0].setTimcntL(setHalf(u16, tim.*[0]._reload, nybble_addr, value)),
|
||||||
|
0x2, 0x3 => tim.*[0].setTimcntH(setHalf(u16, tim.*[0].cnt.raw, nybble_addr, value)),
|
||||||
|
|
||||||
|
0x4, 0x5 => tim.*[1].setTimcntL(setHalf(u16, tim.*[1]._reload, nybble_addr, value)),
|
||||||
|
0x6, 0x7 => tim.*[1].setTimcntH(setHalf(u16, tim.*[1].cnt.raw, nybble_addr, value)),
|
||||||
|
|
||||||
|
0x8, 0x9 => tim.*[2].setTimcntL(setHalf(u16, tim.*[2]._reload, nybble_addr, value)),
|
||||||
|
0xA, 0xB => tim.*[2].setTimcntH(setHalf(u16, tim.*[2].cnt.raw, nybble_addr, value)),
|
||||||
|
|
||||||
|
0xC, 0xD => tim.*[3].setTimcntL(setHalf(u16, tim.*[3]._reload, nybble_addr, value)),
|
||||||
|
0xE, 0xF => tim.*[3].setTimcntH(setHalf(u16, tim.*[3].cnt.raw, nybble_addr, value)),
|
||||||
|
},
|
||||||
else => @compileError("TIM: Unsupported write width"),
|
else => @compileError("TIM: Unsupported write width"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue