diff --git a/src/Bus.zig b/src/Bus.zig index 54ed0e2..2ba4c8f 100644 --- a/src/Bus.zig +++ b/src/Bus.zig @@ -147,7 +147,7 @@ pub fn read8(self: *const Self, addr: u32) u8 { 0x0800_0000...0x09FF_FFFF => self.pak.get8(addr - 0x0800_0000), 0x0A00_0000...0x0BFF_FFFF => self.pak.get8(addr - 0x0A00_0000), 0x0C00_0000...0x0DFF_FFFF => self.pak.get8(addr - 0x0C00_0000), - 0x0E00_0000...0x0EFF_FFFF => self.pak.sram.get8(addr & 0xFFFF), + 0x0E00_0000...0x0E00_FFFF => self.pak.backup.get8(addr & 0xFFFF), else => undRead("Tried to read from 0x{X:0>2}", .{addr}), }; @@ -162,7 +162,7 @@ pub fn write8(self: *Self, addr: u32, byte: u8) void { 0x0400_0410 => log.info("Ignored write of 0x{X:0>2} to 0x{X:0>8}", .{ byte, addr }), // External Memory (Game Pak) - 0x0E00_0000...0x0E00_FFFF => self.pak.sram.set8(addr & 0xFFFF, byte), + 0x0E00_0000...0x0E00_FFFF => self.pak.backup.set8(addr & 0xFFFF, byte), else => undWrite("Tried to write 0x{X:0>2} to 0x{X:0>8}", .{ byte, addr }), } } diff --git a/src/bus/GamePak.zig b/src/bus/GamePak.zig index de3deb7..7dbdc74 100644 --- a/src/bus/GamePak.zig +++ b/src/bus/GamePak.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const Sram = @import("Sram.zig"); +const Backup = @import("backup.zig").Backup; const Allocator = std.mem.Allocator; const log = std.log.scoped(.GamePak); const Self = @This(); @@ -8,7 +8,7 @@ const Self = @This(); title: [12]u8, buf: []u8, alloc: Allocator, -sram: Sram, +backup: Backup, pub fn init(alloc: Allocator, path: []const u8) !Self { const file = try std.fs.cwd().openFile(path, .{}); @@ -18,11 +18,13 @@ pub fn init(alloc: Allocator, path: []const u8) !Self { const buf = try file.readToEndAlloc(alloc, len); const title = parseTitle(buf); + const kind = Backup.guessKind(buf) orelse .Sram; + const pak = Self{ .buf = buf, .alloc = alloc, .title = title, - .sram = try Sram.init(alloc), + .backup = try Backup.init(alloc, kind), }; pak.parseHeader(); @@ -55,7 +57,7 @@ fn lookupMaker(slice: *const [2]u8) ?[]const u8 { pub fn deinit(self: Self) void { self.alloc.free(self.buf); - self.sram.deinit(); + self.backup.deinit(); } pub fn get32(self: *const Self, idx: usize) u32 { diff --git a/src/bus/Sram.zig b/src/bus/Sram.zig deleted file mode 100644 index ae6705f..0000000 --- a/src/bus/Sram.zig +++ /dev/null @@ -1,31 +0,0 @@ -const std = @import("std"); - -const Allocator = std.mem.Allocator; -const log = std.log.scoped(.SRAM); -const Self = @This(); - -buf: []u8, -alloc: Allocator, - -pub fn init(alloc: Allocator) !Self { - // FIXME: SRAM is more than just a 64KB block of memory - const buf = try alloc.alloc(u8, 0x10000); - std.mem.set(u8, buf, 0); - - return Self{ - .buf = buf, - .alloc = alloc, - }; -} - -pub fn deinit(self: Self) void { - self.alloc.free(self.buf); -} - -pub fn get8(self: *const Self, idx: usize) u8 { - return self.buf[idx]; -} - -pub fn set8(self: *Self, idx: usize, byte: u8) void { - self.buf[idx] = byte; -} diff --git a/src/bus/backup.zig b/src/bus/backup.zig new file mode 100644 index 0000000..80eac79 --- /dev/null +++ b/src/bus/backup.zig @@ -0,0 +1,98 @@ +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const log = std.log.scoped(.Backup); + +const backup_kinds = [5]Needle{ + .{ .str = "EEPROM_V", .kind = .Eeprom }, + .{ .str = "SRAM_V", .kind = .Sram }, + .{ .str = "FLASH_V", .kind = .Flash }, + .{ .str = "FLASH512_V", .kind = .Flash }, + .{ .str = "FLASH1M_V", .kind = .Flash1M }, +}; + +pub const Backup = struct { + const Self = @This(); + + buf: []u8, + alloc: Allocator, + kind: BackupKind, + + pub fn init(alloc: Allocator, kind: BackupKind) !Self { + const buf_len: usize = switch (kind) { + .Sram => 0x8000, // 32K + .Flash => 0x10000, // 64K + .Flash1M => 0x20000, // 128K + .Eeprom => 0x2000, // FIXME: We assume 8K here + }; + + const buf = try alloc.alloc(u8, buf_len); + std.mem.set(u8, buf, 0); + + return Self{ + .buf = buf, + .alloc = alloc, + .kind = kind, + }; + } + + pub fn guessKind(rom: []const u8) ?BackupKind { + @setRuntimeSafety(false); + + for (backup_kinds) |needle| { + const needle_len = needle.str.len; + + var i: usize = 0; + while ((i + needle_len) < rom.len) : (i += 1) { + if (std.mem.eql(u8, needle.str, rom[i..][0..needle_len])) return needle.kind; + } + } + + return null; + } + + pub fn deinit(self: Self) void { + self.alloc.free(self.buf); + } + + pub fn get8(self: *const Self, idx: usize) u8 { + // TODO: Implement Flash and EEPROM + switch (self.kind) { + .Flash => return switch (idx) { + 0x0000 => 0x32, // Panasonic manufacturer ID + 0x0001 => 0x1B, // Panasonic device ID + else => self.buf[idx], + }, + .Flash1M => return switch (idx) { + 0x0000 => 0x62, // Sanyo manufacturer ID + 0x0001 => 0x13, // Sanyo device ID + else => self.buf[idx], + }, + .Eeprom => return self.buf[idx], + .Sram => return self.buf[idx & 0x7FFF], // 32K SRAM chips are repeated + } + } + + pub fn set8(self: *Self, idx: usize, byte: u8) void { + self.buf[idx] = byte; + } +}; + +const BackupKind = enum { + Eeprom, + Sram, + Flash, + Flash1M, +}; + +const Needle = struct { + str: []const u8, + kind: BackupKind, + + fn init(str: []const u8, kind: BackupKind) @This() { + return .{ + .str = str, + .kind = kind, + }; + } +};