chore(bios): impl bios handlers
This commit is contained in:
		@@ -75,7 +75,7 @@ pub fn loadFirm(allocator: Allocator, system: System, firm_path: []const u8) !vo
 | 
			
		||||
        const buf = try file.readToEndAlloc(allocator, try file.getEndPos());
 | 
			
		||||
        defer allocator.free(buf);
 | 
			
		||||
 | 
			
		||||
        @memcpy(system.bus7.bios[0..buf.len], buf);
 | 
			
		||||
        try system.bus7.bios.load(allocator, buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    { // NDS9 BIOS
 | 
			
		||||
@@ -90,7 +90,7 @@ pub fn loadFirm(allocator: Allocator, system: System, firm_path: []const u8) !vo
 | 
			
		||||
        const buf = try file.readToEndAlloc(allocator, try file.getEndPos());
 | 
			
		||||
        defer allocator.free(buf);
 | 
			
		||||
 | 
			
		||||
        @memcpy(system.bus9.bios[0..buf.len], buf);
 | 
			
		||||
        try system.bus9.bios.load(allocator, buf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								src/core/nds7/Bios.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/core/nds7/Bios.zig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
 | 
			
		||||
const log = std.log.scoped(.nds7_bios);
 | 
			
		||||
 | 
			
		||||
const KiB = 0x400;
 | 
			
		||||
const len = 16 * KiB;
 | 
			
		||||
 | 
			
		||||
buf: ?*align(4) [len]u8 = null,
 | 
			
		||||
 | 
			
		||||
// FIXME: Currently we dupe here, should we just take ownership?
 | 
			
		||||
pub fn load(self: *@This(), allocator: Allocator, data: []u8) !void {
 | 
			
		||||
    if (data.len != len) {
 | 
			
		||||
        const acutal_size = @as(f32, @floatFromInt(data.len)) / KiB;
 | 
			
		||||
        log.warn("BIOS was {d:.2} KiB (should be {} KiB)", .{ acutal_size, len });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const buf = try allocator.alignedAlloc(u8, 4, len);
 | 
			
		||||
    @memset(buf, 0);
 | 
			
		||||
    @memcpy(buf[0..data.len], data);
 | 
			
		||||
 | 
			
		||||
    self.* = .{ .buf = buf[0..len] };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn deinit(self: @This(), allocator: Allocator) void {
 | 
			
		||||
    if (self.buf) |ptr| allocator.destroy(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Note: Parts of 16MiB addrspace that aren't mapped to BIOS are typically undefined
 | 
			
		||||
pub fn read(self: *const @This(), comptime T: type, address: u32) T {
 | 
			
		||||
    const readInt = std.mem.readIntLittle;
 | 
			
		||||
    const byte_count = @divExact(@typeInfo(T).Int.bits, 8);
 | 
			
		||||
 | 
			
		||||
    // if (address >= len) return 0x0000_0000; // TODO: What is undefined actually?
 | 
			
		||||
 | 
			
		||||
    const ptr = self.buf orelse {
 | 
			
		||||
        log.err("read(T: {}, address: 0x{X:0>8}) from BIOS but none was found!", .{ T, address });
 | 
			
		||||
        @panic("TODO: ability to load in NDS7 BIOS just-in-time");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return readInt(T, ptr[address & (len - 1) ..][0..byte_count]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn write(_: *const @This(), comptime T: type, address: u32, value: T) void {
 | 
			
		||||
    log.err("write(T: {}, address: 0x{X:0>8}, value: 0x{X:}) but we're in the BIOS!", .{ T, address, value });
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ const Scheduler = @import("../Scheduler.zig");
 | 
			
		||||
const SharedCtx = @import("../emu.zig").SharedCtx;
 | 
			
		||||
const Wram = @import("../emu.zig").Wram;
 | 
			
		||||
const Vram = @import("../ppu.zig").Vram;
 | 
			
		||||
const Bios = @import("Bios.zig");
 | 
			
		||||
const forceAlign = @import("../emu.zig").forceAlign;
 | 
			
		||||
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
@@ -20,18 +21,13 @@ main: *[4 * MiB]u8,
 | 
			
		||||
shr_wram: *Wram,
 | 
			
		||||
wram: *[64 * KiB]u8,
 | 
			
		||||
vram: *Vram,
 | 
			
		||||
io: io.Io,
 | 
			
		||||
 | 
			
		||||
bios: *[16 * KiB]u8,
 | 
			
		||||
io: io.Io,
 | 
			
		||||
bios: Bios,
 | 
			
		||||
 | 
			
		||||
pub fn init(allocator: Allocator, scheduler: *Scheduler, ctx: SharedCtx) !@This() {
 | 
			
		||||
    const wram = try allocator.create([64 * KiB]u8);
 | 
			
		||||
    @memset(wram, 0);
 | 
			
		||||
    errdefer allocator.destroy(wram);
 | 
			
		||||
 | 
			
		||||
    const bios = try allocator.create([16 * KiB]u8);
 | 
			
		||||
    @memset(bios, 0);
 | 
			
		||||
    errdefer allocator.destroy(bios);
 | 
			
		||||
 | 
			
		||||
    return .{
 | 
			
		||||
        .main = ctx.main,
 | 
			
		||||
@@ -41,13 +37,13 @@ pub fn init(allocator: Allocator, scheduler: *Scheduler, ctx: SharedCtx) !@This(
 | 
			
		||||
        .scheduler = scheduler,
 | 
			
		||||
        .io = io.Io.init(ctx.io),
 | 
			
		||||
 | 
			
		||||
        .bios = bios,
 | 
			
		||||
        .bios = .{},
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
 | 
			
		||||
    allocator.destroy(self.wram);
 | 
			
		||||
    allocator.destroy(self.bios);
 | 
			
		||||
    self.bios.deinit(allocator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn reset(_: *@This()) void {}
 | 
			
		||||
@@ -73,7 +69,7 @@ fn _read(self: *@This(), comptime T: type, comptime mode: Mode, address: u32) T
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return switch (aligned_addr) {
 | 
			
		||||
        0x0000_0000...0x01FF_FFFF => readInt(T, self.bios[address & 0x3FFF ..][0..byte_count]),
 | 
			
		||||
        0x0000_0000...0x01FF_FFFF => self.bios.read(T, address),
 | 
			
		||||
        0x0200_0000...0x02FF_FFFF => readInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count]),
 | 
			
		||||
        0x0300_0000...0x037F_FFFF => switch (self.io.shr.wramcnt.mode.read()) {
 | 
			
		||||
            0b00 => readInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count]),
 | 
			
		||||
@@ -107,7 +103,7 @@ fn _write(self: *@This(), comptime T: type, comptime mode: Mode, address: u32, v
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (aligned_addr) {
 | 
			
		||||
        0x0000_0000...0x01FF_FFFF => log.err("tried to read from NDS7 BIOS: 0x{X:0>8}", .{aligned_addr}),
 | 
			
		||||
        0x0000_0000...0x01FF_FFFF => self.bios.write(T, address, value),
 | 
			
		||||
        0x0200_0000...0x02FF_FFFF => writeInt(T, self.main[aligned_addr & 0x003F_FFFF ..][0..byte_count], value),
 | 
			
		||||
        0x0300_0000...0x037F_FFFF => switch (self.io.shr.wramcnt.mode.read()) {
 | 
			
		||||
            0b00 => writeInt(T, self.wram[aligned_addr & 0x0000_FFFF ..][0..byte_count], value),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										49
									
								
								src/core/nds9/Bios.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/core/nds9/Bios.zig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
 | 
			
		||||
const log = std.log.scoped(.nds7_bios);
 | 
			
		||||
 | 
			
		||||
const KiB = 0x400;
 | 
			
		||||
 | 
			
		||||
const _len = 4 * KiB; // real size of the NDS9 BIOS
 | 
			
		||||
const len = 32 * KiB; // size allocated to NDS9 BIOS
 | 
			
		||||
 | 
			
		||||
buf: ?*align(4) [len]u8 = null,
 | 
			
		||||
 | 
			
		||||
// FIXME: Currently we dupe here, should we just take ownership?
 | 
			
		||||
pub fn load(self: *@This(), allocator: Allocator, data: []u8) !void {
 | 
			
		||||
    if (data.len != _len) {
 | 
			
		||||
        const acutal_size = @as(f32, @floatFromInt(data.len)) / KiB;
 | 
			
		||||
        log.warn("BIOS was {d:.2} KiB (should be {} KiB)", .{ acutal_size, len });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const buf = try allocator.alignedAlloc(u8, 4, len);
 | 
			
		||||
    @memcpy(buf[0..data.len], data);
 | 
			
		||||
    @memset(buf[data.len..], 0);
 | 
			
		||||
 | 
			
		||||
    self.* = .{ .buf = buf[0..len] };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn deinit(self: @This(), allocator: Allocator) void {
 | 
			
		||||
    if (self.buf) |ptr| allocator.destroy(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Note: Parts of 16MiB addrspace that aren't mapped to BIOS are typically undefined
 | 
			
		||||
pub fn read(self: *const @This(), comptime T: type, address: u32) T {
 | 
			
		||||
    const readInt = std.mem.readIntLittle;
 | 
			
		||||
    const byte_count = @divExact(@typeInfo(T).Int.bits, 8);
 | 
			
		||||
 | 
			
		||||
    // if (address >= len) return 0x0000_0000; // TODO: What is undefined actually?
 | 
			
		||||
 | 
			
		||||
    const ptr = self.buf orelse {
 | 
			
		||||
        log.err("read(T: {}, address: 0x{X:0>8}) from BIOS but none was found!", .{ T, address });
 | 
			
		||||
        @panic("TODO: ability to load in NDS9 BIOS just-in-time");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return readInt(T, ptr[address & (len - 1) ..][0..byte_count]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn write(_: *const @This(), comptime T: type, address: u32, value: T) void {
 | 
			
		||||
    log.err("write(T: {}, address: 0x{X:0>8}, value: 0x{X:}) but we're in the BIOS!", .{ T, address, value });
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@ const Ppu = @import("../ppu.zig").Ppu;
 | 
			
		||||
const Scheduler = @import("../Scheduler.zig");
 | 
			
		||||
const SharedCtx = @import("../emu.zig").SharedCtx;
 | 
			
		||||
const Wram = @import("../emu.zig").Wram;
 | 
			
		||||
const Bios = @import("Bios.zig");
 | 
			
		||||
const forceAlign = @import("../emu.zig").forceAlign;
 | 
			
		||||
 | 
			
		||||
const Allocator = std.mem.Allocator;
 | 
			
		||||
@@ -17,21 +18,16 @@ const log = std.log.scoped(.nds9_bus);
 | 
			
		||||
 | 
			
		||||
main: *[4 * MiB]u8,
 | 
			
		||||
wram: *Wram,
 | 
			
		||||
scheduler: *Scheduler,
 | 
			
		||||
 | 
			
		||||
io: io.Io,
 | 
			
		||||
ppu: Ppu,
 | 
			
		||||
 | 
			
		||||
bios: *[32 * KiB]u8,
 | 
			
		||||
 | 
			
		||||
scheduler: *Scheduler,
 | 
			
		||||
bios: Bios,
 | 
			
		||||
 | 
			
		||||
pub fn init(allocator: Allocator, scheduler: *Scheduler, ctx: SharedCtx) !@This() {
 | 
			
		||||
    const dots_per_cycle = 3; // ARM946E-S runs twice as fast as the ARM7TDMI
 | 
			
		||||
    scheduler.push(.{ .nds9 = .draw }, 256 * dots_per_cycle);
 | 
			
		||||
 | 
			
		||||
    const bios = try allocator.create([32 * KiB]u8);
 | 
			
		||||
    @memset(bios, 0);
 | 
			
		||||
    errdefer allocator.destroy(bios);
 | 
			
		||||
 | 
			
		||||
    return .{
 | 
			
		||||
        .main = ctx.main,
 | 
			
		||||
        .wram = ctx.wram,
 | 
			
		||||
@@ -39,13 +35,13 @@ pub fn init(allocator: Allocator, scheduler: *Scheduler, ctx: SharedCtx) !@This(
 | 
			
		||||
        .scheduler = scheduler,
 | 
			
		||||
        .io = io.Io.init(ctx.io),
 | 
			
		||||
 | 
			
		||||
        .bios = bios,
 | 
			
		||||
        .bios = .{},
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn deinit(self: *@This(), allocator: Allocator) void {
 | 
			
		||||
    self.ppu.deinit(allocator);
 | 
			
		||||
    allocator.destroy(self.bios);
 | 
			
		||||
    self.bios.deinit(allocator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn reset(_: *@This()) void {
 | 
			
		||||
@@ -77,7 +73,7 @@ fn _read(self: *@This(), comptime T: type, comptime mode: Mode, address: u32) T
 | 
			
		||||
        0x0300_0000...0x03FF_FFFF => self.wram.read(T, .nds9, aligned_addr),
 | 
			
		||||
        0x0400_0000...0x04FF_FFFF => io.read(self, T, aligned_addr),
 | 
			
		||||
        0x0600_0000...0x06FF_FFFF => self.ppu.vram.read(T, .nds9, aligned_addr),
 | 
			
		||||
        0xFFFF_0000...0xFFFF_FFFF => readInt(T, self.bios[address & 0x0000_7FFF ..][0..byte_count]),
 | 
			
		||||
        0xFFFF_0000...0xFFFF_FFFF => self.bios.read(T, address),
 | 
			
		||||
        else => warn("unexpected read: 0x{x:0>8} -> {}", .{ aligned_addr, T }),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -107,7 +103,7 @@ fn _write(self: *@This(), comptime T: type, comptime mode: Mode, address: u32, v
 | 
			
		||||
        0x0300_0000...0x03FF_FFFF => self.wram.write(T, .nds9, aligned_addr, value),
 | 
			
		||||
        0x0400_0000...0x04FF_FFFF => io.write(self, T, aligned_addr, value),
 | 
			
		||||
        0x0600_0000...0x06FF_FFFF => self.ppu.vram.write(T, .nds9, aligned_addr, value),
 | 
			
		||||
        0xFFFF_0000...0xFFFF_FFFF => log.err("tried to read from NDS9 BIOS: 0x{X:0>8}", .{aligned_addr}),
 | 
			
		||||
        0xFFFF_0000...0xFFFF_FFFF => self.bios.write(T, address, value),
 | 
			
		||||
        else => log.warn("unexpected write: 0x{X:}{} -> 0x{X:0>8}", .{ value, T, aligned_addr }),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user