chore: move timer, apu and dma i/o addr matching outside of io.zig
This commit is contained in:
@@ -11,6 +11,83 @@ pub fn create() DmaTuple {
|
||||
return .{ DmaController(0).init(), DmaController(1).init(), DmaController(2).init(), DmaController(3).init() };
|
||||
}
|
||||
|
||||
pub fn read(comptime T: type, dma: *const DmaTuple, addr: u32) T {
|
||||
const byte = @truncate(u8, addr);
|
||||
|
||||
return switch (T) {
|
||||
u32 => switch (byte) {
|
||||
0xB8 => @as(T, dma.*[0].cnt.raw) << 16,
|
||||
0xC4 => @as(T, dma.*[1].cnt.raw) << 16,
|
||||
0xD0 => @as(T, dma.*[1].cnt.raw) << 16,
|
||||
0xDC => @as(T, dma.*[3].cnt.raw) << 16,
|
||||
else => @panic("TODO: Unexpected u32 DMA read"),
|
||||
},
|
||||
u16 => switch (byte) {
|
||||
0xBA => dma.*[0].cnt.raw,
|
||||
0xC6 => dma.*[1].cnt.raw,
|
||||
0xD2 => dma.*[2].cnt.raw,
|
||||
0xDE => dma.*[3].cnt.raw,
|
||||
else => @panic("TODO: Unexpected u16 DMA read"),
|
||||
},
|
||||
u8 => @panic("TODO: Unexpected u8 DMA read"),
|
||||
else => @compileError("DMA: Unsupported read width"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write(comptime T: type, dma: *DmaTuple, addr: u32, value: T) void {
|
||||
const byte = @truncate(u8, addr);
|
||||
|
||||
switch (T) {
|
||||
u32 => switch (byte) {
|
||||
0xB0 => dma.*[0].setSad(value),
|
||||
0xB4 => dma.*[0].setDad(value),
|
||||
0xB8 => dma.*[0].setCnt(value),
|
||||
0xBC => dma.*[1].setSad(value),
|
||||
0xC0 => dma.*[1].setDad(value),
|
||||
0xC4 => dma.*[1].setCnt(value),
|
||||
0xC8 => dma.*[2].setSad(value),
|
||||
0xCC => dma.*[2].setDad(value),
|
||||
0xD0 => dma.*[2].setCnt(value),
|
||||
0xD4 => dma.*[3].setSad(value),
|
||||
0xD8 => dma.*[3].setDad(value),
|
||||
0xDC => dma.*[3].setCnt(value),
|
||||
else => @panic("TODO: Unexpected u32 DMA write"),
|
||||
},
|
||||
u16 => switch (byte) {
|
||||
0xB0 => dma.*[0].setSad(setU32L(dma.*[0].sad, value)),
|
||||
0xB2 => dma.*[0].setSad(setU32H(dma.*[0].sad, value)),
|
||||
0xB4 => dma.*[0].setDad(setU32L(dma.*[0].dad, value)),
|
||||
0xB6 => dma.*[0].setDad(setU32H(dma.*[0].dad, value)),
|
||||
0xB8 => dma.*[0].setCntL(value),
|
||||
0xBA => dma.*[0].setCntH(value),
|
||||
|
||||
0xBC => dma.*[1].setSad(setU32L(dma.*[1].sad, value)),
|
||||
0xBE => dma.*[1].setSad(setU32H(dma.*[1].sad, value)),
|
||||
0xC0 => dma.*[1].setDad(setU32L(dma.*[1].dad, value)),
|
||||
0xC2 => dma.*[1].setDad(setU32H(dma.*[1].dad, value)),
|
||||
0xC4 => dma.*[1].setCntL(value),
|
||||
0xC6 => dma.*[1].setCntH(value),
|
||||
|
||||
0xC8 => dma.*[2].setSad(setU32L(dma.*[2].sad, value)),
|
||||
0xCA => dma.*[2].setSad(setU32H(dma.*[2].sad, value)),
|
||||
0xCC => dma.*[2].setDad(setU32L(dma.*[2].dad, value)),
|
||||
0xCE => dma.*[2].setDad(setU32H(dma.*[2].dad, value)),
|
||||
0xD0 => dma.*[2].setCntL(value),
|
||||
0xD2 => dma.*[2].setCntH(value),
|
||||
|
||||
0xD4 => dma.*[3].setSad(setU32L(dma.*[3].sad, value)),
|
||||
0xD6 => dma.*[3].setSad(setU32H(dma.*[3].sad, value)),
|
||||
0xD8 => dma.*[3].setDad(setU32L(dma.*[3].dad, value)),
|
||||
0xDA => dma.*[3].setDad(setU32H(dma.*[3].dad, value)),
|
||||
0xDC => dma.*[3].setCntL(value),
|
||||
0xDE => dma.*[3].setCntH(value),
|
||||
else => @panic("TODO: Unexpected u16 DMA write"),
|
||||
},
|
||||
u8 => @panic("TODO: Unexpected u8 DMA write"),
|
||||
else => @compileError("DMA: Unsupported write width"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Function that creates a DMAController. Determines unique DMA Controller behaiour at compile-time
|
||||
fn DmaController(comptime id: u2) type {
|
||||
return struct {
|
||||
@@ -66,19 +143,19 @@ fn DmaController(comptime id: u2) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeSad(self: *Self, addr: u32) void {
|
||||
pub fn setSad(self: *Self, addr: u32) void {
|
||||
self.sad = addr & sad_mask;
|
||||
}
|
||||
|
||||
pub fn writeDad(self: *Self, addr: u32) void {
|
||||
pub fn setDad(self: *Self, addr: u32) void {
|
||||
self.dad = addr & dad_mask;
|
||||
}
|
||||
|
||||
pub fn writeWordCount(self: *Self, halfword: u16) void {
|
||||
pub fn setCntL(self: *Self, halfword: u16) void {
|
||||
self.word_count = @truncate(@TypeOf(self.word_count), halfword);
|
||||
}
|
||||
|
||||
pub fn writeCntHigh(self: *Self, halfword: u16) void {
|
||||
pub fn setCntH(self: *Self, halfword: u16) void {
|
||||
const new = DmaControl{ .raw = halfword };
|
||||
|
||||
if (!self.cnt.enabled.read() and new.enabled.read()) {
|
||||
@@ -94,9 +171,9 @@ fn DmaController(comptime id: u2) type {
|
||||
self.cnt.raw = halfword;
|
||||
}
|
||||
|
||||
pub fn writeCnt(self: *Self, word: u32) void {
|
||||
pub fn setCnt(self: *Self, word: u32) void {
|
||||
self.word_count = @truncate(@TypeOf(self.word_count), word);
|
||||
self.writeCntHigh(@truncate(u16, word >> 16));
|
||||
self.setCntH(@truncate(u16, word >> 16));
|
||||
}
|
||||
|
||||
pub fn step(self: *Self, cpu: *Arm7tdmi) bool {
|
||||
@@ -218,3 +295,11 @@ const DmaKind = enum(u2) {
|
||||
VBlank,
|
||||
Special,
|
||||
};
|
||||
|
||||
fn setU32L(left: u32, right: u16) u32 {
|
||||
return (left & 0xFFFF_0000) | right;
|
||||
}
|
||||
|
||||
fn setU32H(left: u32, right: u16) u32 {
|
||||
return (left & 0x0000_FFFF) | (@as(u32, right) << 16);
|
||||
}
|
||||
|
161
src/bus/io.zig
161
src/bus/io.zig
@@ -7,6 +7,10 @@ const Bus = @import("../Bus.zig");
|
||||
const DmaController = @import("dma.zig").DmaController;
|
||||
const Scheduler = @import("../scheduler.zig").Scheduler;
|
||||
|
||||
const timer = @import("timer.zig");
|
||||
const dma = @import("dma.zig");
|
||||
const apu = @import("../apu.zig");
|
||||
|
||||
const log = std.log.scoped(.@"I/O");
|
||||
|
||||
pub const Io = struct {
|
||||
@@ -46,16 +50,10 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||
0x0400_0006 => @as(T, bus.ppu.bg[0].cnt.raw) << 16 | bus.ppu.vcount.raw,
|
||||
|
||||
// DMA Transfers
|
||||
0x0400_00B8 => @as(T, bus.dma[0].cnt.raw) << 16,
|
||||
0x0400_00C4 => @as(T, bus.dma[1].cnt.raw) << 16,
|
||||
0x0400_00D0 => @as(T, bus.dma[1].cnt.raw) << 16,
|
||||
0x0400_00DC => @as(T, bus.dma[3].cnt.raw) << 16,
|
||||
0x0400_00B8...0x0400_00DC => dma.read(T, &bus.dma, address),
|
||||
|
||||
// Timers
|
||||
0x0400_0100 => @as(T, bus.tim[0].cnt.raw) << 16 | bus.tim[0].counter(),
|
||||
0x0400_0104 => @as(T, bus.tim[1].cnt.raw) << 16 | bus.tim[1].counter(),
|
||||
0x0400_0108 => @as(T, bus.tim[2].cnt.raw) << 16 | bus.tim[2].counter(),
|
||||
0x0400_010C => @as(T, bus.tim[3].cnt.raw) << 16 | bus.tim[3].counter(),
|
||||
0x0400_0100...0x0400_010C => timer.read(T, &bus.tim, address),
|
||||
|
||||
// Serial Communication 1
|
||||
0x0400_0128 => unimplementedRead("Read {} from SIOCNT and SIOMLT_SEND", .{T}),
|
||||
@@ -83,33 +81,13 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||
0x0400_004C => unimplementedRead("Read {} from MOSAIC", .{T}),
|
||||
|
||||
// Sound
|
||||
0x0400_0060 => bus.apu.ch1.sweep.raw,
|
||||
0x0400_0062 => @as(u16, bus.apu.ch1.envelope.raw) << 8 | bus.apu.ch1.duty.raw,
|
||||
0x0400_0064 => bus.apu.ch1.freq.raw,
|
||||
0x0400_0068 => @as(u16, bus.apu.ch2.envelope.raw) << 8 | bus.apu.ch2.duty.raw,
|
||||
0x0400_006C => bus.apu.ch2.freq.raw,
|
||||
0x0400_0070 => bus.apu.ch3.select.raw,
|
||||
0x0400_0074 => bus.apu.ch3.freq.raw,
|
||||
0x0400_0078 => @as(u16, bus.apu.ch4.envelope.raw) << 8 | bus.apu.ch4.len,
|
||||
0x0400_007C => @as(u16, bus.apu.ch4.poly.raw) << 8 | bus.apu.ch4.cnt.raw,
|
||||
0x0400_0080 => bus.apu.dma_cnt.raw,
|
||||
0x0400_0088 => bus.apu.bias.raw,
|
||||
0x0400_0060...0x0400_0088 => apu.read(T, &bus.apu, address),
|
||||
|
||||
// DMA Transfers
|
||||
0x0400_00BA => bus.dma[0].cnt.raw,
|
||||
0x0400_00C6 => bus.dma[1].cnt.raw,
|
||||
0x0400_00D2 => bus.dma[2].cnt.raw,
|
||||
0x0400_00DE => bus.dma[3].cnt.raw,
|
||||
0x0400_00BA...0x0400_00DE => dma.read(T, &bus.dma, address),
|
||||
|
||||
// Timers
|
||||
0x0400_0100 => bus.tim[0].counter(),
|
||||
0x0400_0102 => bus.tim[0].cnt.raw,
|
||||
0x0400_0104 => bus.tim[1].counter(),
|
||||
0x0400_0106 => bus.tim[1].cnt.raw,
|
||||
0x0400_0108 => bus.tim[2].counter(),
|
||||
0x0400_010A => bus.tim[2].cnt.raw,
|
||||
0x0400_010C => bus.tim[3].counter(),
|
||||
0x0400_010E => bus.tim[3].cnt.raw,
|
||||
0x0400_0100...0x0400_010E => timer.read(T, &bus.tim, address),
|
||||
|
||||
// Serial Communication 1
|
||||
0x0400_0128 => unimplementedRead("Read {} from SIOCNT", .{T}),
|
||||
@@ -139,15 +117,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||
0x0400_000B => @truncate(T, bus.ppu.bg[1].cnt.raw >> 8),
|
||||
|
||||
// Sound
|
||||
0x0400_0060 => bus.apu.ch1.sweep.raw,
|
||||
0x0400_0063 => bus.apu.ch1.envelope.raw,
|
||||
0x0400_0069 => bus.apu.ch2.envelope.raw,
|
||||
0x0400_0073 => bus.apu.ch3.vol.raw,
|
||||
0x0400_0079 => bus.apu.ch4.envelope.raw,
|
||||
0x0400_007C => bus.apu.ch4.poly.raw,
|
||||
0x0400_0081 => @truncate(T, bus.apu.psg_cnt.raw >> 8),
|
||||
0x0400_0084 => bus.apu.soundCntX(),
|
||||
0x0400_0089 => @truncate(T, bus.apu.bias.raw >> 8),
|
||||
0x0400_0060...0x0400_0089 => apu.read(T, &bus.apu, address),
|
||||
|
||||
// Serial Communication 1
|
||||
0x0400_0128 => unimplementedRead("Read {} from SIOCNT_L", .{T}),
|
||||
@@ -199,35 +169,15 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
|
||||
0x0400_0058...0x0400_005C => {}, // Unused
|
||||
|
||||
// Sound
|
||||
0x0400_0080 => {
|
||||
bus.apu.psg_cnt.raw = @truncate(u16, value);
|
||||
bus.apu.dma_cnt.raw = @truncate(u16, value >> 16);
|
||||
},
|
||||
0x0400_0090...0x0400_009F => bus.apu.ch3.wave_dev.write(T, bus.apu.ch3.select, address, value),
|
||||
0x0400_00A0 => bus.apu.chA.push(value),
|
||||
0x0400_00A4 => bus.apu.chB.push(value),
|
||||
0x0400_0080...0x0400_00A4 => apu.write(T, &bus.apu, address, value),
|
||||
0x0400_00A8, 0x0400_00AC => {}, // Unused
|
||||
|
||||
// DMA Transfers
|
||||
0x0400_00B0 => bus.dma[0].writeSad(value),
|
||||
0x0400_00B4 => bus.dma[0].writeDad(value),
|
||||
0x0400_00B8 => bus.dma[0].writeCnt(value),
|
||||
0x0400_00BC => bus.dma[1].writeSad(value),
|
||||
0x0400_00C0 => bus.dma[1].writeDad(value),
|
||||
0x0400_00C4 => bus.dma[1].writeCnt(value),
|
||||
0x0400_00C8 => bus.dma[2].writeSad(value),
|
||||
0x0400_00CC => bus.dma[2].writeDad(value),
|
||||
0x0400_00D0 => bus.dma[2].writeCnt(value),
|
||||
0x0400_00D4 => bus.dma[3].writeSad(value),
|
||||
0x0400_00D8 => bus.dma[3].writeDad(value),
|
||||
0x0400_00DC => bus.dma[3].writeCnt(value),
|
||||
0x0400_00B0...0x0400_00DC => dma.write(T, &bus.dma, address, value),
|
||||
0x0400_00E0...0x0400_00FC => {}, // Unused
|
||||
|
||||
// Timers
|
||||
0x0400_0100 => bus.tim[0].writeCnt(value),
|
||||
0x0400_0104 => bus.tim[1].writeCnt(value),
|
||||
0x0400_0108 => bus.tim[2].writeCnt(value),
|
||||
0x0400_010C => bus.tim[3].writeCnt(value),
|
||||
0x0400_0100...0x0400_010C => timer.write(T, &bus.tim, address, value),
|
||||
0x0400_0110...0x0400_011C => {}, // Unused
|
||||
|
||||
// Serial Communication 1
|
||||
@@ -299,64 +249,13 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
|
||||
0x0400_004E, 0x0400_0056 => {}, // Not used
|
||||
|
||||
// Sound
|
||||
0x0400_0060 => bus.apu.ch1.sweep.raw = @truncate(u8, value), // Channel 1
|
||||
0x0400_0062 => bus.apu.ch1.setSoundCntH(value),
|
||||
0x0400_0064 => bus.apu.ch1.setFreq(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0068 => bus.apu.ch2.setSoundCntH(value), // Channel 2
|
||||
0x0400_006C => bus.apu.ch2.setFreq(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0070 => bus.apu.ch3.setWaveSelect(@truncate(u8, value)), // Channel 3
|
||||
0x0400_0072 => bus.apu.ch3.setSoundCntH(value),
|
||||
0x0400_0074 => bus.apu.ch3.setFreq(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0078 => bus.apu.ch4.setSoundCntL(value), // Channel 4
|
||||
0x0400_007C => bus.apu.ch4.setSoundCntH(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0080 => bus.apu.psg_cnt.raw = value,
|
||||
0x0400_0082 => bus.apu.setDmaCnt(value),
|
||||
0x0400_0084 => bus.apu.setSoundCntX(value >> 7 & 1 == 1),
|
||||
0x0400_0088 => bus.apu.bias.raw = value,
|
||||
0x0400_0090...0x0400_009F => bus.apu.ch3.wave_dev.write(T, bus.apu.ch3.select, address, value),
|
||||
0x0400_0060...0x0400_009F => apu.write(T, &bus.apu, address, value),
|
||||
|
||||
// Dma Transfers
|
||||
0x0400_00B0 => bus.dma[0].writeSad(bus.dma[0].sad & 0xFFFF_0000 | value),
|
||||
0x0400_00B2 => bus.dma[0].writeSad(bus.dma[0].sad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00B4 => bus.dma[0].writeDad(bus.dma[0].dad & 0xFFFF_0000 | value),
|
||||
0x0400_00B6 => bus.dma[0].writeDad(bus.dma[0].dad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00B8 => bus.dma[0].writeWordCount(value),
|
||||
0x0400_00BA => bus.dma[0].writeCntHigh(value),
|
||||
|
||||
0x0400_00BC => bus.dma[1].writeSad(bus.dma[1].sad & 0xFFFF_0000 | value),
|
||||
0x0400_00BE => bus.dma[1].writeSad(bus.dma[1].sad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00C0 => bus.dma[1].writeDad(bus.dma[1].dad & 0xFFFF_0000 | value),
|
||||
0x0400_00C2 => bus.dma[1].writeDad(bus.dma[1].dad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00C4 => bus.dma[1].writeWordCount(value),
|
||||
0x0400_00C6 => bus.dma[1].writeCntHigh(value),
|
||||
|
||||
0x0400_00C8 => bus.dma[2].writeSad(bus.dma[2].sad & 0xFFFF_0000 | value),
|
||||
0x0400_00CA => bus.dma[2].writeSad(bus.dma[2].sad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00CC => bus.dma[2].writeDad(bus.dma[2].dad & 0xFFFF_0000 | value),
|
||||
0x0400_00CE => bus.dma[2].writeDad(bus.dma[2].dad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00D0 => bus.dma[2].writeWordCount(value),
|
||||
0x0400_00D2 => bus.dma[2].writeCntHigh(value),
|
||||
|
||||
0x0400_00D4 => bus.dma[3].writeSad(bus.dma[3].sad & 0xFFFF_0000 | value),
|
||||
0x0400_00D6 => bus.dma[3].writeSad(bus.dma[3].sad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00D8 => bus.dma[3].writeDad(bus.dma[3].dad & 0xFFFF_0000 | value),
|
||||
0x0400_00DA => bus.dma[3].writeDad(bus.dma[3].dad & 0x0000_FFFF | (@as(u32, value) << 16)),
|
||||
0x0400_00DC => bus.dma[3].writeWordCount(value),
|
||||
0x0400_00DE => bus.dma[3].writeCntHigh(value),
|
||||
0x0400_00B0...0x0400_00DE => dma.write(T, &bus.dma, address, value),
|
||||
|
||||
// Timers
|
||||
0x0400_0100 => bus.tim[0].setReload(value),
|
||||
0x0400_0102 => bus.tim[0].writeCntHigh(value),
|
||||
0x0400_0104 => bus.tim[1].setReload(value),
|
||||
0x0400_0106 => bus.tim[1].writeCntHigh(value),
|
||||
0x0400_0108 => bus.tim[2].setReload(value),
|
||||
0x0400_010A => bus.tim[2].writeCntHigh(value),
|
||||
0x0400_010C => bus.tim[3].setReload(value),
|
||||
0x0400_010E => bus.tim[3].writeCntHigh(value),
|
||||
0x0400_0100...0x0400_010E => timer.write(T, &bus.tim, address, value),
|
||||
0x0400_0114 => {}, // TODO: Gyakuten Saiban writes 0x8000 to 0x0400_0114
|
||||
0x0400_0110 => {}, // Not Used,
|
||||
|
||||
@@ -399,33 +298,7 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
|
||||
0x0400_0054 => log.debug("Wrote 0x{X:0>2} to BLDY_L", .{value}),
|
||||
|
||||
// Sound
|
||||
0x0400_0060 => bus.apu.ch1.sweep.raw = value, // Channel 1
|
||||
0x0400_0062 => bus.apu.ch1.duty.raw = value,
|
||||
0x0400_0063 => bus.apu.ch1.envelope.raw = value,
|
||||
0x0400_0064 => bus.apu.ch1.setFreqLow(value),
|
||||
0x0400_0065 => bus.apu.ch1.setFreqHigh(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0068 => bus.apu.ch2.duty.raw = value, // Channel 2
|
||||
0x0400_0069 => bus.apu.ch2.envelope.raw = value,
|
||||
0x0400_006C => bus.apu.ch2.setFreqLow(value),
|
||||
0x0400_006D => bus.apu.ch2.setFreqHigh(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0070 => bus.apu.ch3.setWaveSelect(value), // Channel 3
|
||||
0x0400_0072 => bus.apu.ch3.setLength(value),
|
||||
0x0400_0073 => bus.apu.ch3.vol.raw = value,
|
||||
0x0400_0074 => bus.apu.ch3.setFreqLow(value),
|
||||
0x0400_0075 => bus.apu.ch3.setFreqHigh(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0078 => bus.apu.ch4.setLength(value), // Channel 4
|
||||
0x0400_0079 => bus.apu.ch4.setEnvelope(value),
|
||||
0x0400_007C => bus.apu.ch4.poly.raw = value,
|
||||
0x0400_007D => bus.apu.ch4.setCnt(&bus.apu.fs, value),
|
||||
|
||||
0x0400_0080 => bus.apu.setSoundCntLLow(value),
|
||||
0x0400_0081 => bus.apu.setSoundCntLHigh(value),
|
||||
0x0400_0084 => bus.apu.setSoundCntX(value >> 7 & 1 == 1),
|
||||
0x0400_0089 => bus.apu.setBiasHigh(value),
|
||||
0x0400_0090...0x0400_009F => bus.apu.ch3.wave_dev.write(T, bus.apu.ch3.select, address, value),
|
||||
0x0400_0060...0x0400_009F => apu.write(T, &bus.apu, address, value),
|
||||
|
||||
// Serial Communication 1
|
||||
0x0400_0120 => log.debug("Wrote 0x{X:0>2} to SIODATA32_L_L", .{value}),
|
||||
|
@@ -13,17 +13,71 @@ pub fn create(sched: *Scheduler) TimerTuple {
|
||||
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 {
|
||||
const nybble = @truncate(u4, addr);
|
||||
|
||||
return switch (T) {
|
||||
u32 => switch (nybble) {
|
||||
0x0 => @as(T, tim.*[0].cnt.raw) << 16 | tim.*[0].getCntL(),
|
||||
0x4 => @as(T, tim.*[1].cnt.raw) << 16 | tim.*[1].getCntL(),
|
||||
0x8 => @as(T, tim.*[2].cnt.raw) << 16 | tim.*[2].getCntL(),
|
||||
0xC => @as(T, tim.*[3].cnt.raw) << 16 | tim.*[3].getCntL(),
|
||||
else => @panic("TODO: u32 timer unexpected nybble"),
|
||||
},
|
||||
u16 => switch (nybble) {
|
||||
0x0 => tim.*[0].getCntL(),
|
||||
0x2 => tim.*[0].cnt.raw,
|
||||
0x4 => tim.*[1].getCntL(),
|
||||
0x6 => tim.*[1].cnt.raw,
|
||||
0x8 => tim.*[2].getCntL(),
|
||||
0xA => tim.*[2].cnt.raw,
|
||||
0xC => tim.*[3].getCntL(),
|
||||
0xE => tim.*[3].cnt.raw,
|
||||
else => @panic("TODO: u16 timer unexpected nybble"),
|
||||
},
|
||||
u8 => @panic("TODO: u8 timer unexpected read"),
|
||||
else => @compileError("TIMX: Unsupported read width"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write(comptime T: type, tim: *TimerTuple, addr: u32, value: T) void {
|
||||
const nybble = @truncate(u4, addr);
|
||||
|
||||
return switch (T) {
|
||||
u32 => switch (nybble) {
|
||||
0x0 => tim.*[0].setCnt(value),
|
||||
0x4 => tim.*[1].setCnt(value),
|
||||
0x8 => tim.*[2].setCnt(value),
|
||||
0xC => tim.*[3].setCnt(value),
|
||||
else => @panic("TODO: u32 timer unexpected nybble"),
|
||||
},
|
||||
u16 => switch (nybble) {
|
||||
0x0 => tim.*[0].setCntL(value),
|
||||
0x2 => tim.*[0].setCntH(value),
|
||||
0x4 => tim.*[1].setCntL(value),
|
||||
0x6 => tim.*[1].setCntH(value),
|
||||
0x8 => tim.*[2].setCntL(value),
|
||||
0xA => tim.*[2].setCntH(value),
|
||||
0xC => tim.*[3].setCntL(value),
|
||||
0xE => tim.*[3].setCntH(value),
|
||||
else => @panic("TODO: u16 timer unexpected nybble"),
|
||||
},
|
||||
u8 => @panic("TODO: u8 timer unexpected write"),
|
||||
else => @compileError("TIMX: Unsupported write width"),
|
||||
};
|
||||
}
|
||||
|
||||
fn Timer(comptime id: u2) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
/// Read Only, Internal. Please use self.counter()
|
||||
/// Read Only, Internal. Please use self.getCntL()
|
||||
_counter: u16,
|
||||
|
||||
/// Write Only, Internal. Please use self.setReload()
|
||||
/// Write Only, Internal. Please use self.setCntL()
|
||||
_reload: u16,
|
||||
|
||||
/// Write Only, Internal. Please use self.WriteCntHigh()
|
||||
/// Write Only, Internal. Please use self.setCntH()
|
||||
cnt: TimerControl,
|
||||
|
||||
/// Internal.
|
||||
@@ -42,22 +96,26 @@ fn Timer(comptime id: u2) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn counter(self: *const Self) u16 {
|
||||
/// TIMCNT_L
|
||||
pub fn getCntL(self: *const Self) u16 {
|
||||
if (self.cnt.cascade.read() or !self.cnt.enabled.read()) return self._counter;
|
||||
|
||||
return self._counter +% @truncate(u16, (self.sched.now() - self._start_timestamp) / self.frequency());
|
||||
}
|
||||
|
||||
pub fn writeCnt(self: *Self, word: u32) void {
|
||||
self.setReload(@truncate(u16, word));
|
||||
self.writeCntHigh(@truncate(u16, word >> 16));
|
||||
}
|
||||
|
||||
pub fn setReload(self: *Self, halfword: u16) void {
|
||||
/// TIMCNT_L
|
||||
pub fn setCntL(self: *Self, halfword: u16) void {
|
||||
self._reload = halfword;
|
||||
}
|
||||
|
||||
pub fn writeCntHigh(self: *Self, halfword: u16) void {
|
||||
/// TIMCNT_L & TIMCNT_H
|
||||
pub fn setCnt(self: *Self, word: u32) void {
|
||||
self.setCntL(@truncate(u16, word));
|
||||
self.setCntH(@truncate(u16, word >> 16));
|
||||
}
|
||||
|
||||
/// TIMCNT_H
|
||||
pub fn setCntH(self: *Self, halfword: u16) void {
|
||||
const new = TimerControl{ .raw = halfword };
|
||||
|
||||
// If Timer happens to be enabled, It will either be resheduled or disabled
|
||||
|
Reference in New Issue
Block a user