Compare commits
No commits in common. "905c4448d08853bc4776f90dfe844ed13da34eee" and "8e1a539e70bd3ba2c12134e526680eae547d61bd" have entirely different histories.
905c4448d0
...
8e1a539e70
|
@ -107,7 +107,7 @@ pub fn deinit(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fillReadTable(bus: *Self, table: *[table_len]?*const anyopaque) void {
|
fn fillReadTable(bus: *Self, table: *[table_len]?*const anyopaque) void {
|
||||||
const vramMirror = @import("ppu/Vram.zig").mirror;
|
const vramMirror = @import("ppu.zig").Vram.mirror;
|
||||||
|
|
||||||
for (table) |*ptr, i| {
|
for (table) |*ptr, i| {
|
||||||
const addr = page_size * i;
|
const addr = page_size * i;
|
||||||
|
@ -134,7 +134,7 @@ fn fillReadTable(bus: *Self, table: *[table_len]?*const anyopaque) void {
|
||||||
|
|
||||||
fn fillWriteTable(comptime T: type, bus: *Self, table: *[table_len]?*const anyopaque) void {
|
fn fillWriteTable(comptime T: type, bus: *Self, table: *[table_len]?*const anyopaque) void {
|
||||||
comptime std.debug.assert(T == u32 or T == u16 or T == u8);
|
comptime std.debug.assert(T == u32 or T == u16 or T == u8);
|
||||||
const vramMirror = @import("ppu/Vram.zig").mirror;
|
const vramMirror = @import("ppu.zig").Vram.mirror;
|
||||||
|
|
||||||
for (table) |*ptr, i| {
|
for (table) |*ptr, i| {
|
||||||
const addr = page_size * i;
|
const addr = page_size * i;
|
||||||
|
|
|
@ -338,7 +338,7 @@ fn DmaController(comptime id: u2) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn onBlanking(bus: *Bus, comptime kind: DmaKind) void {
|
pub fn pollDmaOnBlank(bus: *Bus, comptime kind: DmaKind) void {
|
||||||
comptime var i: usize = 0;
|
comptime var i: usize = 0;
|
||||||
inline while (i < 4) : (i += 1) {
|
inline while (i < 4) : (i += 1) {
|
||||||
bus.dma[i].poll(kind);
|
bus.dma[i].poll(kind);
|
||||||
|
|
|
@ -449,8 +449,6 @@ pub const BldY = extern union {
|
||||||
raw: u16,
|
raw: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8WriteKind = enum { Hi, Lo };
|
|
||||||
|
|
||||||
/// Write-only
|
/// Write-only
|
||||||
pub const WinH = extern union {
|
pub const WinH = extern union {
|
||||||
x2: Bitfield(u16, 0, 8),
|
x2: Bitfield(u16, 0, 8),
|
||||||
|
@ -460,8 +458,6 @@ pub const WinH = extern union {
|
||||||
|
|
||||||
/// Write-only
|
/// Write-only
|
||||||
pub const WinV = extern union {
|
pub const WinV = extern union {
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
y2: Bitfield(u16, 0, 8),
|
y2: Bitfield(u16, 0, 8),
|
||||||
y1: Bitfield(u16, 8, 8),
|
y1: Bitfield(u16, 8, 8),
|
||||||
raw: u16,
|
raw: u16,
|
||||||
|
@ -470,20 +466,20 @@ pub const WinV = extern union {
|
||||||
pub const WinIn = extern union {
|
pub const WinIn = extern union {
|
||||||
w0_bg: Bitfield(u16, 0, 4),
|
w0_bg: Bitfield(u16, 0, 4),
|
||||||
w0_obj: Bit(u16, 4),
|
w0_obj: Bit(u16, 4),
|
||||||
w0_bld: Bit(u16, 5),
|
w0_colour: Bit(u16, 5),
|
||||||
w1_bg: Bitfield(u16, 8, 4),
|
w1_bg: Bitfield(u16, 8, 4),
|
||||||
w1_obj: Bit(u16, 12),
|
w1_obj: Bit(u16, 12),
|
||||||
w1_bld: Bit(u16, 13),
|
w1_colour: Bit(u16, 13),
|
||||||
raw: u16,
|
raw: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const WinOut = extern union {
|
pub const WinOut = extern union {
|
||||||
out_bg: Bitfield(u16, 0, 4),
|
out_bg: Bitfield(u16, 0, 4),
|
||||||
out_obj: Bit(u16, 4),
|
out_obj: Bit(u16, 4),
|
||||||
out_bld: Bit(u16, 5),
|
out_colour: Bit(u16, 5),
|
||||||
obj_bg: Bitfield(u16, 8, 4),
|
obj_bg: Bitfield(u16, 8, 4),
|
||||||
obj_obj: Bit(u16, 12),
|
obj_obj: Bit(u16, 12),
|
||||||
obj_bld: Bit(u16, 13),
|
obj_colour: Bit(u16, 13),
|
||||||
raw: u16,
|
raw: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
886
src/core/ppu.zig
886
src/core/ppu.zig
File diff suppressed because it is too large
Load Diff
|
@ -1,40 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const buf_len = 0x400;
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
buf: []u8,
|
|
||||||
allocator: Allocator,
|
|
||||||
|
|
||||||
pub fn read(self: *const Self, comptime T: type, address: usize) T {
|
|
||||||
const addr = address & 0x3FF;
|
|
||||||
|
|
||||||
return switch (T) {
|
|
||||||
u32, u16, u8 => std.mem.readIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)]),
|
|
||||||
else => @compileError("OAM: Unsupported read width"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(self: *Self, comptime T: type, address: usize, value: T) void {
|
|
||||||
const addr = address & 0x3FF;
|
|
||||||
|
|
||||||
switch (T) {
|
|
||||||
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)], value),
|
|
||||||
u8 => return, // 8-bit writes are explicitly ignored
|
|
||||||
else => @compileError("OAM: Unsupported write width"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !Self {
|
|
||||||
const buf = try allocator.alloc(u8, buf_len);
|
|
||||||
std.mem.set(u8, buf, 0);
|
|
||||||
|
|
||||||
return Self{ .buf = buf, .allocator = allocator };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.allocator.free(self.buf);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const buf_len = 0x400;
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
buf: []u8,
|
|
||||||
allocator: Allocator,
|
|
||||||
|
|
||||||
pub fn read(self: *const Self, comptime T: type, address: usize) T {
|
|
||||||
const addr = address & 0x3FF;
|
|
||||||
|
|
||||||
return switch (T) {
|
|
||||||
u32, u16, u8 => std.mem.readIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)]),
|
|
||||||
else => @compileError("PALRAM: Unsupported read width"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(self: *Self, comptime T: type, address: usize, value: T) void {
|
|
||||||
const addr = address & 0x3FF;
|
|
||||||
|
|
||||||
switch (T) {
|
|
||||||
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)], value),
|
|
||||||
u8 => {
|
|
||||||
const align_addr = addr & ~@as(u32, 1); // Aligned to Halfword boundary
|
|
||||||
std.mem.writeIntSliceLittle(u16, self.buf[align_addr..][0..@sizeOf(u16)], @as(u16, value) * 0x101);
|
|
||||||
},
|
|
||||||
else => @compileError("PALRAM: Unsupported write width"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !Self {
|
|
||||||
const buf = try allocator.alloc(u8, buf_len);
|
|
||||||
std.mem.set(u8, buf, 0);
|
|
||||||
|
|
||||||
return Self{ .buf = buf, .allocator = allocator };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.allocator.free(self.buf);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn backdrop(self: *const Self) u16 {
|
|
||||||
return std.mem.readIntNative(u16, self.buf[0..2]);
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const io = @import("../bus/io.zig");
|
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const buf_len = 0x18000;
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
buf: []u8,
|
|
||||||
allocator: Allocator,
|
|
||||||
|
|
||||||
pub fn read(self: *const Self, comptime T: type, address: usize) T {
|
|
||||||
const addr = Self.mirror(address);
|
|
||||||
|
|
||||||
return switch (T) {
|
|
||||||
u32, u16, u8 => std.mem.readIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)]),
|
|
||||||
else => @compileError("VRAM: Unsupported read width"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(self: *Self, comptime T: type, dispcnt: io.DisplayControl, address: usize, value: T) void {
|
|
||||||
const mode: u3 = dispcnt.bg_mode.read();
|
|
||||||
const idx = Self.mirror(address);
|
|
||||||
|
|
||||||
switch (T) {
|
|
||||||
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[idx..][0..@sizeOf(T)], value),
|
|
||||||
u8 => {
|
|
||||||
// Ignore write if it falls within the boundaries of OBJ VRAM
|
|
||||||
switch (mode) {
|
|
||||||
0, 1, 2 => if (0x0001_0000 <= idx) return,
|
|
||||||
else => if (0x0001_4000 <= idx) return,
|
|
||||||
}
|
|
||||||
|
|
||||||
const align_idx = idx & ~@as(u32, 1); // Aligned to a halfword boundary
|
|
||||||
std.mem.writeIntSliceLittle(u16, self.buf[align_idx..][0..@sizeOf(u16)], @as(u16, value) * 0x101);
|
|
||||||
},
|
|
||||||
else => @compileError("VRAM: Unsupported write width"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !Self {
|
|
||||||
const buf = try allocator.alloc(u8, buf_len);
|
|
||||||
std.mem.set(u8, buf, 0);
|
|
||||||
|
|
||||||
return Self{ .buf = buf, .allocator = allocator };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.allocator.free(self.buf);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mirror(address: usize) usize {
|
|
||||||
// Mirrored in steps of 128K (64K + 32K + 32K) (abcc)
|
|
||||||
const addr = address & 0x1FFFF;
|
|
||||||
|
|
||||||
// If the address is within 96K we don't do anything,
|
|
||||||
// otherwise we want to mirror the last 32K (addresses between 64K and 96K)
|
|
||||||
return if (addr < buf_len) addr else 0x10000 + (addr & 0x7FFF);
|
|
||||||
}
|
|
46
src/util.zig
46
src/util.zig
|
@ -5,8 +5,6 @@ const config = @import("config.zig");
|
||||||
const Log2Int = std.math.Log2Int;
|
const Log2Int = std.math.Log2Int;
|
||||||
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
const Arm7tdmi = @import("core/cpu.zig").Arm7tdmi;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
// Sign-Extend value of type `T` to type `U`
|
// Sign-Extend value of type `T` to type `U`
|
||||||
pub fn sext(comptime T: type, comptime U: type, value: T) T {
|
pub fn sext(comptime T: type, comptime U: type, value: T) T {
|
||||||
// U must have less bits than T
|
// U must have less bits than T
|
||||||
|
@ -125,7 +123,6 @@ pub const io = struct {
|
||||||
|
|
||||||
pub const Logger = struct {
|
pub const Logger = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
const FmtArgTuple = std.meta.Tuple(&.{ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32 });
|
|
||||||
|
|
||||||
buf: std.io.BufferedWriter(4096 << 2, std.fs.File.Writer),
|
buf: std.io.BufferedWriter(4096 << 2, std.fs.File.Writer),
|
||||||
|
|
||||||
|
@ -184,6 +181,8 @@ pub const Logger = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FmtArgTuple = struct { u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32 };
|
||||||
|
|
||||||
pub const audio = struct {
|
pub const audio = struct {
|
||||||
const _io = @import("core/bus/io.zig");
|
const _io = @import("core/bus/io.zig");
|
||||||
|
|
||||||
|
@ -276,44 +275,3 @@ fn HalfInt(comptime T: type) type {
|
||||||
|
|
||||||
return std.meta.Int(type_info.Int.signedness, type_info.Int.bits >> 1);
|
return std.meta.Int(type_info.Int.signedness, type_info.Int.bits >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Double Buffering Implementation
|
|
||||||
pub const FrameBuffer = struct {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
layers: [2][]u8,
|
|
||||||
buf: []u8,
|
|
||||||
current: u1,
|
|
||||||
|
|
||||||
allocator: Allocator,
|
|
||||||
|
|
||||||
// TODO: Rename
|
|
||||||
const Device = enum { Emulator, Renderer };
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, comptime len: comptime_int) !Self {
|
|
||||||
const buf = try allocator.alloc(u8, len * 2);
|
|
||||||
std.mem.set(u8, buf, 0);
|
|
||||||
|
|
||||||
return .{
|
|
||||||
// Front and Back Framebuffers
|
|
||||||
.layers = [_][]u8{ buf[0..][0..len], buf[len..][0..len] },
|
|
||||||
.buf = buf,
|
|
||||||
.current = 0,
|
|
||||||
|
|
||||||
.allocator = allocator,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
|
||||||
self.allocator.free(self.buf);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn swap(self: *Self) void {
|
|
||||||
self.current = ~self.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(self: *Self, comptime dev: Device) []u8 {
|
|
||||||
return self.layers[if (dev == .Emulator) self.current else ~self.current];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue