diff --git a/src/main.zig b/src/main.zig index 6d06f57..ddf1e74 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,38 +1,52 @@ const std = @import("std"); pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); + // var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + // defer _ = gpa.deinit(); + // const allocator = gpa.allocator(); + const mem: [0xFFFF]u8 = undefined; + const ws: [0xFF]u8 = undefined; + const rs: [0xFF]u8 = undefined; var uxn = Uxn{ - .mem = try allocator.alloc(u8, 0xFFFF), - .ws = .{ - .s = try allocator.alloc(u8, 0xFF), - .sp = 0, - }, - .rs = .{ - .s = try allocator.alloc(u8, 0xFF), - .sp = 0, - }, - .pc = 0x0100, + .mem = .{ .m = mem }, + .ws = .{ .s = ws }, + .rs = .{ .s = rs }, + .pc = 0x100, }; - defer allocator.free(uxn.mem); - defer allocator.free(uxn.ws.s); - defer allocator.free(uxn.rs.s); while (true) uxn.loop(); } pub const Uxn = struct { - mem: [0xFFFF]u8, + mem: Memory, ws: Stack, rs: Stack, pc: u16, + const Memory = struct { + m: [0xFFFF]u8, + + pub fn peek(self: *Memory, comptime T: type, idx: u16) T { + return switch (T) { + u8 => self.m[idx], + u16 => self.m[idx], + else => unreachable, + }; + } + + pub fn poke(self: *Memory, comptime T: type, idx: u16, val: T) void { + switch (T) { + u8 => self.m[idx] = val, + u16 => {}, + else => unreachable, + } + } + }; + const Stack = struct { s: [0xFF]u8, - sp: u8, + sp: u8 = 0, pub fn peek(self: *Stack, comptime T: type) T { return switch (T) { @@ -72,7 +86,7 @@ pub const Uxn = struct { }, u16 => { self.sp +%= 2; - self.s[self.sp] = v; + self.s[self.sp] = @truncate(v); }, else => unreachable, } @@ -80,7 +94,7 @@ pub const Uxn = struct { }; pub fn loop(self: *Uxn) void { - switch (self.mem[self.pc]) { + switch (self.mem.m[self.pc]) { 0x00 => {}, // BRK 0x01 => inc(&self.ws, u8, false), // INC 0x02 => pop(&self.ws, u8, false), // POP @@ -421,7 +435,7 @@ pub const Uxn = struct { fn jmp(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(T) else stack.pop(T); switch (T) { - u8 => self.pc +%= @as(i8, @bitCast(addr)), + u8 => self.pc = @intCast(@as(i32, @intCast(self.pc)) + @as(i8, @bitCast(addr))), u16 => self.pc = addr, else => unreachable, } @@ -432,7 +446,7 @@ pub const Uxn = struct { const addr = if (keep) stack.peek(T) else stack.pop(T); if (cond == 0) return; switch (T) { - u8 => self.pc +%= @as(i8, @bitCast(addr)), + u8 => self.pc = @intCast(@as(i32, @intCast(self.pc)) + @as(i8, @bitCast(addr))), u16 => self.pc = addr, else => unreachable, } @@ -442,55 +456,56 @@ pub const Uxn = struct { self.rs.push(u16, self.pc); const addr = if (keep) stack.peek(T) else stack.pop(T); switch (T) { - u8 => self.pc +%= @as(i8, @bitCast(addr)), + u8 => self.pc = @intCast(@as(i32, @intCast(self.pc)) + @as(i8, @bitCast(addr))), u16 => self.pc = addr, else => unreachable, } } fn sth(self: *Uxn, comptime swap: bool, comptime T: type, comptime keep: bool) void { - const src = if (swap) self.rs else self.ws; - const dst = if (swap) self.ws else self.rs; + var src = if (swap) self.rs else self.ws; + var dst = if (swap) self.ws else self.rs; const a = if (keep) src.peek(T) else src.pop(T); dst.push(T, a); } fn ldz(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u8) else stack.pop(u8); - switch (T) { - u8 => stack.push(T, self.mem[addr]), - u16 => {}, - else => unreachable, - } + stack.push(T, self.mem.peek(T, addr)); + // switch (T) { + // u8 => stack.push(T, self.mem[addr]), + // u16 => {}, + // else => unreachable, + // } } fn stz(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u8) else stack.pop(u8); const val = if (keep) stack.peek(T) else stack.pop(T); - self.mem[addr] = val; + self.mem.poke(T, addr, val); } fn ldr(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u8) else stack.pop(u8); - const val = self.mem[self.pc +% @as(i8, @intCast(addr))]; + const val = self.mem.peek(T, @intCast(@as(i32, @intCast(self.pc)) + @as(i8, @intCast(addr)))); stack.push(T, val); } fn str(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u8) else stack.pop(u8); const val = if (keep) stack.peek(T) else stack.pop(T); - self.mem[self.pc +% @as(i8, @bitCast(addr))] = val; + self.mem.poke(T, @intCast(@as(i32, @intCast(self.pc)) + @as(i8, @bitCast(addr))), val); } fn lda(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u16) else stack.pop(u16); - stack.push(T, self.mem[addr]); + stack.push(T, self.mem.peek(T, addr)); } fn sta(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void { const addr = if (keep) stack.peek(u16) else stack.pop(u16); const val = if (keep) stack.peek(T) else stack.pop(T); - self.mem[addr] = val; + self.mem.poke(T, addr, val); } fn dei(stack: *Stack, comptime T: type, comptime keep: bool) void { @@ -550,9 +565,19 @@ pub const Uxn = struct { fn sft(stack: *Stack, comptime T: type, comptime keep: bool) void { const a = if (keep) stack.peek(T) else stack.pop(T); const b = if (keep) stack.peek(T) else stack.pop(T); - const right = b & 0b00001111; - const left = (b & 0b11110000) >> 4; - stack.push(T, (a >> right) << left); + switch (T) { + u8 => { + const right: u3 = @truncate(b & 0b00001111); + const left: u3 = @truncate((b & 0b11110000) >> 4); + stack.push(T, (a >> right) << left); + }, + u16 => { + const right: u4 = @truncate(b & 0b0000000011111111); + const left: u4 = @truncate((b & 0b1111111100000000) >> 8); + stack.push(T, (a >> right) << left); + }, + else => unreachable, + } } }; @@ -667,12 +692,12 @@ test "uxnasm" { const ws: [0xFF]u8 = undefined; const rs: [0xFF]u8 = undefined; var uxn = Uxn{ - .mem = mem, + .mem = .{ .m = mem }, .ws = .{ .s = ws, .sp = 0 }, .rs = .{ .s = rs, .sp = 0 }, .pc = 0x100, }; - @memcpy(uxn.mem[0x100 .. 0x100 + rom.len], &rom); + @memcpy(uxn.mem.m[0x100 .. 0x100 + rom.len], &rom); while (true) uxn.loop(); }