Compare commits

..

No commits in common. "26db340077185cda94cc88717c68a250db17fa63" and "d7e3d347260696cafaad53dd683deafc251d0448" have entirely different histories.

5 changed files with 47 additions and 70 deletions

View File

@ -24,14 +24,14 @@ pub const Io = struct {
postflg: PostFlag, postflg: PostFlag,
waitcnt: WaitControl, waitcnt: WaitControl,
haltcnt: HaltControl, haltcnt: HaltControl,
keyinput: AtomicKeyInput, keyinput: KeyInput,
pub fn init() Self { pub fn init() Self {
return .{ return .{
.ime = false, .ime = false,
.ie = .{ .raw = 0x0000 }, .ie = .{ .raw = 0x0000 },
.irq = .{ .raw = 0x0000 }, .irq = .{ .raw = 0x0000 },
.keyinput = AtomicKeyInput.init(.{ .raw = 0x03FF }), .keyinput = .{ .raw = 0x03FF },
.waitcnt = .{ .raw = 0x0000_0000 }, // Bit 15 == 0 for GBA .waitcnt = .{ .raw = 0x0000_0000 }, // Bit 15 == 0 for GBA
.postflg = .FirstBoot, .postflg = .FirstBoot,
.haltcnt = .Execute, .haltcnt = .Execute,
@ -92,7 +92,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) ?T {
0x0400_0128 => util.io.read.todo(log, "Read {} from SIOCNT", .{T}), 0x0400_0128 => util.io.read.todo(log, "Read {} from SIOCNT", .{T}),
// Keypad Input // Keypad Input
0x0400_0130 => bus.io.keyinput.load(.Monotonic).raw, 0x0400_0130 => bus.io.keyinput.raw,
// Serial Communication 2 // Serial Communication 2
0x0400_0134 => util.io.read.todo(log, "Read {} from RCNT", .{T}), 0x0400_0134 => util.io.read.todo(log, "Read {} from RCNT", .{T}),
@ -376,31 +376,6 @@ const KeyInput = extern union {
raw: u16, raw: u16,
}; };
const AtomicKeyInput = struct {
const Self = @This();
const Ordering = std.atomic.Ordering;
inner: KeyInput,
pub fn init(value: KeyInput) Self {
return .{ .inner = value };
}
pub inline fn load(self: *const Self, comptime ordering: Ordering) KeyInput {
return .{ .raw = switch (ordering) {
.AcqRel, .Release => @compileError("not supported for atomic loads"),
else => @atomicLoad(u16, &self.inner.raw, ordering),
} };
}
pub inline fn store(self: *Self, value: u16, comptime ordering: Ordering) void {
switch (ordering) {
.AcqRel, .Acquire => @compileError("not supported for atomic stores"),
else => @atomicStore(u16, &self.inner.raw, value, ordering),
}
}
};
// Read / Write // Read / Write
pub const BackgroundControl = extern union { pub const BackgroundControl = extern union {
priority: Bitfield(u16, 0, 2), priority: Bitfield(u16, 0, 2),

View File

@ -56,7 +56,7 @@ fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), schedule
.Unlimited, .UnlimitedFPS => { .Unlimited, .UnlimitedFPS => {
log.info("Emulation w/out video sync", .{}); log.info("Emulation w/out video sync", .{});
while (!quit.load(.Monotonic)) { while (!quit.load(.SeqCst)) {
runFrame(scheduler, cpu); runFrame(scheduler, cpu);
audioSync(audio_sync, cpu.bus.apu.stream, &cpu.bus.apu.is_buffer_full); audioSync(audio_sync, cpu.bus.apu.stream, &cpu.bus.apu.is_buffer_full);
@ -68,7 +68,7 @@ fn inner(comptime kind: RunKind, audio_sync: bool, quit: *Atomic(bool), schedule
var timer = Timer.start() catch @panic("failed to initalize std.timer.Timer"); var timer = Timer.start() catch @panic("failed to initalize std.timer.Timer");
var wake_time: u64 = frame_period; var wake_time: u64 = frame_period;
while (!quit.load(.Monotonic)) { while (!quit.load(.SeqCst)) {
runFrame(scheduler, cpu); runFrame(scheduler, cpu);
const new_wake_time = videoSync(&timer, wake_time); const new_wake_time = videoSync(&timer, wake_time);

View File

@ -1464,7 +1464,7 @@ const FrameBuffer = struct {
layers: [2][]u8, layers: [2][]u8,
buf: []u8, buf: []u8,
current: std.atomic.Atomic(u8), current: u1,
allocator: Allocator, allocator: Allocator,
@ -1483,7 +1483,7 @@ const FrameBuffer = struct {
// Front and Back Framebuffers // Front and Back Framebuffers
.layers = [_][]u8{ buf[0..][0..framebuf_len], buf[framebuf_len..][0..framebuf_len] }, .layers = [_][]u8{ buf[0..][0..framebuf_len], buf[framebuf_len..][0..framebuf_len] },
.buf = buf, .buf = buf,
.current = std.atomic.Atomic(u8).init(0), .current = 0,
.allocator = allocator, .allocator = allocator,
}; };
@ -1495,12 +1495,10 @@ const FrameBuffer = struct {
} }
pub fn swap(self: *Self) void { pub fn swap(self: *Self) void {
_ = self.current.fetchXor(1, .Release); // fetchNot(.Release) self.current = ~self.current;
} }
pub fn get(self: *Self, comptime dev: Device) []u8 { pub fn get(self: *Self, comptime dev: Device) []u8 {
const current = @intCast(u1, self.current.load(.Acquire)); return self.layers[if (dev == .Emulator) self.current else ~self.current];
return self.layers[if (dev == .Emulator) current else ~current];
} }
}; };

View File

@ -64,7 +64,7 @@ pub const Gui = struct {
const ctx = SDL.SDL_GL_CreateContext(window) orelse panic(); const ctx = SDL.SDL_GL_CreateContext(window) orelse panic();
if (SDL.SDL_GL_MakeCurrent(window, ctx) < 0) panic(); if (SDL.SDL_GL_MakeCurrent(window, ctx) < 0) panic();
try gl.load(ctx, Self.glGetProcAddress); gl.load(ctx, Self.glGetProcAddress) catch @panic("gl.load failed");
if (SDL.SDL_GL_SetSwapInterval(@boolToInt(config.config().host.vsync)) < 0) panic(); if (SDL.SDL_GL_SetSwapInterval(@boolToInt(config.config().host.vsync)) < 0) panic();
const program_id = try compileShaders(); const program_id = try compileShaders();
@ -164,10 +164,9 @@ pub const Gui = struct {
gl.deleteBuffers(1, &buffer_ids[1]); // VBO gl.deleteBuffers(1, &buffer_ids[1]); // VBO
gl.deleteVertexArrays(1, &buffer_ids[0]); // VAO gl.deleteVertexArrays(1, &buffer_ids[0]); // VAO
} }
const vao_id = buffer_ids[0];
const tex_id = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer)); const vao_id = buffer_ids[0];
defer gl.deleteTextures(1, &tex_id); _ = Self.generateTexture(cpu.bus.ppu.framebuf.get(.Renderer));
const thread = try std.Thread.spawn(.{}, emu.run, .{ &quit, scheduler, cpu, &tracker }); const thread = try std.Thread.spawn(.{}, emu.run, .{ &quit, scheduler, cpu, &tracker });
defer thread.join(); defer thread.join();
@ -180,50 +179,54 @@ pub const Gui = struct {
switch (event.type) { switch (event.type) {
SDL.SDL_QUIT => break :emu_loop, SDL.SDL_QUIT => break :emu_loop,
SDL.SDL_KEYDOWN => { SDL.SDL_KEYDOWN => {
const io = &cpu.bus.io;
const key_code = event.key.keysym.sym; const key_code = event.key.keysym.sym;
var keyinput = cpu.bus.io.keyinput.load(.Monotonic);
switch (key_code) { switch (key_code) {
SDL.SDLK_UP => keyinput.up.unset(), SDL.SDLK_UP => io.keyinput.up.unset(),
SDL.SDLK_DOWN => keyinput.down.unset(), SDL.SDLK_DOWN => io.keyinput.down.unset(),
SDL.SDLK_LEFT => keyinput.left.unset(), SDL.SDLK_LEFT => io.keyinput.left.unset(),
SDL.SDLK_RIGHT => keyinput.right.unset(), SDL.SDLK_RIGHT => io.keyinput.right.unset(),
SDL.SDLK_x => keyinput.a.unset(), SDL.SDLK_x => io.keyinput.a.unset(),
SDL.SDLK_z => keyinput.b.unset(), SDL.SDLK_z => io.keyinput.b.unset(),
SDL.SDLK_a => keyinput.shoulder_l.unset(), SDL.SDLK_a => io.keyinput.shoulder_l.unset(),
SDL.SDLK_s => keyinput.shoulder_r.unset(), SDL.SDLK_s => io.keyinput.shoulder_r.unset(),
SDL.SDLK_RETURN => keyinput.start.unset(), SDL.SDLK_RETURN => io.keyinput.start.unset(),
SDL.SDLK_RSHIFT => keyinput.select.unset(), SDL.SDLK_RSHIFT => io.keyinput.select.unset(),
else => {}, else => {},
} }
cpu.bus.io.keyinput.store(keyinput.raw, .Monotonic);
}, },
SDL.SDL_KEYUP => { SDL.SDL_KEYUP => {
const io = &cpu.bus.io;
const key_code = event.key.keysym.sym; const key_code = event.key.keysym.sym;
var keyinput = cpu.bus.io.keyinput.load(.Monotonic);
switch (key_code) { switch (key_code) {
SDL.SDLK_UP => keyinput.up.set(), SDL.SDLK_UP => io.keyinput.up.set(),
SDL.SDLK_DOWN => keyinput.down.set(), SDL.SDLK_DOWN => io.keyinput.down.set(),
SDL.SDLK_LEFT => keyinput.left.set(), SDL.SDLK_LEFT => io.keyinput.left.set(),
SDL.SDLK_RIGHT => keyinput.right.set(), SDL.SDLK_RIGHT => io.keyinput.right.set(),
SDL.SDLK_x => keyinput.a.set(), SDL.SDLK_x => io.keyinput.a.set(),
SDL.SDLK_z => keyinput.b.set(), SDL.SDLK_z => io.keyinput.b.set(),
SDL.SDLK_a => keyinput.shoulder_l.set(), SDL.SDLK_a => io.keyinput.shoulder_l.set(),
SDL.SDLK_s => keyinput.shoulder_r.set(), SDL.SDLK_s => io.keyinput.shoulder_r.set(),
SDL.SDLK_RETURN => keyinput.start.set(), SDL.SDLK_RETURN => io.keyinput.start.set(),
SDL.SDLK_RSHIFT => keyinput.select.set(), SDL.SDLK_RSHIFT => io.keyinput.select.set(),
SDL.SDLK_i => { SDL.SDLK_i => {
comptime std.debug.assert(sample_format == SDL.AUDIO_U16); comptime std.debug.assert(sample_format == SDL.AUDIO_U16);
log.err("Sample Count: {}", .{@intCast(u32, SDL.SDL_AudioStreamAvailable(cpu.bus.apu.stream)) / (2 * @sizeOf(u16))}); log.err("Sample Count: {}", .{@intCast(u32, SDL.SDL_AudioStreamAvailable(cpu.bus.apu.stream)) / (2 * @sizeOf(u16))});
}, },
// SDL.SDLK_j => log.err("Scheduler Capacity: {} | Scheduler Event Count: {}", .{ scheduler.queue.capacity(), scheduler.queue.count() }), SDL.SDLK_j => log.err("Scheduler Capacity: {} | Scheduler Event Count: {}", .{ scheduler.queue.capacity(), scheduler.queue.count() }),
SDL.SDLK_k => {}, SDL.SDLK_k => {
// Dump IWRAM to file
log.info("PC: 0x{X:0>8}", .{cpu.r[15]});
log.info("LR: 0x{X:0>8}", .{cpu.r[14]});
// const iwram_file = try std.fs.cwd().createFile("iwram.bin", .{});
// defer iwram_file.close();
// try iwram_file.writeAll(cpu.bus.iwram.buf);
},
else => {}, else => {},
} }
cpu.bus.io.keyinput.store(keyinput.raw, .Monotonic);
}, },
else => {}, else => {},
} }
@ -242,11 +245,12 @@ pub const Gui = struct {
SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr); SDL.SDL_SetWindowTitle(self.window, dyn_title.ptr);
} }
quit.store(true, .Monotonic); // Terminate Emulator Thread quit.store(true, .SeqCst); // Terminate Emulator Thread
} }
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
self.audio.deinit(); self.audio.deinit();
// TODO: Buffer deletions
gl.deleteProgram(self.program_id); gl.deleteProgram(self.program_id);
SDL.SDL_GL_DeleteContext(self.ctx); SDL.SDL_GL_DeleteContext(self.ctx);
SDL.SDL_DestroyWindow(self.window); SDL.SDL_DestroyWindow(self.window);

View File

@ -47,7 +47,7 @@ pub const FpsTracker = struct {
pub fn value(self: *Self) u32 { pub fn value(self: *Self) u32 {
if (self.timer.read() >= std.time.ns_per_s) { if (self.timer.read() >= std.time.ns_per_s) {
self.fps = self.count.swap(0, .Monotonic); self.fps = self.count.swap(0, .SeqCst);
self.timer.reset(); self.timer.reset();
} }