Compare commits

..

4 Commits

7 changed files with 87 additions and 69 deletions

View File

@ -9,6 +9,7 @@ const Ppu = @import("ppu.zig").Ppu;
const Scheduler = @import("scheduler.zig").Scheduler;
const Allocator = std.mem.Allocator;
const log = std.log.scoped(.Bus);
const Self = @This();
pak: GamePak,
@ -56,7 +57,7 @@ pub fn read32(self: *const Self, addr: u32) u32 {
0x0C00_0000...0x0DFF_FFFF => self.pak.get32(addr - 0x0C00_0000),
else => {
std.log.warn("[Bus:32] ZBA tried to read from 0x{X:}", .{addr});
log.warn("32-bit read from 0x{X:0>8}", .{addr});
return 0x0000_0000;
},
};
@ -76,7 +77,7 @@ pub fn write32(self: *Self, addr: u32, word: u32) void {
0x0600_0000...0x0601_7FFF => self.ppu.vram.set32(addr - 0x0600_0000, word),
0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:32] wrote 0x{X:} to 0x{X:} in OAM", .{ word, addr }),
else => std.log.warn("[Bus:32] ZBA tried to write 0x{X:} to 0x{X:}", .{ word, addr }),
else => log.warn("32-bit write of 0x{X:0>8} to 0x{X:0>8}", .{ word, addr }),
}
}
@ -99,7 +100,7 @@ pub fn read16(self: *const Self, addr: u32) u16 {
0x0C00_0000...0x0DFF_FFFF => self.pak.get16(addr - 0x0C00_0000),
else => {
std.log.warn("[Bus:16] ZBA tried to read from 0x{X:}", .{addr});
log.warn("16-bit read from 0x{X:0>8}", .{addr});
return 0x0000;
},
};
@ -118,7 +119,7 @@ pub fn write16(self: *Self, addr: u32, halfword: u16) void {
0x0600_0000...0x0601_7FFF => self.ppu.vram.set16(addr - 0x0600_0000, halfword),
0x0700_0000...0x0700_03FF => std.debug.panic("[Bus:16] write 0x{X:} to 0x{X:} in OAM", .{ halfword, addr }),
else => std.log.warn("[Bus:16] ZBA tried to write 0x{X:} to 0x{X:}", .{ halfword, addr }),
else => log.warn("16-bit write of 0x{X:0>4} to 0x{X:0>8}", .{ halfword, addr }),
}
}
@ -142,7 +143,7 @@ pub fn read8(self: *const Self, addr: u32) u8 {
0x0E00_0000...0x0E00_FFFF => std.debug.panic("[Bus:8] read from 0x{X:} in Game Pak SRAM", .{addr}),
else => {
std.log.warn("[Bus:8] ZBA tried to read from 0x{X:}", .{addr});
log.warn("8-bit read from 0x{X:0>8}", .{addr});
return 0x00;
},
};
@ -157,6 +158,6 @@ pub fn write8(self: *Self, addr: u32, byte: u8) void {
// External Memory (Game Pak)
0x0E00_0000...0x0E00_FFFF => std.debug.panic("[Bus:8] write 0x{X:} to 0x{X:} in Game Pak SRAM", .{ byte, addr }),
else => std.log.warn("[Bus:8] ZBA tried to write 0x{X:} to 0x{X:}", .{ byte, addr }),
else => log.warn("8-bit write of 0x{X:0>2} to 0x{X:0>8}", .{ byte, addr }),
}
}

View File

@ -97,8 +97,8 @@ pub const Arm7tdmi = struct {
self.binary_log = is_binary;
}
inline fn bankedIdx(mode: Mode) usize {
return switch (mode) {
inline fn bankedIdx(mode: Mode, kind: BankedKind) usize {
const idx: usize = switch (mode) {
.User, .System => 0,
.Supervisor => 1,
.Abort => 2,
@ -106,9 +106,11 @@ pub const Arm7tdmi = struct {
.Irq => 4,
.Fiq => 5,
};
return (idx * 2) + if (kind == .R14) @as(usize, 1) else 0;
}
inline fn spsrIdx(mode: Mode) usize {
inline fn bankedSpsrIndex(mode: Mode) usize {
return switch (mode) {
.Supervisor => 0,
.Abort => 1,
@ -119,6 +121,10 @@ pub const Arm7tdmi = struct {
};
}
inline fn bankedFiqIdx(i: usize, mode: Mode) usize {
return (i * 2) + if (mode == .Fiq) @as(usize, 1) else 0;
}
pub inline fn hasSPSR(self: *const Self) bool {
const mode = getModeChecked(self, self.cpsr.mode.read());
return switch (mode) {
@ -147,84 +153,77 @@ pub const Arm7tdmi = struct {
pub fn setUserModeRegister(self: *Self, idx: usize, value: u32) void {
const current = getModeChecked(self, self.cpsr.mode.read());
if (idx < 8) {
self.r[idx] = value;
} else if (idx < 13) {
if (current == .Fiq) {
const user_offset: usize = 0;
self.banked_fiq[(idx - 8) * 2 + user_offset] = value;
} else self.r[idx] = value;
} else if (idx < 15) {
switch (current) {
switch (idx) {
8...12 => {
if (current == .Fiq) {
self.banked_fiq[bankedFiqIdx(idx - 8, .User)] = value;
} else self.r[idx] = value;
},
13, 14 => switch (current) {
.User, .System => self.r[idx] = value,
else => {
self.banked_r[bankedIdx(.User) * 2 + (idx - 13)] = value;
const kind = std.meta.intToEnum(BankedKind, idx - 13) catch unreachable;
self.banked_r[bankedIdx(.User, kind)] = value;
},
}
} else self.r[idx] = value;
},
else => self.r[idx] = value, // R0 -> R7 and R15
}
}
pub fn getUserModeRegister(self: *Self, idx: usize) u32 {
const current = getModeChecked(self, self.cpsr.mode.read());
var result: u32 = undefined;
if (idx < 8) {
result = self.r[idx];
} else if (idx < 13) {
if (current == .Fiq) {
const user_offset: usize = 0;
result = self.banked_fiq[(idx - 8) * 2 + user_offset];
} else result = self.r[idx];
} else if (idx < 15) {
switch (current) {
.User, .System => result = self.r[idx],
else => {
result = self.banked_r[bankedIdx(.User) * 2 + (idx - 13)];
return switch (idx) {
8...12 => if (current == .Fiq) self.banked_fiq[bankedFiqIdx(idx - 8, .User)] else self.r[idx],
13, 14 => switch (current) {
.User, .System => self.r[idx],
else => blk: {
const kind = std.meta.intToEnum(BankedKind, idx - 13) catch unreachable;
break :blk self.banked_r[bankedIdx(.User, kind)];
},
}
} else result = self.r[idx];
return result;
},
else => self.r[idx], // R0 -> R7 and R15
};
}
pub fn changeMode(self: *Self, next: Mode) void {
const now = getModeChecked(self, self.cpsr.mode.read());
// Bank R8 -> r12
var r: usize = 8;
while (r <= 12) : (r += 1) {
self.banked_fiq[(r - 8) * 2 + if (now == .Fiq) @as(usize, 1) else 0] = self.r[r];
var i: usize = 0;
while (i < 5) : (i += 1) {
self.banked_fiq[bankedFiqIdx(i, now)] = self.r[8 + i];
}
// Bank r13, r14, SPSR
switch (now) {
.User, .System => {
self.banked_r[bankedIdx(now) * 2 + 0] = self.r[13];
self.banked_r[bankedIdx(now) * 2 + 1] = self.r[14];
self.banked_r[bankedIdx(now, .R13)] = self.r[13];
self.banked_r[bankedIdx(now, .R14)] = self.r[14];
},
else => {
self.banked_r[bankedIdx(now) * 2 + 0] = self.r[13];
self.banked_r[bankedIdx(now) * 2 + 1] = self.r[14];
self.banked_spsr[spsrIdx(now)] = self.spsr;
self.banked_r[bankedIdx(now, .R13)] = self.r[13];
self.banked_r[bankedIdx(now, .R14)] = self.r[14];
self.banked_spsr[bankedSpsrIndex(now)] = self.spsr;
},
}
// Grab R8 -> R12
r = 8;
while (r <= 12) : (r += 1) {
self.r[r] = self.banked_fiq[(r - 8) * 2 + if (next == .Fiq) @as(usize, 1) else 0];
i = 0;
while (i < 5) : (i += 1) {
self.r[8 + i] = self.banked_fiq[bankedFiqIdx(i, next)];
}
// Grab r13, r14, SPSR
switch (next) {
.User, .System => {
self.r[13] = self.banked_r[bankedIdx(next) * 2 + 0];
self.r[14] = self.banked_r[bankedIdx(next) * 2 + 1];
self.r[13] = self.banked_r[bankedIdx(next, .R13)];
self.r[14] = self.banked_r[bankedIdx(next, .R14)];
},
else => {
self.r[13] = self.banked_r[bankedIdx(next) * 2 + 0];
self.r[14] = self.banked_r[bankedIdx(next) * 2 + 1];
self.spsr = self.banked_spsr[spsrIdx(next)];
self.r[13] = self.banked_r[bankedIdx(next, .R13)];
self.r[14] = self.banked_r[bankedIdx(next, .R14)];
self.spsr = self.banked_spsr[bankedSpsrIndex(next)];
},
}
@ -232,16 +231,15 @@ pub const Arm7tdmi = struct {
}
pub fn fastBoot(self: *Self) void {
self.r = std.mem.zeroes([16]u32);
self.r[0] = 0x08000000;
self.r[1] = 0x000000EA;
// GPRs 2 -> 12 *should* already be 0 initialized
self.r[13] = 0x0300_7F00;
self.r[14] = 0x0000_0000;
self.r[15] = 0x0800_0000;
// Set r13_irq and r14_svc to their respective values
self.banked_r[bankedIdx(.Irq) * 2 + 0] = 0x0300_7FA0;
self.banked_r[bankedIdx(.Supervisor) * 2 + 0] = 0x0300_7FE0;
self.banked_r[bankedIdx(.Irq, .R13)] = 0x0300_7FA0;
self.banked_r[bankedIdx(.Supervisor, .R13)] = 0x0300_7FE0;
self.cpsr.raw = 0x6000001F;
}
@ -496,7 +494,7 @@ fn thumbPopulate() [0x400]ThumbInstrFn {
},
0b001 => blk: {
const L = i >> 5 & 1 == 1;
const rd = i >> 2 & 0x3;
const rd = i >> 2 & 0x7;
break :blk format11(L, rd);
},
0b010 => blk: {
@ -632,6 +630,11 @@ const Mode = enum(u5) {
System = 0b11111,
};
const BankedKind = enum(u1) {
R13 = 0,
R14,
};
fn getMode(bits: u5) ?Mode {
return std.meta.intToEnum(Mode, bits) catch null;
}

View File

@ -5,6 +5,8 @@ const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
const PSR = @import("../../cpu.zig").PSR;
const log = std.log.scoped(.PsrTransfer);
pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
@ -13,7 +15,7 @@ pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrF
// MRS
const rd = opcode >> 12 & 0xF;
if (R and !cpu.hasSPSR()) std.log.warn("[CPU/PSR Transfer] Tried to read SPSR from User/System Mode", .{});
if (R and !cpu.hasSPSR()) log.warn("Tried to read SPSR from User/System Mode", .{});
cpu.r[rd] = if (R) cpu.spsr.raw else cpu.cpsr.raw;
},
0b10 => {
@ -22,7 +24,7 @@ pub fn psrTransfer(comptime I: bool, comptime R: bool, comptime kind: u2) InstrF
const rm_idx = opcode & 0xF;
const right = if (I) std.math.rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) << 1) else cpu.r[rm_idx];
if (R and !cpu.hasSPSR()) std.log.warn("[CPU/PSR Transfer] Tried to write to SPSR User/System Mode", .{});
if (R and !cpu.hasSPSR()) log.warn("Tried to write to SPSR in User/System Mode", .{});
if (R) {
if (cpu.isPrivileged()) cpu.spsr.raw = fieldMask(&cpu.spsr, field_mask, right);

View File

@ -5,12 +5,12 @@ const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
pub fn format14(comptime L: bool, comptime R: bool) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, bus: *Bus, opcode: u16) void {
const count = countRlist(opcode);
const start = cpu.r[13] - if (!L) 4 * (@boolToInt(R) + count) else 0;
const count = @boolToInt(R) + countRlist(opcode);
const start = cpu.r[13] - if (!L) count * 4 else 0;
var end = cpu.r[13];
if (L) {
end += 4 * (@boolToInt(R) + count);
end += count * 4;
} else {
end -= 4;
}
@ -40,7 +40,7 @@ pub fn format14(comptime L: bool, comptime R: bool) InstrFn {
address += 4;
}
cpu.r[13] = if (L) end else cpu.r[13] - 4 * (@boolToInt(R) + count);
cpu.r[13] = if (L) end else start;
}
}.inner;
}

View File

@ -1,3 +1,5 @@
const std = @import("std");
const Bus = @import("../../Bus.zig");
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
const InstrFn = @import("../../cpu.zig").ThumbInstrFn;
@ -8,6 +10,8 @@ const sub = @import("../arm/data_processing.zig").sub;
const cmp = @import("../arm/data_processing.zig").cmp;
const setLogicOpFlags = @import("../arm/data_processing.zig").setLogicOpFlags;
const log = std.log.scoped(.Thumb1);
pub fn format1(comptime op: u2, comptime offset: u5) InstrFn {
return struct {
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u16) void {
@ -41,7 +45,10 @@ pub fn format1(comptime op: u2, comptime offset: u5) InstrFn {
break :blk shifter.arithmeticRight(true, &cpu.cpsr, cpu.r[rs], offset);
}
},
else => cpu.panic("[CPU|THUMB|Fmt1] {} is an invalid op", .{op}),
else => {
log.err("0b{b:0>2} is not a valid op", .{op});
// TODO: Should we panic here?
},
};
// Equivalent to an ARM MOVS

View File

@ -15,7 +15,11 @@ pub fn format5(comptime op: u2, comptime h1: u1, comptime h2: u1) InstrFn {
const dst = if (dst_idx == 0xF) (cpu.r[dst_idx] + 2) & 0xFFFF_FFFE else cpu.r[dst_idx];
switch (op) {
0b00 => cpu.r[dst_idx] = add(false, cpu, dst, src) & if (dst_idx == 0xF) 0xFFFF_FFFC else @as(u32, 0xFFF_FFFF), // ADD
0b00 => {
// ADD
const sum = add(false, cpu, dst, src);
cpu.r[dst_idx] = if (dst_idx == 0xF) sum & 0xFFFF_FFFC else sum;
},
0b01 => cmp(cpu, dst, src), // CMP
0b10 => {
// MOV

View File

@ -6,6 +6,7 @@ const Arm7tdmi = @import("cpu.zig").Arm7tdmi;
const Order = std.math.Order;
const PriorityQueue = std.PriorityQueue;
const Allocator = std.mem.Allocator;
const log = std.log.scoped(.Scheduler);
pub const Scheduler = struct {
const Self = @This();
@ -29,7 +30,7 @@ pub const Scheduler = struct {
if (should_handle) {
const event = self.queue.remove();
// std.log.info("[Scheduler] Handle {} at {} ticks", .{ event.kind, self.tick });
// log.debug("Handle {} @ tick = {}", .{ event.kind, self.tick });
switch (event.kind) {
.HeatDeath => {