feat: implement WRAM
This commit is contained in:
parent
eba2de39fb
commit
f0b5bb1207
|
@ -1 +1 @@
|
||||||
Subproject commit 481271ba2abcaab82b0930a10d424134099143c8
|
Subproject commit 1bd96304badf24d50698e04abaf8f45c31571d6d
|
133
src/core/emu.zig
133
src/core/emu.zig
|
@ -92,33 +92,150 @@ pub fn runFrame(scheduler: *Scheduler, system: System) void {
|
||||||
// FIXME: Perf win to allocating on the stack instead?
|
// FIXME: Perf win to allocating on the stack instead?
|
||||||
pub const SharedContext = struct {
|
pub const SharedContext = struct {
|
||||||
const MiB = 0x100000;
|
const MiB = 0x100000;
|
||||||
|
const KiB = 0x400;
|
||||||
|
|
||||||
io: *SharedIo,
|
io: *SharedIo,
|
||||||
main: *[4 * MiB]u8,
|
main: *[4 * MiB]u8,
|
||||||
|
wram: *Wram,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !@This() {
|
pub fn init(allocator: Allocator) !@This() {
|
||||||
|
const wram = try allocator.create(Wram);
|
||||||
|
errdefer allocator.destroy(wram);
|
||||||
|
|
||||||
|
try wram.init(allocator);
|
||||||
|
|
||||||
const ctx = .{
|
const ctx = .{
|
||||||
.io = try allocator.create(SharedIo),
|
.io = blk: {
|
||||||
|
const io = try allocator.create(SharedIo);
|
||||||
|
io.* = .{};
|
||||||
|
|
||||||
|
break :blk io;
|
||||||
|
},
|
||||||
|
.wram = wram,
|
||||||
.main = try allocator.create([4 * MiB]u8),
|
.main = try allocator.create([4 * MiB]u8),
|
||||||
};
|
};
|
||||||
ctx.io.* = .{};
|
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: @This(), allocator: Allocator) void {
|
pub fn deinit(self: @This(), allocator: Allocator) void {
|
||||||
|
self.wram.deinit(allocator);
|
||||||
|
allocator.destroy(self.wram);
|
||||||
|
|
||||||
allocator.destroy(self.io);
|
allocator.destroy(self.io);
|
||||||
allocator.destroy(self.main);
|
allocator.destroy(self.main);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub inline fn forceAlign(comptime T: type, address: u32) u32 {
|
// Before I implement Bus-wide Fastmem, Let's play with some more limited (read: less useful)
|
||||||
return switch (T) {
|
// fastmem implementations
|
||||||
u32 => address & ~@as(u32, 3),
|
|
||||||
u16 => address & ~@as(u32, 1),
|
// TODO: move somewhere else ideally
|
||||||
u8 => address,
|
pub const Wram = struct {
|
||||||
else => @compileError("Bus: Invalid read/write type"),
|
const page_size = 1 * KiB; // perhaps too big?
|
||||||
|
const addr_space_size = 0x8000;
|
||||||
|
const table_len = addr_space_size / page_size;
|
||||||
|
const IntFittingRange = std.math.IntFittingRange;
|
||||||
|
|
||||||
|
const io = @import("io.zig");
|
||||||
|
const KiB = 0x400;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.shared_wram);
|
||||||
|
|
||||||
|
_buf: *[32 * KiB]u8,
|
||||||
|
|
||||||
|
nds9_table: *const [table_len]?[*]u8,
|
||||||
|
nds7_table: *const [table_len]?[*]u8,
|
||||||
|
|
||||||
|
pub fn init(self: *@This(), allocator: Allocator) !void {
|
||||||
|
const buf = try allocator.create([32 * KiB]u8);
|
||||||
|
errdefer allocator.destroy(buf);
|
||||||
|
|
||||||
|
const tables = try allocator.alloc(?[*]u8, 2 * table_len);
|
||||||
|
@memset(tables, null);
|
||||||
|
|
||||||
|
self.* = .{
|
||||||
|
.nds9_table = tables[0..table_len],
|
||||||
|
.nds7_table = tables[table_len .. 2 * table_len],
|
||||||
|
._buf = buf,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: @This(), allocator: Allocator) void {
|
||||||
|
allocator.destroy(self._buf);
|
||||||
|
|
||||||
|
const ptr: [*]?[*]const u8 = @ptrCast(@constCast(self.nds9_table));
|
||||||
|
allocator.free(ptr[0 .. 2 * table_len]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *@This(), wramcnt: io.WramCnt) void {
|
||||||
|
const mode = wramcnt.mode.read();
|
||||||
|
|
||||||
|
const nds9_tbl = @constCast(self.nds9_table);
|
||||||
|
const nds7_tbl = @constCast(self.nds7_table);
|
||||||
|
|
||||||
|
for (nds9_tbl, nds7_tbl, 0..) |*nds9_ptr, *nds7_ptr, i| {
|
||||||
|
const addr = i * page_size;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
0b00 => {
|
||||||
|
nds9_ptr.* = self._buf[addr..].ptr;
|
||||||
|
nds7_ptr.* = null;
|
||||||
|
},
|
||||||
|
0b01 => {
|
||||||
|
nds9_ptr.* = self._buf[0x4000 + (addr & 0x3FFF) ..].ptr;
|
||||||
|
nds7_ptr.* = self._buf[(addr & 0x3FFF)..].ptr;
|
||||||
|
},
|
||||||
|
0b10 => {
|
||||||
|
nds9_ptr.* = self._buf[(addr & 0x3FFF)..].ptr;
|
||||||
|
nds7_ptr.* = self._buf[0x4000 + (addr & 0x3FFF) ..].ptr;
|
||||||
|
},
|
||||||
|
0b11 => {
|
||||||
|
nds9_ptr.* = null;
|
||||||
|
nds7_ptr.* = self._buf[addr..].ptr;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rename
|
||||||
|
const Device = enum { nds9, nds7 };
|
||||||
|
|
||||||
|
pub fn read(self: @This(), comptime T: type, comptime dev: Device, address: u32) T {
|
||||||
|
const bits = @typeInfo(IntFittingRange(0, page_size - 1)).Int.bits;
|
||||||
|
const page = address >> bits;
|
||||||
|
const offset = address & (page_size - 1);
|
||||||
|
const table = if (dev == .nds9) self.nds9_table else self.nds7_table;
|
||||||
|
|
||||||
|
if (table[page]) |some_ptr| {
|
||||||
|
const ptr: [*]align(1) const T = @ptrCast(@alignCast(some_ptr));
|
||||||
|
|
||||||
|
return ptr[offset / @sizeOf(T)];
|
||||||
|
}
|
||||||
|
|
||||||
|
log.err("{s}: read(T: {}, addr: 0x{X:0>8}) was in un-mapped WRAM space", .{ @tagName(dev), T, 0x0300_0000 + address });
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(self: *@This(), comptime T: type, comptime dev: Device, address: u32, value: T) void {
|
||||||
|
const bits = @typeInfo(IntFittingRange(0, page_size - 1)).Int.bits;
|
||||||
|
const page = address >> bits;
|
||||||
|
const offset = address & (page_size - 1);
|
||||||
|
const table = if (dev == .nds9) self.nds9_table else self.nds7_table;
|
||||||
|
|
||||||
|
if (table[page]) |some_ptr| {
|
||||||
|
const ptr: [*]align(1) T = @ptrCast(@alignCast(some_ptr));
|
||||||
|
ptr[offset / @sizeOf(T)] = value;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.err("{s}: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8}) was in un-mapped WRAM space", .{ @tagName(dev), T, 0x0300_0000 + address, value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub inline fn forceAlign(comptime T: type, address: u32) u32 {
|
||||||
|
return address & ~@as(u32, @sizeOf(T) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const System = struct {
|
pub const System = struct {
|
||||||
|
|
|
@ -35,6 +35,8 @@ pub const Io = struct {
|
||||||
/// Caller must cast the `u8` to either `nds7.PostFlg` or `nds9.PostFlg`
|
/// Caller must cast the `u8` to either `nds7.PostFlg` or `nds9.PostFlg`
|
||||||
post_flg: u8 = @intFromEnum(nds7.PostFlag.in_progress),
|
post_flg: u8 = @intFromEnum(nds7.PostFlag.in_progress),
|
||||||
|
|
||||||
|
wramcnt: WramCnt = .{ .raw = 0x00 },
|
||||||
|
|
||||||
// TODO: DS Cartridge I/O Ports
|
// TODO: DS Cartridge I/O Ports
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,10 +76,30 @@ const IpcFifo = struct {
|
||||||
.nds7 => {
|
.nds7 => {
|
||||||
self._nds7.sync.raw = masks.ipcFifoSync(self._nds7.sync.raw, value);
|
self._nds7.sync.raw = masks.ipcFifoSync(self._nds7.sync.raw, value);
|
||||||
self._nds9.sync.raw = masks.mask(self._nds9.sync.raw, (self._nds7.sync.raw >> 8) & 0xF, 0xF);
|
self._nds9.sync.raw = masks.mask(self._nds9.sync.raw, (self._nds7.sync.raw >> 8) & 0xF, 0xF);
|
||||||
|
|
||||||
|
if (value >> 3 & 1 == 1) {
|
||||||
|
self._nds7.fifo.reset();
|
||||||
|
|
||||||
|
self._nds7.cnt.send_fifo_empty.write(true);
|
||||||
|
self._nds9.cnt.recv_fifo_empty.write(true);
|
||||||
|
|
||||||
|
self._nds7.cnt.send_fifo_full.write(false);
|
||||||
|
self._nds9.cnt.recv_fifo_full.write(false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.nds9 => {
|
.nds9 => {
|
||||||
self._nds9.sync.raw = masks.ipcFifoSync(self._nds9.sync.raw, value);
|
self._nds9.sync.raw = masks.ipcFifoSync(self._nds9.sync.raw, value);
|
||||||
self._nds7.sync.raw = masks.mask(self._nds7.sync.raw, (self._nds9.sync.raw >> 8) & 0xF, 0xF);
|
self._nds7.sync.raw = masks.mask(self._nds7.sync.raw, (self._nds9.sync.raw >> 8) & 0xF, 0xF);
|
||||||
|
|
||||||
|
if (value >> 3 & 1 == 1) {
|
||||||
|
self._nds9.fifo.reset();
|
||||||
|
|
||||||
|
self._nds9.cnt.send_fifo_empty.write(true);
|
||||||
|
self._nds7.cnt.recv_fifo_empty.write(true);
|
||||||
|
|
||||||
|
self._nds9.cnt.send_fifo_full.write(false);
|
||||||
|
self._nds7.cnt.recv_fifo_full.write(false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +240,11 @@ const IpcFifoCnt = extern union {
|
||||||
raw: u32,
|
raw: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const WramCnt = extern union {
|
||||||
|
mode: Bitfield(u8, 0, 2),
|
||||||
|
raw: u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const masks = struct {
|
pub const masks = struct {
|
||||||
const Bus9 = @import("nds9/Bus.zig");
|
const Bus9 = @import("nds9/Bus.zig");
|
||||||
const Bus7 = @import("nds7/Bus.zig");
|
const Bus7 = @import("nds7/Bus.zig");
|
||||||
|
|
|
@ -4,6 +4,7 @@ const io = @import("io.zig");
|
||||||
const Scheduler = @import("../Scheduler.zig");
|
const Scheduler = @import("../Scheduler.zig");
|
||||||
const SharedIo = @import("../io.zig").Io;
|
const SharedIo = @import("../io.zig").Io;
|
||||||
const SharedContext = @import("../emu.zig").SharedContext;
|
const SharedContext = @import("../emu.zig").SharedContext;
|
||||||
|
const Wram = @import("../emu.zig").Wram;
|
||||||
const forceAlign = @import("../emu.zig").forceAlign;
|
const forceAlign = @import("../emu.zig").forceAlign;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
@ -16,6 +17,7 @@ const log = std.log.scoped(.nds7_bus);
|
||||||
|
|
||||||
scheduler: *Scheduler,
|
scheduler: *Scheduler,
|
||||||
main: *[4 * MiB]u8,
|
main: *[4 * MiB]u8,
|
||||||
|
wram_shr: *Wram,
|
||||||
wram: *[64 * KiB]u8,
|
wram: *[64 * KiB]u8,
|
||||||
io: io.Io,
|
io: io.Io,
|
||||||
|
|
||||||
|
@ -26,6 +28,7 @@ pub fn init(allocator: Allocator, scheduler: *Scheduler, shared_ctx: SharedConte
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.main = shared_ctx.main,
|
.main = shared_ctx.main,
|
||||||
|
.wram_shr = shared_ctx.wram,
|
||||||
.wram = wram,
|
.wram = wram,
|
||||||
.scheduler = scheduler,
|
.scheduler = scheduler,
|
||||||
.io = io.Io.init(shared_ctx.io),
|
.io = io.Io.init(shared_ctx.io),
|
||||||
|
@ -60,6 +63,10 @@ fn _read(self: *@This(), comptime T: type, comptime mode: Mode, address: u32) T
|
||||||
|
|
||||||
return switch (aligned_addr) {
|
return switch (aligned_addr) {
|
||||||
0x0200_0000...0x02FF_FFFF => readInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count]),
|
0x0200_0000...0x02FF_FFFF => readInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count]),
|
||||||
|
0x0300_0000...0x037F_FFFF => switch (self.io.shared.wramcnt.mode.read()) {
|
||||||
|
0b00 => readInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count]),
|
||||||
|
else => self.wram_shr.read(T, .nds7, address & 0x7FFF),
|
||||||
|
},
|
||||||
0x0380_0000...0x0380_FFFF => readInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count]),
|
0x0380_0000...0x0380_FFFF => readInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count]),
|
||||||
0x0400_0000...0x04FF_FFFF => io.read(self, T, aligned_addr),
|
0x0400_0000...0x04FF_FFFF => io.read(self, T, aligned_addr),
|
||||||
else => warn("unexpected read: 0x{x:0>8} -> {}", .{ aligned_addr, T }),
|
else => warn("unexpected read: 0x{x:0>8} -> {}", .{ aligned_addr, T }),
|
||||||
|
@ -88,6 +95,10 @@ fn _write(self: *@This(), comptime T: type, comptime mode: Mode, address: u32, v
|
||||||
|
|
||||||
switch (aligned_addr) {
|
switch (aligned_addr) {
|
||||||
0x0200_0000...0x02FF_FFFF => writeInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count], value),
|
0x0200_0000...0x02FF_FFFF => writeInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count], value),
|
||||||
|
0x0300_0000...0x037F_FFFF => switch (self.io.shared.wramcnt.mode.read()) {
|
||||||
|
0b00 => writeInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count], value),
|
||||||
|
else => self.wram_shr.write(T, .nds7, address & 0x7FFF, value),
|
||||||
|
},
|
||||||
0x0380_0000...0x0380_FFFF => writeInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count], value),
|
0x0380_0000...0x0380_FFFF => writeInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count], value),
|
||||||
0x0400_0000...0x04FF_FFFF => io.write(self, T, aligned_addr, value),
|
0x0400_0000...0x04FF_FFFF => io.write(self, T, aligned_addr, value),
|
||||||
else => log.warn("unexpected write: 0x{X:}{} -> 0x{X:0>8}", .{ value, T, aligned_addr }),
|
else => log.warn("unexpected write: 0x{X:}{} -> 0x{X:0>8}", .{ value, T, aligned_addr }),
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||||
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
||||||
},
|
},
|
||||||
u8 => switch (address) {
|
u8 => switch (address) {
|
||||||
|
0x0400_0241 => bus.io.shared.wramcnt.raw,
|
||||||
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
||||||
},
|
},
|
||||||
else => @compileError(T ++ " is an unsupported bus read type"),
|
else => @compileError(T ++ " is an unsupported bus read type"),
|
||||||
|
|
|
@ -4,6 +4,7 @@ const io = @import("io.zig");
|
||||||
const Ppu = @import("../ppu.zig").Ppu;
|
const Ppu = @import("../ppu.zig").Ppu;
|
||||||
const Scheduler = @import("../Scheduler.zig");
|
const Scheduler = @import("../Scheduler.zig");
|
||||||
const SharedContext = @import("../emu.zig").SharedContext;
|
const SharedContext = @import("../emu.zig").SharedContext;
|
||||||
|
const Wram = @import("../emu.zig").Wram;
|
||||||
const forceAlign = @import("../emu.zig").forceAlign;
|
const forceAlign = @import("../emu.zig").forceAlign;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
@ -15,6 +16,7 @@ const KiB = 0x400;
|
||||||
const log = std.log.scoped(.nds9_bus);
|
const log = std.log.scoped(.nds9_bus);
|
||||||
|
|
||||||
main: *[4 * MiB]u8,
|
main: *[4 * MiB]u8,
|
||||||
|
wram: *Wram,
|
||||||
vram1: *[512 * KiB]u8, // TODO: Rename
|
vram1: *[512 * KiB]u8, // TODO: Rename
|
||||||
io: io.Io,
|
io: io.Io,
|
||||||
ppu: Ppu,
|
ppu: Ppu,
|
||||||
|
@ -31,6 +33,7 @@ pub fn init(allocator: Allocator, scheduler: *Scheduler, shared_ctx: SharedConte
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.main = shared_ctx.main,
|
.main = shared_ctx.main,
|
||||||
|
.wram = shared_ctx.wram,
|
||||||
.vram1 = vram1_mem,
|
.vram1 = vram1_mem,
|
||||||
.ppu = try Ppu.init(allocator),
|
.ppu = try Ppu.init(allocator),
|
||||||
.scheduler = scheduler,
|
.scheduler = scheduler,
|
||||||
|
@ -40,7 +43,6 @@ pub fn init(allocator: Allocator, scheduler: *Scheduler, shared_ctx: SharedConte
|
||||||
|
|
||||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||||
self.ppu.deinit(allocator);
|
self.ppu.deinit(allocator);
|
||||||
|
|
||||||
allocator.destroy(self.vram1);
|
allocator.destroy(self.vram1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ fn _read(self: *@This(), comptime T: type, comptime mode: Mode, address: u32) T
|
||||||
|
|
||||||
return switch (aligned_addr) {
|
return switch (aligned_addr) {
|
||||||
0x0200_0000...0x02FF_FFFF => readInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count]),
|
0x0200_0000...0x02FF_FFFF => readInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count]),
|
||||||
|
0x0300_0000...0x03FF_FFFF => self.wram.read(T, .nds9, aligned_addr & 0x7FFF),
|
||||||
0x0400_0000...0x04FF_FFFF => io.read(self, T, aligned_addr),
|
0x0400_0000...0x04FF_FFFF => io.read(self, T, aligned_addr),
|
||||||
0x0600_0000...0x06FF_FFFF => readInt(T, self.vram1[aligned_addr & 0x0007_FFFF ..][0..byte_count]),
|
0x0600_0000...0x06FF_FFFF => readInt(T, self.vram1[aligned_addr & 0x0007_FFFF ..][0..byte_count]),
|
||||||
else => warn("unexpected read: 0x{x:0>8} -> {}", .{ aligned_addr, T }),
|
else => warn("unexpected read: 0x{x:0>8} -> {}", .{ aligned_addr, T }),
|
||||||
|
@ -99,6 +102,7 @@ fn _write(self: *@This(), comptime T: type, comptime mode: Mode, address: u32, v
|
||||||
|
|
||||||
switch (aligned_addr) {
|
switch (aligned_addr) {
|
||||||
0x0200_0000...0x02FF_FFFF => writeInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count], value),
|
0x0200_0000...0x02FF_FFFF => writeInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count], value),
|
||||||
|
0x0300_0000...0x03FF_FFFF => self.wram.write(T, .nds9, aligned_addr & 0x7FFF, value),
|
||||||
0x0400_0000...0x04FF_FFFF => io.write(self, T, aligned_addr, value),
|
0x0400_0000...0x04FF_FFFF => io.write(self, T, aligned_addr, value),
|
||||||
0x0600_0000...0x06FF_FFFF => writeInt(T, self.vram1[aligned_addr & 0x0007_FFFF ..][0..byte_count], value),
|
0x0600_0000...0x06FF_FFFF => writeInt(T, self.vram1[aligned_addr & 0x0007_FFFF ..][0..byte_count], value),
|
||||||
else => log.warn("unexpected write: 0x{X:}{} -> 0x{X:0>8}", .{ value, T, aligned_addr }),
|
else => log.warn("unexpected write: 0x{X:}{} -> 0x{X:0>8}", .{ value, T, aligned_addr }),
|
||||||
|
|
|
@ -135,6 +135,10 @@ pub fn write(bus: *Bus, comptime T: type, address: u32, value: T) void {
|
||||||
0x0400_0241 => bus.ppu.io.vramcnt_b.raw = value,
|
0x0400_0241 => bus.ppu.io.vramcnt_b.raw = value,
|
||||||
0x0400_0242 => bus.ppu.io.vramcnt_c.raw = value,
|
0x0400_0242 => bus.ppu.io.vramcnt_c.raw = value,
|
||||||
0x0400_0243 => bus.ppu.io.vramcnt_d.raw = value,
|
0x0400_0243 => bus.ppu.io.vramcnt_d.raw = value,
|
||||||
|
0x0400_0247 => {
|
||||||
|
bus.io.shared.wramcnt.raw = value;
|
||||||
|
bus.wram.update(bus.io.shared.wramcnt);
|
||||||
|
},
|
||||||
|
|
||||||
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
|
else => log.warn("unexpected: write(T: {}, addr: 0x{X:0>8}, value: 0x{X:0>8})", .{ T, address, value }),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue