improve debugging, fix a lot, add basic op test, heap allocation, dear god
This commit is contained in:
parent
24f5fd49fa
commit
6d2cb973d1
3 changed files with 193 additions and 115 deletions
15
src/main.zig
15
src/main.zig
|
@ -3,6 +3,8 @@ const std = @import("std");
|
||||||
const Uxn = @import("uxn.zig");
|
const Uxn = @import("uxn.zig");
|
||||||
const Varvara = @import("varvara.zig");
|
const Varvara = @import("varvara.zig");
|
||||||
|
|
||||||
|
const DEBUG = true;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
|
@ -19,16 +21,17 @@ pub fn main() !void {
|
||||||
const rom = try file.readToEndAlloc(allocator, 0xFF00);
|
const rom = try file.readToEndAlloc(allocator, 0xFF00);
|
||||||
defer allocator.free(rom);
|
defer allocator.free(rom);
|
||||||
|
|
||||||
var varvara = Varvara.init(rom);
|
Uxn.setDebug(DEBUG);
|
||||||
|
|
||||||
var running = true;
|
var varvara = try Varvara.init(allocator, rom);
|
||||||
while (running) {
|
defer varvara.deinit();
|
||||||
std.debug.print("pc={X} code={X} op={s}\n", .{
|
|
||||||
|
while (varvara.uxn.eval()) {
|
||||||
|
if (DEBUG) std.debug.print("{s}\t\tpc {X}, code {X}\n", .{
|
||||||
|
Uxn.fmtInstrs(varvara.uxn.mem.m[varvara.uxn.pc .. varvara.uxn.pc +% 1]),
|
||||||
varvara.uxn.pc,
|
varvara.uxn.pc,
|
||||||
varvara.uxn.mem.m[varvara.uxn.pc],
|
varvara.uxn.mem.m[varvara.uxn.pc],
|
||||||
Uxn.fmtInstrs(varvara.uxn.mem.m[varvara.uxn.pc .. varvara.uxn.pc +% 1]),
|
|
||||||
});
|
});
|
||||||
if (varvara.uxn.eval()) running = false;
|
|
||||||
}
|
}
|
||||||
} else return error.NoRom;
|
} else return error.NoRom;
|
||||||
}
|
}
|
||||||
|
|
240
src/uxn.zig
240
src/uxn.zig
|
@ -1,11 +1,17 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Uxn = @This();
|
const Uxn = @This();
|
||||||
|
|
||||||
|
var debug = true;
|
||||||
|
|
||||||
|
pub fn setDebug(v: bool) void {
|
||||||
|
debug = v;
|
||||||
|
}
|
||||||
|
|
||||||
mem: Memory = .{ .m = undefined },
|
mem: Memory = .{ .m = undefined },
|
||||||
ws: Stack = .{ .s = undefined },
|
ws: Stack = .{ .s = undefined },
|
||||||
rs: Stack = .{ .s = undefined },
|
rs: Stack = .{ .s = undefined },
|
||||||
dev: [0x100]u8 = undefined,
|
dev: [0x100]u8 = undefined,
|
||||||
pc: u16,
|
pc: u16 = 0x100,
|
||||||
|
|
||||||
deo8: *const fn (*Uxn, *Stack, u8, u8) void = deo8Stub,
|
deo8: *const fn (*Uxn, *Stack, u8, u8) void = deo8Stub,
|
||||||
deo16: *const fn (*Uxn, *Stack, u8, u16) void = deo16Stub,
|
deo16: *const fn (*Uxn, *Stack, u8, u16) void = deo16Stub,
|
||||||
|
@ -17,18 +23,43 @@ fn deo16Stub(_: *Uxn, _: *Stack, _: u8, _: u16) void {}
|
||||||
fn dei8Stub(_: *Uxn, _: *Stack, _: u8) void {}
|
fn dei8Stub(_: *Uxn, _: *Stack, _: u8) void {}
|
||||||
fn dei16Stub(_: *Uxn, _: *Stack, _: u8) void {}
|
fn dei16Stub(_: *Uxn, _: *Stack, _: u8) void {}
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !Uxn {
|
||||||
|
const mem = try allocator.alloc(u8, 0x10000);
|
||||||
|
errdefer allocator.free(mem);
|
||||||
|
for (mem) |*b| b.* = 0;
|
||||||
|
return .{
|
||||||
|
.mem = .{ .m = mem },
|
||||||
|
.ws = .{ .s = [_]u8{0} ** 0x100 },
|
||||||
|
.rs = .{ .s = [_]u8{0} ** 0x100 },
|
||||||
|
.dev = [_]u8{0} ** 0x100,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Uxn, allocator: std.mem.Allocator) void {
|
||||||
|
allocator.free(self.mem.m);
|
||||||
|
}
|
||||||
|
|
||||||
const Memory = struct {
|
const Memory = struct {
|
||||||
m: [0x10000]u8,
|
m: []u8,
|
||||||
|
|
||||||
pub fn peek(self: *Memory, comptime T: type, idx: u16) T {
|
pub fn peek(self: *Memory, comptime T: type, idx: u16) T {
|
||||||
return switch (T) {
|
switch (T) {
|
||||||
u8 => self.m[idx],
|
u8 => {
|
||||||
u16 => @as(u16, @intCast(self.m[idx])) << 8 | self.m[idx +% 1],
|
const val = self.m[idx];
|
||||||
|
if (debug) std.debug.print("\x1b[33mmem peek:\x1b[0m\tidx {d}, type {s}, val {d}\n", .{ idx, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
u16 => {
|
||||||
|
const val = @as(u16, @intCast(self.m[idx])) << 8 | self.m[idx +% 1];
|
||||||
|
if (debug) std.debug.print("\x1b[33mmem peek:\x1b[0m\tidx {d}, type {s}, val {d}\n", .{ idx, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poke(self: *Memory, comptime T: type, idx: u16, val: T) void {
|
pub fn poke(self: *Memory, comptime T: type, idx: u16, val: T) void {
|
||||||
|
if (debug) std.debug.print("\x1b[33mmem poke:\x1b[0m\tidx {d}, type {s}, val {d}\n", .{ idx, @typeName(T), val });
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u8 => self.m[idx] = val,
|
u8 => self.m[idx] = val,
|
||||||
u16 => {
|
u16 => {
|
||||||
|
@ -41,28 +72,37 @@ const Memory = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
test "memory peek/poke" {
|
test "memory peek/poke" {
|
||||||
var mem = Memory{ .m = undefined };
|
const m = try std.testing.allocator.alloc(u8, 0x10000);
|
||||||
|
defer std.testing.allocator.free(m);
|
||||||
|
var mem = Memory{ .m = m };
|
||||||
mem.poke(u16, 0, 0xABCD);
|
mem.poke(u16, 0, 0xABCD);
|
||||||
mem.poke(u8, 2, 0x69);
|
mem.poke(u8, 2, 0x69);
|
||||||
try std.testing.expectEqual(0xABCD, mem.peek(u16, 0));
|
try std.testing.expectEqual(0xABCD, mem.peek(u16, 0));
|
||||||
try std.testing.expectEqual(0x69, mem.peek(u8, 2));
|
try std.testing.expectEqual(0x69, mem.peek(u8, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Stack = struct {
|
pub const Stack = struct {
|
||||||
s: [0x100]u8,
|
s: [0x100]u8,
|
||||||
sp: u8 = 0,
|
sp: u8 = 0,
|
||||||
|
|
||||||
pub fn peek(self: *Stack, comptime T: type) T {
|
pub fn peek(self: *Stack, comptime T: type) T {
|
||||||
std.debug.print("\x1b[1;32mstack peek:\x1b[0m sp {d}, type {s}\n", .{ self.sp, @typeName(T) });
|
switch (T) {
|
||||||
return switch (T) {
|
u8 => {
|
||||||
u8 => self.s[self.sp -% 1],
|
const val = self.s[self.sp -% 1];
|
||||||
u16 => @as(u16, @intCast(self.s[self.sp -% 2])) << 8 | self.s[self.sp -% 1],
|
if (debug) std.debug.print("\x1b[32mstack peek:\x1b[0m\tsp {d}, type {s}, val {d}\n", .{ self.sp, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
u16 => {
|
||||||
|
const val = @as(u16, @intCast(self.s[self.sp -% 2])) << 8 | self.s[self.sp -% 1];
|
||||||
|
if (debug) std.debug.print("\x1b[32mstack peek:\x1b[0m\tsp {d}, type {s}, val {d}\n", .{ self.sp, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poke(self: *Stack, comptime T: type, v: T) void {
|
pub fn poke(self: *Stack, comptime T: type, v: T) void {
|
||||||
std.debug.print("\x1b[1;32mstack poke:\x1b[0m sp {d}, type {s}\n", .{ self.sp, @typeName(T) });
|
if (debug) std.debug.print("\x1b[32mstack poke:\x1b[0m\tsp {d}, type {s}, val {d}\n", .{ self.sp, @typeName(T), v });
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u8 => self.s[self.sp -% 1] = v,
|
u8 => self.s[self.sp -% 1] = v,
|
||||||
u16 => {
|
u16 => {
|
||||||
|
@ -75,16 +115,23 @@ const Stack = struct {
|
||||||
|
|
||||||
pub fn pop(self: *Stack, comptime T: type) T {
|
pub fn pop(self: *Stack, comptime T: type) T {
|
||||||
self.sp -%= @intCast(@divExact(@typeInfo(T).int.bits, 8));
|
self.sp -%= @intCast(@divExact(@typeInfo(T).int.bits, 8));
|
||||||
std.debug.print("\x1b[1;32mstack pop:\x1b[0m sp {d}, type {s}\n", .{ self.sp, @typeName(T) });
|
|
||||||
return switch (T) {
|
return switch (T) {
|
||||||
u8 => self.s[self.sp],
|
u8 => {
|
||||||
u16 => @as(u16, @intCast(self.s[self.sp])) << 8 | self.s[self.sp +% 1],
|
const val = self.s[self.sp];
|
||||||
|
if (debug) std.debug.print("\x1b[32mstack pop:\x1b[0m\tsp {d}, type {s}, val {d}\n", .{ self.sp, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
u16 => {
|
||||||
|
const val = @as(u16, @intCast(self.s[self.sp])) << 8 | self.s[self.sp +% 1];
|
||||||
|
if (debug) std.debug.print("\x1b[32mstack pop:\x1b[0m\tsp {d}, type {s}, val {d}\n", .{ self.sp, @typeName(T), val });
|
||||||
|
return val;
|
||||||
|
},
|
||||||
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
else => @compileError("expected u8 or u16, got " + @typeName(T)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(self: *Stack, comptime T: type, v: T) void {
|
pub fn push(self: *Stack, comptime T: type, v: T) void {
|
||||||
std.debug.print("\x1b[1;32mstack push:\x1b[0m sp {d}, type {s}\n", .{ self.sp, @typeName(T) });
|
if (debug) std.debug.print("\x1b[32mstack push:\x1b[0m\tsp {d}, type {s}, value {d}\n", .{ self.sp, @typeName(T), v });
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u8 => self.s[self.sp] = v,
|
u8 => self.s[self.sp] = v,
|
||||||
u16 => {
|
u16 => {
|
||||||
|
@ -113,7 +160,7 @@ test "stack poke/peek/push/pop" {
|
||||||
|
|
||||||
pub fn eval(self: *Uxn) bool {
|
pub fn eval(self: *Uxn) bool {
|
||||||
switch (self.mem.m[self.pc]) {
|
switch (self.mem.m[self.pc]) {
|
||||||
0x00 => return true, // BRK
|
0x00 => return false, // BRK
|
||||||
0x01 => inc(&self.ws, u8, false), // INC
|
0x01 => inc(&self.ws, u8, false), // INC
|
||||||
0x02 => pop(&self.ws, u8, false), // POP
|
0x02 => pop(&self.ws, u8, false), // POP
|
||||||
0x03 => nip(&self.ws, u8, false), // NIP
|
0x03 => nip(&self.ws, u8, false), // NIP
|
||||||
|
@ -256,8 +303,7 @@ pub fn eval(self: *Uxn) bool {
|
||||||
0x7F => sft(&self.rs, u16, false), // SFT2r
|
0x7F => sft(&self.rs, u16, false), // SFT2r
|
||||||
|
|
||||||
0x80 => {
|
0x80 => {
|
||||||
self.ws.push(u8, self.mem.m[self.pc +% 1]);
|
self.ws.push(u8, self.mem.peek(u8, self.pc +% 1));
|
||||||
std.debug.print("LIT: {d}\n", .{self.ws.peek(u8)});
|
|
||||||
self.pc +%= 1;
|
self.pc +%= 1;
|
||||||
}, // LIT
|
}, // LIT
|
||||||
0x81 => inc(&self.ws, u8, true), // INCk
|
0x81 => inc(&self.ws, u8, true), // INCk
|
||||||
|
@ -293,8 +339,7 @@ pub fn eval(self: *Uxn) bool {
|
||||||
0x9F => sft(&self.ws, u8, true), // SFTk
|
0x9F => sft(&self.ws, u8, true), // SFTk
|
||||||
|
|
||||||
0xA0 => {
|
0xA0 => {
|
||||||
self.ws.push(u16, self.mem.m[self.pc +% 1]);
|
self.ws.push(u16, self.mem.peek(u16, self.pc +% 1));
|
||||||
std.debug.print("LIT2: {d}\n", .{self.ws.peek(u16)});
|
|
||||||
self.pc +%= 2;
|
self.pc +%= 2;
|
||||||
}, // LIT2
|
}, // LIT2
|
||||||
0xA1 => inc(&self.ws, u16, true), // INC2k
|
0xA1 => inc(&self.ws, u16, true), // INC2k
|
||||||
|
@ -330,8 +375,7 @@ pub fn eval(self: *Uxn) bool {
|
||||||
0xBF => sft(&self.ws, u16, true), // SFT2k
|
0xBF => sft(&self.ws, u16, true), // SFT2k
|
||||||
|
|
||||||
0xC0 => {
|
0xC0 => {
|
||||||
self.rs.push(u8, self.mem.m[self.pc +% 1]);
|
self.rs.push(u8, self.mem.peek(u8, self.pc +% 1));
|
||||||
std.debug.print("LITr: {d}\n", .{self.rs.peek(u8)});
|
|
||||||
self.pc +%= 1;
|
self.pc +%= 1;
|
||||||
}, // LITr
|
}, // LITr
|
||||||
0xC1 => inc(&self.rs, u8, true), // INCkr
|
0xC1 => inc(&self.rs, u8, true), // INCkr
|
||||||
|
@ -367,8 +411,7 @@ pub fn eval(self: *Uxn) bool {
|
||||||
0xDF => sft(&self.rs, u8, true), // SFTkr
|
0xDF => sft(&self.rs, u8, true), // SFTkr
|
||||||
|
|
||||||
0xE0 => {
|
0xE0 => {
|
||||||
self.rs.push(u16, self.mem.m[self.pc +% 1]);
|
self.rs.push(u16, self.mem.peek(u16, self.pc +% 1));
|
||||||
std.debug.print("LIT2r: {d}\n", .{self.rs.peek(u16)});
|
|
||||||
self.pc +%= 2;
|
self.pc +%= 2;
|
||||||
}, // LIT2r
|
}, // LIT2r
|
||||||
0xE1 => inc(&self.rs, u16, true), // INC2kr
|
0xE1 => inc(&self.rs, u16, true), // INC2kr
|
||||||
|
@ -405,7 +448,7 @@ pub fn eval(self: *Uxn) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pc +%= 1;
|
self.pc +%= 1;
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn brk() void {}
|
fn brk() void {}
|
||||||
|
@ -565,7 +608,7 @@ fn dei(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void {
|
||||||
fn deo(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void {
|
fn deo(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void {
|
||||||
const d = if (keep) stack.peek(u8) else stack.pop(u8);
|
const d = if (keep) stack.peek(u8) else stack.pop(u8);
|
||||||
const v = if (keep) stack.peek(T) else stack.pop(T);
|
const v = if (keep) stack.peek(T) else stack.pop(T);
|
||||||
std.debug.print("DEO: dev {X}, val {X}\n", .{ d, v });
|
if (debug) std.debug.print("DEO: dev {X}, val {X}\n", .{ d, v });
|
||||||
switch (T) {
|
switch (T) {
|
||||||
u8 => {
|
u8 => {
|
||||||
self.dev[d] = v;
|
self.dev[d] = v;
|
||||||
|
@ -640,24 +683,30 @@ fn sft(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test "arithmetic instructions" {
|
test "op" {
|
||||||
// var uxn = Uxn{
|
var uxn = try Uxn.init(std.testing.allocator);
|
||||||
// .mem = .{ .m = undefined },
|
defer uxn.deinit(std.testing.allocator);
|
||||||
// .ws = .{ .s = undefined },
|
|
||||||
// .rs = .{ .s = undefined },
|
const rom = [_]u8{
|
||||||
// .pc = 0,
|
0x01, 0x01, 0x01, 0x01,
|
||||||
// };
|
0x00,
|
||||||
// uxn.mem.m[0] = 0x18;
|
};
|
||||||
// uxn.mem.m[1] = 0x19;
|
@memcpy(uxn.mem.m[0x100 .. rom.len + 0x100], &rom);
|
||||||
// uxn.mem.m[2] = 0x1A;
|
|
||||||
// uxn.mem.m[3] = 0x1B;
|
std.debug.print("op.inc\n", .{});
|
||||||
// uxn.ws.push(u8, 4);
|
uxn.ws.push(u8, 0x01);
|
||||||
// uxn.ws.push(u8, 20);
|
uxn.ws.push(u8, 0xff);
|
||||||
// uxn.ws.push(u8, 6);
|
uxn.ws.push(u8, 0xfe);
|
||||||
// uxn.loop();
|
uxn.ws.push(u8, 0x00);
|
||||||
// uxn.loop();
|
_ = uxn.eval();
|
||||||
// try std.testing.expectEqual(18, uxn.ws.pop(u8));
|
try std.testing.expectEqual(0x01, uxn.ws.pop(u8));
|
||||||
// }
|
_ = uxn.eval();
|
||||||
|
try std.testing.expectEqual(0xff, uxn.ws.pop(u8));
|
||||||
|
_ = uxn.eval();
|
||||||
|
try std.testing.expectEqual(0x00, uxn.ws.pop(u8));
|
||||||
|
_ = uxn.eval();
|
||||||
|
try std.testing.expectEqual(0x02, uxn.ws.pop(u8));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn formatInstruction(
|
pub fn formatInstruction(
|
||||||
bytes: []const u8,
|
bytes: []const u8,
|
||||||
|
@ -667,55 +716,60 @@ pub fn formatInstruction(
|
||||||
) !void {
|
) !void {
|
||||||
_ = fmt;
|
_ = fmt;
|
||||||
_ = options;
|
_ = options;
|
||||||
|
if (!debug) return;
|
||||||
std.debug.assert(bytes.len == 1);
|
std.debug.assert(bytes.len == 1);
|
||||||
switch (bytes[0] & 0x1F) {
|
try writer.writeAll("\x1b[1;31m");
|
||||||
0x00 => return switch (bytes[0]) {
|
instr: {
|
||||||
0x00 => try writer.writeAll("BRK"),
|
switch (bytes[0] & 0x1F) {
|
||||||
0x20 => try writer.writeAll("JCI"),
|
0x00 => break :instr switch (bytes[0]) {
|
||||||
0x40 => try writer.writeAll("JMI"),
|
0x00 => try writer.writeAll("BRK"),
|
||||||
0x60 => try writer.writeAll("JSI"),
|
0x20 => try writer.writeAll("JCI"),
|
||||||
0x80 => try writer.writeAll("LIT"),
|
0x40 => try writer.writeAll("JMI"),
|
||||||
0xA0 => try writer.writeAll("LIT2"),
|
0x60 => try writer.writeAll("JSI"),
|
||||||
0xC0 => try writer.writeAll("LITr"),
|
0x80 => try writer.writeAll("LIT"),
|
||||||
0xE0 => try writer.writeAll("LIT2r"),
|
0xA0 => try writer.writeAll("LIT2"),
|
||||||
|
0xC0 => try writer.writeAll("LITr"),
|
||||||
|
0xE0 => try writer.writeAll("LIT2r"),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
0x01 => try writer.writeAll("INC"),
|
||||||
|
0x02 => try writer.writeAll("POP"),
|
||||||
|
0x03 => try writer.writeAll("NIP"),
|
||||||
|
0x04 => try writer.writeAll("SWP"),
|
||||||
|
0x05 => try writer.writeAll("ROT"),
|
||||||
|
0x06 => try writer.writeAll("DUP"),
|
||||||
|
0x07 => try writer.writeAll("OVR"),
|
||||||
|
0x08 => try writer.writeAll("EQU"),
|
||||||
|
0x09 => try writer.writeAll("NEQ"),
|
||||||
|
0x0A => try writer.writeAll("GTH"),
|
||||||
|
0x0B => try writer.writeAll("LTH"),
|
||||||
|
0x0C => try writer.writeAll("JMP"),
|
||||||
|
0x0D => try writer.writeAll("JCN"),
|
||||||
|
0x0E => try writer.writeAll("JSR"),
|
||||||
|
0x0F => try writer.writeAll("STH"),
|
||||||
|
0x10 => try writer.writeAll("LDZ"),
|
||||||
|
0x11 => try writer.writeAll("STZ"),
|
||||||
|
0x12 => try writer.writeAll("LDR"),
|
||||||
|
0x13 => try writer.writeAll("STR"),
|
||||||
|
0x14 => try writer.writeAll("LDA"),
|
||||||
|
0x15 => try writer.writeAll("STA"),
|
||||||
|
0x16 => try writer.writeAll("DEI"),
|
||||||
|
0x17 => try writer.writeAll("DEO"),
|
||||||
|
0x18 => try writer.writeAll("ADD"),
|
||||||
|
0x19 => try writer.writeAll("SUB"),
|
||||||
|
0x1A => try writer.writeAll("MUL"),
|
||||||
|
0x1B => try writer.writeAll("DIV"),
|
||||||
|
0x1C => try writer.writeAll("AND"),
|
||||||
|
0x1D => try writer.writeAll("ORA"),
|
||||||
|
0x1E => try writer.writeAll("EOR"),
|
||||||
|
0x1F => try writer.writeAll("SFT"),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
}
|
||||||
0x01 => try writer.writeAll("INC"),
|
if (bytes[0] & 0x20 == 0x20) try writer.writeByte('2');
|
||||||
0x02 => try writer.writeAll("POP"),
|
if (bytes[0] & 0x40 == 0x40) try writer.writeByte('k');
|
||||||
0x03 => try writer.writeAll("NIP"),
|
if (bytes[0] & 0x80 == 0x80) try writer.writeByte('r');
|
||||||
0x04 => try writer.writeAll("SWP"),
|
|
||||||
0x05 => try writer.writeAll("ROT"),
|
|
||||||
0x06 => try writer.writeAll("DUP"),
|
|
||||||
0x07 => try writer.writeAll("OVR"),
|
|
||||||
0x08 => try writer.writeAll("EQU"),
|
|
||||||
0x09 => try writer.writeAll("NEQ"),
|
|
||||||
0x0A => try writer.writeAll("GTH"),
|
|
||||||
0x0B => try writer.writeAll("LTH"),
|
|
||||||
0x0C => try writer.writeAll("JMP"),
|
|
||||||
0x0D => try writer.writeAll("JCN"),
|
|
||||||
0x0E => try writer.writeAll("JSR"),
|
|
||||||
0x0F => try writer.writeAll("STH"),
|
|
||||||
0x10 => try writer.writeAll("LDZ"),
|
|
||||||
0x11 => try writer.writeAll("STZ"),
|
|
||||||
0x12 => try writer.writeAll("LDR"),
|
|
||||||
0x13 => try writer.writeAll("STR"),
|
|
||||||
0x14 => try writer.writeAll("LDA"),
|
|
||||||
0x15 => try writer.writeAll("STA"),
|
|
||||||
0x16 => try writer.writeAll("DEI"),
|
|
||||||
0x17 => try writer.writeAll("DEO"),
|
|
||||||
0x18 => try writer.writeAll("ADD"),
|
|
||||||
0x19 => try writer.writeAll("SUB"),
|
|
||||||
0x1A => try writer.writeAll("MUL"),
|
|
||||||
0x1B => try writer.writeAll("DIV"),
|
|
||||||
0x1C => try writer.writeAll("AND"),
|
|
||||||
0x1D => try writer.writeAll("ORA"),
|
|
||||||
0x1E => try writer.writeAll("EOR"),
|
|
||||||
0x1F => try writer.writeAll("SFT"),
|
|
||||||
else => unreachable,
|
|
||||||
}
|
}
|
||||||
if (bytes[0] & 0x20 == 0x20) try writer.writeByte('2');
|
try writer.writeAll("\x1b[0m");
|
||||||
if (bytes[0] & 0x40 == 0x40) try writer.writeByte('k');
|
|
||||||
if (bytes[0] & 0x80 == 0x80) try writer.writeByte('r');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fmtInstrs(bytes: []const u8) std.fmt.Formatter(formatInstruction) {
|
pub fn fmtInstrs(bytes: []const u8) std.fmt.Formatter(formatInstruction) {
|
||||||
|
|
|
@ -5,36 +5,57 @@ const Varvara = @This();
|
||||||
|
|
||||||
uxn: Uxn,
|
uxn: Uxn,
|
||||||
|
|
||||||
pub fn init(rom: []const u8) Varvara {
|
allocator: std.mem.Allocator,
|
||||||
var uxn = Uxn{ .pc = 0x100 };
|
metadata: ?[]const u8 = null,
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator, rom: []const u8) !Varvara {
|
||||||
|
var uxn = try Uxn.init(allocator);
|
||||||
|
uxn.deo8 = deo8;
|
||||||
|
uxn.deo16 = deo16;
|
||||||
|
uxn.dei8 = dei8;
|
||||||
|
uxn.dei16 = dei16;
|
||||||
@memcpy(uxn.mem.m[0x100 .. rom.len + 0x100], rom);
|
@memcpy(uxn.mem.m[0x100 .. rom.len + 0x100], rom);
|
||||||
return .{ .uxn = uxn };
|
return .{ .uxn = uxn, .allocator = allocator };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Varvara) void {
|
||||||
|
self.uxn.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deo8(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u8) void {
|
pub fn deo8(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u8) void {
|
||||||
const self: Varvara = @fieldParentPtr("uxn", uxn);
|
const self: *Varvara = @fieldParentPtr("uxn", uxn);
|
||||||
// _ = .{ self, stack, device, value };
|
_ = .{ self, stack, device, value };
|
||||||
_ = self;
|
switch (device) { // Console/write
|
||||||
_ = stack;
|
|
||||||
switch (device) {
|
|
||||||
0x18 => {
|
0x18 => {
|
||||||
std.io.getStdOut().writer().writeByte(value) catch |e| @panic(e);
|
std.io.getStdOut().writer().writeByte(value) catch |e| @panic(@errorName(e));
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deo16(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u16) void {
|
pub fn deo16(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u16) void {
|
||||||
const self: Varvara = @fieldParentPtr("uxn", uxn);
|
const self: *Varvara = @fieldParentPtr("uxn", uxn);
|
||||||
_ = .{ self, stack, device, value };
|
_ = .{ self, stack, device, value };
|
||||||
|
switch (device) {
|
||||||
|
0x06, 0x07 => { // System/metadata
|
||||||
|
self.metadata = std.mem.span(@as([*:0]const u8, @ptrCast(&uxn.mem.m[value +% 1])));
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dei8(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u8) void {
|
pub fn dei8(uxn: *Uxn, stack: *Uxn.Stack, device: u8) void {
|
||||||
const self: Varvara = @fieldParentPtr("uxn", uxn);
|
const self: *Varvara = @fieldParentPtr("uxn", uxn);
|
||||||
_ = .{ self, stack, device, value };
|
_ = .{ self, stack, device };
|
||||||
|
switch (device) {
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dei16(uxn: *Uxn, stack: *Uxn.Stack, device: u8, value: u16) void {
|
pub fn dei16(uxn: *Uxn, stack: *Uxn.Stack, device: u8) void {
|
||||||
const self: Varvara = @fieldParentPtr("uxn", uxn);
|
const self: *Varvara = @fieldParentPtr("uxn", uxn);
|
||||||
_ = .{ self, stack, device, value };
|
_ = .{ self, stack, device };
|
||||||
|
switch (device) {
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue