feat: revamp controls, add support for X and Y buttons
This commit is contained in:
parent
0ad017cf43
commit
32e54c67bf
|
@ -14,7 +14,7 @@ pub const Io = struct {
|
||||||
wramcnt: WramCnt = .{ .raw = 0x00 },
|
wramcnt: WramCnt = .{ .raw = 0x00 },
|
||||||
|
|
||||||
// Read Only
|
// Read Only
|
||||||
keyinput: AtomicKeyInput = .{},
|
input: Input = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn warn(comptime format: []const u8, args: anytype) u0 {
|
fn warn(comptime format: []const u8, args: anytype) u0 {
|
||||||
|
@ -413,24 +413,54 @@ pub const KeyInput = extern union {
|
||||||
raw: u16,
|
raw: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
const AtomicKeyInput = struct {
|
pub const ExtKeyIn = extern union {
|
||||||
const Self = @This();
|
x: Bit(u16, 0),
|
||||||
|
y: Bit(u16, 1),
|
||||||
|
debug: Bit(u16, 3),
|
||||||
|
stylus: Bit(u16, 6),
|
||||||
|
hinge: Bit(u16, 7),
|
||||||
|
raw: u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Input = struct {
|
||||||
const AtomicOrder = std.builtin.AtomicOrder;
|
const AtomicOrder = std.builtin.AtomicOrder;
|
||||||
|
const AtomicRmwOp = std.builtin.AtomicRmwOp;
|
||||||
|
|
||||||
inner: KeyInput = .{ .raw = 0x03FF },
|
inner: u32 = 0x007F_03FF,
|
||||||
|
|
||||||
pub inline fn load(self: *const Self, comptime order: AtomicOrder) u16 {
|
pub inline fn keyinput(self: *const Input) KeyInput {
|
||||||
return switch (order) {
|
const value = @atomicLoad(u32, &self.inner, .Monotonic);
|
||||||
.AcqRel, .Release => @compileError("not supported for atomic loads"),
|
return .{ .raw = @truncate(value) };
|
||||||
else => @atomicLoad(u16, &self.inner.raw, order),
|
}
|
||||||
|
|
||||||
|
pub inline fn set_keyinput(self: *Input, comptime op: AtomicRmwOp, input: KeyInput) void {
|
||||||
|
const msked = switch (op) {
|
||||||
|
.And => 0xFFFF_FFFF & @as(u32, input.raw),
|
||||||
|
.Or => 0x0000_0000 | @as(u32, input.raw),
|
||||||
|
else => @compileError("not supported"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_ = @atomicRmw(u32, &self.inner, op, msked, .Monotonic);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn fetchOr(self: *Self, value: u16, comptime order: AtomicOrder) void {
|
pub inline fn extkeyin(self: *const Input) ExtKeyIn {
|
||||||
_ = @atomicRmw(u16, &self.inner.raw, .Or, value, order);
|
const value = @atomicLoad(u32, &self.inner, .Monotonic);
|
||||||
|
const shifted: u16 = @truncate(value >> 16);
|
||||||
|
|
||||||
|
return .{ .raw = shifted | 0b00110100 }; // bits 2, 4, 5 are always set
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn fetchAnd(self: *Self, value: u16, comptime order: AtomicOrder) void {
|
pub inline fn set_extkeyin(self: *Input, comptime op: AtomicRmwOp, input: ExtKeyIn) void {
|
||||||
_ = @atomicRmw(u16, &self.inner.raw, .And, value, order);
|
const msked = switch (op) {
|
||||||
|
.And => 0xFFFF_FFFF & (@as(u32, ~input.raw) << 16),
|
||||||
|
.Or => 0x0000_0000 | (@as(u32, input.raw) << 16),
|
||||||
|
else => @compileError("not supported"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = @atomicRmw(u32, &self.inner, op, msked, .Monotonic);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn set(self: *Input, comptime op: AtomicRmwOp, value: u32) void {
|
||||||
|
_ = @atomicRmw(u32, &self.inner, op, value, .Monotonic);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,7 +75,9 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||||
// Timers
|
// Timers
|
||||||
0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
||||||
|
|
||||||
0x0400_0130 => bus.io.shr.keyinput.load(.Monotonic),
|
0x0400_0130 => bus.io.shr.input.keyinput().raw,
|
||||||
|
0x0400_0136 => bus.io.shr.input.extkeyin().raw,
|
||||||
|
|
||||||
0x0400_0180 => @truncate(bus.io.shr.ipc._nds7.sync.raw),
|
0x0400_0180 => @truncate(bus.io.shr.ipc._nds7.sync.raw),
|
||||||
0x0400_0184 => @truncate(bus.io.shr.ipc._nds7.cnt.raw),
|
0x0400_0184 => @truncate(bus.io.shr.ipc._nds7.cnt.raw),
|
||||||
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
else => warn("unexpected: read(T: {}, addr: 0x{X:0>8}) {} ", .{ T, address, T }),
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub fn read(bus: *const Bus, comptime T: type, address: u32) T {
|
||||||
0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
0x0400_0100...0x0400_010E => warn("TODO: impl timer", .{}),
|
||||||
|
|
||||||
0x0400_0004 => bus.ppu.io.nds9.dispstat.raw,
|
0x0400_0004 => bus.ppu.io.nds9.dispstat.raw,
|
||||||
0x0400_0130 => bus.io.shr.keyinput.load(.Monotonic),
|
0x0400_0130 => bus.io.shr.input.keyinput().raw,
|
||||||
|
|
||||||
0x0400_0180 => @truncate(bus.io.shr.ipc._nds9.sync.raw),
|
0x0400_0180 => @truncate(bus.io.shr.ipc._nds9.sync.raw),
|
||||||
0x0400_0184 => @truncate(bus.io.shr.ipc._nds9.cnt.raw),
|
0x0400_0184 => @truncate(bus.io.shr.ipc._nds9.cnt.raw),
|
||||||
|
|
|
@ -9,6 +9,7 @@ const emu = @import("core/emu.zig");
|
||||||
|
|
||||||
const System = @import("core/emu.zig").System;
|
const System = @import("core/emu.zig").System;
|
||||||
const KeyInput = @import("core/io.zig").KeyInput;
|
const KeyInput = @import("core/io.zig").KeyInput;
|
||||||
|
const ExtKeyIn = @import("core/io.zig").ExtKeyIn;
|
||||||
const Scheduler = @import("core/Scheduler.zig");
|
const Scheduler = @import("core/Scheduler.zig");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
@ -125,44 +126,54 @@ pub const Ui = struct {
|
||||||
SDL.SDL_KEYDOWN => {
|
SDL.SDL_KEYDOWN => {
|
||||||
// TODO: Make use of compare_and_xor?
|
// TODO: Make use of compare_and_xor?
|
||||||
const key_code = event.key.keysym.sym;
|
const key_code = event.key.keysym.sym;
|
||||||
|
|
||||||
var keyinput: KeyInput = .{ .raw = 0x0000 };
|
var keyinput: KeyInput = .{ .raw = 0x0000 };
|
||||||
|
var extkeyin: ExtKeyIn = .{ .raw = 0x0000 };
|
||||||
|
|
||||||
switch (key_code) {
|
switch (key_code) {
|
||||||
SDL.SDLK_UP => keyinput.up.set(),
|
SDL.SDLK_UP => keyinput.up.set(),
|
||||||
SDL.SDLK_DOWN => keyinput.down.set(),
|
SDL.SDLK_DOWN => keyinput.down.set(),
|
||||||
SDL.SDLK_LEFT => keyinput.left.set(),
|
SDL.SDLK_LEFT => keyinput.left.set(),
|
||||||
SDL.SDLK_RIGHT => keyinput.right.set(),
|
SDL.SDLK_RIGHT => keyinput.right.set(),
|
||||||
SDL.SDLK_x => keyinput.a.set(),
|
SDL.SDLK_c => keyinput.a.set(),
|
||||||
SDL.SDLK_z => keyinput.b.set(),
|
SDL.SDLK_x => keyinput.b.set(),
|
||||||
|
SDL.SDLK_d => extkeyin.x.set(),
|
||||||
|
SDL.SDLK_s => extkeyin.y.set(),
|
||||||
SDL.SDLK_a => keyinput.shoulder_l.set(),
|
SDL.SDLK_a => keyinput.shoulder_l.set(),
|
||||||
SDL.SDLK_s => keyinput.shoulder_r.set(),
|
SDL.SDLK_f => keyinput.shoulder_r.set(),
|
||||||
SDL.SDLK_RETURN => keyinput.start.set(),
|
SDL.SDLK_RETURN => keyinput.start.set(),
|
||||||
SDL.SDLK_RSHIFT => keyinput.select.set(),
|
SDL.SDLK_RSHIFT => keyinput.select.set(),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
system.bus9.io.shr.keyinput.fetchAnd(~keyinput.raw, .Monotonic);
|
const input = (@as(u32, extkeyin.raw) << 16) | keyinput.raw;
|
||||||
|
system.bus9.io.shr.input.set(.And, ~input);
|
||||||
},
|
},
|
||||||
SDL.SDL_KEYUP => {
|
SDL.SDL_KEYUP => {
|
||||||
// TODO: Make use of compare_and_xor?
|
// TODO: Make use of compare_and_xor?
|
||||||
const key_code = event.key.keysym.sym;
|
const key_code = event.key.keysym.sym;
|
||||||
|
|
||||||
var keyinput: KeyInput = .{ .raw = 0x0000 };
|
var keyinput: KeyInput = .{ .raw = 0x0000 };
|
||||||
|
var extkeyin: ExtKeyIn = .{ .raw = 0x0000 };
|
||||||
|
|
||||||
switch (key_code) {
|
switch (key_code) {
|
||||||
SDL.SDLK_UP => keyinput.up.set(),
|
SDL.SDLK_UP => keyinput.up.set(),
|
||||||
SDL.SDLK_DOWN => keyinput.down.set(),
|
SDL.SDLK_DOWN => keyinput.down.set(),
|
||||||
SDL.SDLK_LEFT => keyinput.left.set(),
|
SDL.SDLK_LEFT => keyinput.left.set(),
|
||||||
SDL.SDLK_RIGHT => keyinput.right.set(),
|
SDL.SDLK_RIGHT => keyinput.right.set(),
|
||||||
SDL.SDLK_x => keyinput.a.set(),
|
SDL.SDLK_c => keyinput.a.set(),
|
||||||
SDL.SDLK_z => keyinput.b.set(),
|
SDL.SDLK_x => keyinput.b.set(),
|
||||||
|
SDL.SDLK_d => extkeyin.x.set(),
|
||||||
|
SDL.SDLK_s => extkeyin.y.set(),
|
||||||
SDL.SDLK_a => keyinput.shoulder_l.set(),
|
SDL.SDLK_a => keyinput.shoulder_l.set(),
|
||||||
SDL.SDLK_s => keyinput.shoulder_r.set(),
|
SDL.SDLK_f => keyinput.shoulder_r.set(),
|
||||||
SDL.SDLK_RETURN => keyinput.start.set(),
|
SDL.SDLK_RETURN => keyinput.start.set(),
|
||||||
SDL.SDLK_RSHIFT => keyinput.select.set(),
|
SDL.SDLK_RSHIFT => keyinput.select.set(),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
system.bus9.io.shr.keyinput.fetchOr(keyinput.raw, .Monotonic);
|
const input = (@as(u32, extkeyin.raw) << 16) | keyinput.raw;
|
||||||
|
system.bus9.io.shr.input.set(.Or, input);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue