Compare commits
3 Commits
887bd89668
...
926b6d4dd4
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | 926b6d4dd4 | |
Rekai Nyangadzayi Musuka | d798aea6ea | |
Rekai Nyangadzayi Musuka | 5d37c212e2 |
|
@ -182,10 +182,12 @@ fn DmaController(comptime id: u2) type {
|
||||||
const transfer_type = is_fifo or self.cnt.transfer_type.read();
|
const transfer_type = is_fifo or self.cnt.transfer_type.read();
|
||||||
const offset: u32 = if (transfer_type) @sizeOf(u32) else @sizeOf(u16);
|
const offset: u32 = if (transfer_type) @sizeOf(u32) else @sizeOf(u16);
|
||||||
|
|
||||||
|
const mask = if (transfer_type) ~@as(u32, 3) else ~@as(u32, 1);
|
||||||
|
|
||||||
if (transfer_type) {
|
if (transfer_type) {
|
||||||
cpu.bus.write(u32, self._dad, cpu.bus.read(u32, self._sad));
|
cpu.bus.write(u32, self._dad & mask, cpu.bus.read(u32, self._sad & mask));
|
||||||
} else {
|
} else {
|
||||||
cpu.bus.write(u16, self._dad, cpu.bus.read(u16, self._sad));
|
cpu.bus.write(u16, self._dad & mask, cpu.bus.read(u16, self._sad & mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sad_adj) {
|
switch (sad_adj) {
|
||||||
|
|
35
src/cpu.zig
35
src/cpu.zig
|
@ -60,6 +60,7 @@ pub const Arm7tdmi = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
r: [16]u32,
|
r: [16]u32,
|
||||||
|
pipe: [2]u32,
|
||||||
sched: *Scheduler,
|
sched: *Scheduler,
|
||||||
bus: Bus,
|
bus: Bus,
|
||||||
cpsr: PSR,
|
cpsr: PSR,
|
||||||
|
@ -82,6 +83,7 @@ pub const Arm7tdmi = struct {
|
||||||
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self {
|
pub fn init(alloc: Allocator, sched: *Scheduler, paths: FilePaths) !Self {
|
||||||
return Self{
|
return Self{
|
||||||
.r = [_]u32{0x00} ** 16,
|
.r = [_]u32{0x00} ** 16,
|
||||||
|
.pipe = [_]u32{0xF000_0000} ** 2,
|
||||||
.sched = sched,
|
.sched = sched,
|
||||||
.bus = try Bus.init(alloc, sched, paths),
|
.bus = try Bus.init(alloc, sched, paths),
|
||||||
.cpsr = .{ .raw = 0x0000_001F },
|
.cpsr = .{ .raw = 0x0000_001F },
|
||||||
|
@ -256,14 +258,14 @@ pub const Arm7tdmi = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(self: *Self) void {
|
pub fn step(self: *Self) void {
|
||||||
if (self.cpsr.t.read()) {
|
const opcode = self.pipe[0];
|
||||||
const opcode = self.fetch(u16);
|
|
||||||
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
||||||
|
|
||||||
thumb_lut[thumbIdx(opcode)](self, &self.bus, opcode);
|
if (self.cpsr.t.read()) {
|
||||||
|
self.stepPipeline(u16);
|
||||||
|
thumb_lut[thumbIdx(@truncate(u16, opcode))](self, &self.bus, @truncate(u16, opcode));
|
||||||
} else {
|
} else {
|
||||||
const opcode = self.fetch(u32);
|
self.stepPipeline(u32);
|
||||||
if (enable_logging) if (self.log_file) |file| self.debug_log(file, opcode);
|
|
||||||
|
|
||||||
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
if (checkCond(self.cpsr, @truncate(u4, opcode >> 28))) {
|
||||||
arm_lut[armIdx(opcode)](self, &self.bus, opcode);
|
arm_lut[armIdx(opcode)](self, &self.bus, opcode);
|
||||||
|
@ -326,6 +328,27 @@ pub const Arm7tdmi = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fn stepPipeline(self: *Self, comptime T: type) void {
|
||||||
|
self.pipe[0] = self.pipe[1]; // Decoded Instr will be executed next
|
||||||
|
self.pipe[1] = self.fetch(T); // Fetch new opcode to be decoded next
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reloadPipeline(self: *Self, comptime T: type) void {
|
||||||
|
switch (T) {
|
||||||
|
u32 => {
|
||||||
|
self.pipe[0] = self.bus.read(u32, self.r[15]);
|
||||||
|
self.pipe[1] = self.bus.read(u32, self.r[15] + 4);
|
||||||
|
self.r[15] += 8;
|
||||||
|
},
|
||||||
|
u16 => {
|
||||||
|
self.pipe[0] = self.bus.read(u32, self.r[15]);
|
||||||
|
self.pipe[1] = self.bus.read(u32, self.r[15] + 2);
|
||||||
|
self.r[15] += 4;
|
||||||
|
},
|
||||||
|
else => @compileError("Pipeline Reload: unsupported read width"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline fn fetch(self: *Self, comptime T: type) T {
|
inline fn fetch(self: *Self, comptime T: type) T {
|
||||||
comptime std.debug.assert(T == u32 or T == u16); // Opcode may be 32-bit (ARM) or 16-bit (THUMB)
|
comptime std.debug.assert(T == u32 or T == u16); // Opcode may be 32-bit (ARM) or 16-bit (THUMB)
|
||||||
defer self.r[15] += if (T == u32) 4 else 2;
|
defer self.r[15] += if (T == u32) 4 else 2;
|
||||||
|
@ -461,7 +484,7 @@ pub const Arm7tdmi = struct {
|
||||||
log_str = try std.fmt.bufPrint(&buf, thumb_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
log_str = try std.fmt.bufPrint(&buf, thumb_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_str = try std.fmt.bufPrint(&buf, arm_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, c_psr, opcode });
|
log_str = try std.fmt.bufPrint(&buf, arm_fmt, .{ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15 - 4, c_psr, opcode });
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = try file.writeAll(log_str);
|
_ = try file.writeAll(log_str);
|
||||||
|
|
|
@ -9,14 +9,24 @@ const sext = @import("../../util.zig").sext;
|
||||||
pub fn branch(comptime L: bool) InstrFn {
|
pub fn branch(comptime L: bool) InstrFn {
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||||
if (L) cpu.r[14] = cpu.r[15];
|
if (L) cpu.r[14] = cpu.r[15] - 4;
|
||||||
cpu.r[15] = cpu.fakePC() +% (sext(u32, u24, opcode) << 2);
|
|
||||||
|
cpu.r[15] = cpu.r[15] +% (sext(u32, u24, opcode) << 2);
|
||||||
|
cpu.reloadPipeline(u32);
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branchAndExchange(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
pub fn branchAndExchange(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
|
||||||
const rn = opcode & 0xF;
|
const rn = opcode & 0xF;
|
||||||
cpu.cpsr.t.write(cpu.r[rn] & 1 == 1);
|
|
||||||
cpu.r[15] = cpu.r[rn] & 0xFFFF_FFFE;
|
if (cpu.r[rn] & 1 == 1) {
|
||||||
|
cpu.r[15] = cpu.r[rn] & ~@as(u32, 1);
|
||||||
|
cpu.cpsr.t.set();
|
||||||
|
cpu.reloadPipeline(u16);
|
||||||
|
} else {
|
||||||
|
cpu.r[15] = cpu.r[rn] & ~@as(u32, 3);
|
||||||
|
cpu.cpsr.t.unset();
|
||||||
|
cpu.reloadPipeline(u32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const expected_rate = @import("emu.zig").frame_rate;
|
||||||
|
|
||||||
const sample_rate = @import("apu.zig").host_sample_rate;
|
const sample_rate = @import("apu.zig").host_sample_rate;
|
||||||
|
|
||||||
pub const enable_logging: bool = false;
|
pub const enable_logging: bool = true;
|
||||||
const is_binary: bool = false;
|
const is_binary: bool = false;
|
||||||
const log = std.log.scoped(.GUI);
|
const log = std.log.scoped(.GUI);
|
||||||
pub const log_level = if (builtin.mode != .Debug) .info else std.log.default_level;
|
pub const log_level = if (builtin.mode != .Debug) .info else std.log.default_level;
|
||||||
|
@ -72,7 +72,7 @@ pub fn main() anyerror!void {
|
||||||
var cpu = try Arm7tdmi.init(alloc, &scheduler, paths);
|
var cpu = try Arm7tdmi.init(alloc, &scheduler, paths);
|
||||||
defer cpu.deinit();
|
defer cpu.deinit();
|
||||||
cpu.bus.attach(&cpu);
|
cpu.bus.attach(&cpu);
|
||||||
// cpu.fastBoot(); // Uncomment to skip BIOS
|
cpu.fastBoot(); // Uncomment to skip BIOS
|
||||||
|
|
||||||
// Copy ROM title while Emulator still belongs to this thread
|
// Copy ROM title while Emulator still belongs to this thread
|
||||||
const title = cpu.bus.pak.title;
|
const title = cpu.bus.pak.title;
|
||||||
|
|
23
src/ppu.zig
23
src/ppu.zig
|
@ -658,11 +658,8 @@ const Palette = struct {
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)], value),
|
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)], value),
|
||||||
u8 => {
|
u8 => {
|
||||||
const halfword: u16 = @as(u16, value) * 0x0101;
|
const align_addr = addr & ~@as(u32, 1); // Aligned to Halfword boundary
|
||||||
// FIXME: I don't think my comment here makes sense?
|
std.mem.writeIntSliceLittle(u16, self.buf[align_addr..][0..@sizeOf(u16)], @as(u16, value) * 0x101);
|
||||||
const weird_addr = addr & ~@as(u32, 1); // *was* 8-bit read so address won't be aligned
|
|
||||||
|
|
||||||
std.mem.writeIntSliceLittle(u16, self.buf[weird_addr..(weird_addr + @sizeOf(u16))], halfword);
|
|
||||||
},
|
},
|
||||||
else => @compileError("PALRAM: Unsupported write width"),
|
else => @compileError("PALRAM: Unsupported write width"),
|
||||||
}
|
}
|
||||||
|
@ -705,21 +702,19 @@ const Vram = struct {
|
||||||
|
|
||||||
pub fn write(self: *Self, comptime T: type, dispcnt: io.DisplayControl, address: usize, value: T) void {
|
pub fn write(self: *Self, comptime T: type, dispcnt: io.DisplayControl, address: usize, value: T) void {
|
||||||
const mode: u3 = dispcnt.bg_mode.read();
|
const mode: u3 = dispcnt.bg_mode.read();
|
||||||
const addr = Self.mirror(address);
|
const idx = Self.mirror(address);
|
||||||
|
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[addr..][0..@sizeOf(T)], value),
|
u32, u16 => std.mem.writeIntSliceLittle(T, self.buf[idx..][0..@sizeOf(T)], value),
|
||||||
u8 => {
|
u8 => {
|
||||||
// Ignore if write is in OBJ
|
// Ignore write if it falls within the boundaries of OBJ VRAM
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
0, 1, 2 => if (0x0601_0000 <= address and address < 0x0601_8000) return,
|
0, 1, 2 => if (0x0001_0000 <= idx) return,
|
||||||
else => if (0x0601_4000 <= address and address < 0x0601_8000) return,
|
else => if (0x0001_4000 <= idx) return,
|
||||||
}
|
}
|
||||||
|
|
||||||
const halfword: u16 = @as(u16, value) * 0x0101;
|
const align_idx = idx & ~@as(u32, 1); // Aligned to a halfword boundary
|
||||||
const weird_addr = addr & ~@as(u32, 1);
|
std.mem.writeIntSliceLittle(u16, self.buf[align_idx..][0..@sizeOf(u16)], @as(u16, value) * 0x101);
|
||||||
|
|
||||||
std.mem.writeIntSliceLittle(u16, self.buf[weird_addr..(weird_addr + @sizeOf(u16))], halfword);
|
|
||||||
},
|
},
|
||||||
else => @compileError("VRAM: Unsupported write width"),
|
else => @compileError("VRAM: Unsupported write width"),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue