diff --git a/src/main.zig b/src/main.zig index 5a7883e..6ae442b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Uxn = @import("uxn.zig"); +const Varvara = @import("varvara.zig"); // TODO combine with uxn.zig const UxnFmt = @import("uxn-instructions.zig"); @@ -20,13 +21,16 @@ pub fn main() !void { const rom = try file.readToEndAlloc(allocator, 0xFF00); defer allocator.free(rom); - var uxn = Uxn{ .pc = 0x100 }; - @memcpy(uxn.mem.m[0x100 .. rom.len + 0x100], rom); + var varvara = Varvara.init(rom); var running = true; while (running) { - std.debug.print("pc={X} code={X} op={s}\n", .{ uxn.pc, uxn.mem.m[uxn.pc], UxnFmt.fmtInstrs(uxn.mem.m[uxn.pc .. uxn.pc +% 1]) }); - if (uxn.eval()) running = false; + std.debug.print("pc={X} code={X} op={s}\n", .{ + varvara.uxn.pc, + varvara.uxn.mem.m[varvara.uxn.pc], + UxnFmt.fmtInstrs(varvara.uxn.mem.m[varvara.uxn.pc .. varvara.uxn.pc +% 1]), + }); + if (varvara.uxn.eval()) running = false; } } else return error.NoRom; } diff --git a/src/uxn.zig b/src/uxn.zig index 1da3114..d88cc3a 100644 --- a/src/uxn.zig +++ b/src/uxn.zig @@ -7,6 +7,16 @@ rs: Stack = .{ .s = undefined }, dev: [0x100]u8 = undefined, pc: u16, +deo8: *const fn (*Uxn, *Stack, u8, u8) void = deo8Stub, +deo16: *const fn (*Uxn, *Stack, u8, u16) void = deo16Stub, +dei8: *const fn (*Uxn, *Stack, u8) void = dei8Stub, +dei16: *const fn (*Uxn, *Stack, u8) void = dei16Stub, + +fn deo8Stub(_: *Uxn, _: *Stack, _: u8, _: u8) void {} +fn deo16Stub(_: *Uxn, _: *Stack, _: u8, _: u16) void {} +fn dei8Stub(_: *Uxn, _: *Stack, _: u8) void {} +fn dei16Stub(_: *Uxn, _: *Stack, _: u8) void {} + const Memory = struct { m: [0x10000]u8, @@ -503,21 +513,29 @@ fn sta(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { fn dei(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const d = if (keep) stack.peek(u8) else stack.pop(u8); + switch (T) { + u8 => self.dei8(self, stack, d), + u16 => self.dei16(self, stack, d), + else => @compileError("expected u8 or u16, got " + @typeName(T)), + } stack.push(T, self.dev[d]); } fn deo(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { - std.debug.print("DEO: {any} ", .{stack.s}); const d = if (keep) stack.peek(u8) else stack.pop(u8); const v = if (keep) stack.peek(T) else stack.pop(T); - std.debug.print("v{X} d{X}\n", .{ v, d }); + std.debug.print("DEO: dev {X}, val {X}\n", .{ d, v }); switch (T) { - u8 => self.dev[d] = v, + u8 => { + self.dev[d] = v; + self.deo8(self, stack, d, v); + }, u16 => { self.dev[d] = @truncate(v >> 8); self.dev[d +% 1] = @truncate(v & 0xFF); + self.deo16(self, stack, d, v); }, - else => unreachable, + else => @compileError("expected u8 or u16, got " + @typeName(T)), } } diff --git a/src/varvara.zig b/src/varvara.zig new file mode 100644 index 0000000..60110b9 --- /dev/null +++ b/src/varvara.zig @@ -0,0 +1,40 @@ +const std = @import("std"); + +const Uxn = @import("uxn.zig"); +const Varvara = @This(); + +uxn: Uxn, + +pub fn init(rom: []const u8) Varvara { + var uxn = Uxn{ .pc = 0x100 }; + @memcpy(uxn.mem.m[0x100 .. rom.len + 0x100], rom); + return .{ .uxn = uxn }; +} + +pub fn deo8(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u8) void { + const self: Varvara = @fieldParentPtr("uxn", uxn); + // _ = .{ self, stack, device, value }; + _ = self; + _ = stack; + switch (device) { + 0x18 => { + std.io.getStdOut().writer().writeByte(value) catch |e| @panic(e); + }, + else => {}, + } +} + +pub fn deo16(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u16) void { + const self: Varvara = @fieldParentPtr("uxn", uxn); + _ = .{ self, stack, device, value }; +} + +pub fn dei8(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u8) void { + const self: Varvara = @fieldParentPtr("uxn", uxn); + _ = .{ self, stack, device, value }; +} + +pub fn dei16(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u16) void { + const self: Varvara = @fieldParentPtr("uxn", uxn); + _ = .{ self, stack, device, value }; +}