2024-04-20 06:05:30 -06:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
pub fn main() !void {
|
|
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
|
|
defer _ = gpa.deinit();
|
|
|
|
const allocator = gpa.allocator();
|
|
|
|
|
|
|
|
var uxn = Uxn{
|
|
|
|
.mem = try allocator.alloc(u8, 0xFFFF),
|
|
|
|
.ws = try allocator.alloc(u8, 0xFF),
|
|
|
|
.rs = try allocator.alloc(u8, 0xFF),
|
|
|
|
.wsp = 0,
|
|
|
|
.rsp = 0,
|
|
|
|
.pc = 0x0100,
|
|
|
|
};
|
|
|
|
defer allocator.free(uxn.mem);
|
|
|
|
defer allocator.free(uxn.ws);
|
|
|
|
defer allocator.free(uxn.rs);
|
|
|
|
|
|
|
|
while (true) uxn.loop();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const Uxn = struct {
|
|
|
|
mem: [0xFFFF]u8,
|
|
|
|
// ws: [0xFF]u8,
|
|
|
|
// rs: [0xFF]u8,
|
|
|
|
// wsp: u8,
|
|
|
|
// rsp: u8,
|
|
|
|
ws: Stack,
|
|
|
|
rs: Stack,
|
|
|
|
pc: u16,
|
|
|
|
|
|
|
|
const Stack = struct {
|
|
|
|
s: *[0xFF]u8,
|
|
|
|
sp: *u8,
|
2024-04-20 10:01:44 -06:00
|
|
|
|
|
|
|
pub fn peek(self: *Stack, comptime T: type) T {
|
|
|
|
return switch (T) {
|
|
|
|
u8 => self.s[self.sp],
|
|
|
|
u16 => @intCast(self.s[self.sp]), // but actually do the conversion
|
|
|
|
else => unreachable,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn poke(self: *Stack, comptime T: type, v: T) void {
|
|
|
|
switch (T) {
|
|
|
|
u8 => self.s[self.sp] = v,
|
|
|
|
u16 => {},
|
|
|
|
else => unreachable,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pop(self: *Stack, comptime T: type) T {
|
|
|
|
switch (T) {
|
|
|
|
u8 => {
|
|
|
|
self.sp -%= 1;
|
|
|
|
return self.s[self.sp +% 1];
|
|
|
|
},
|
|
|
|
u16 => {
|
|
|
|
self.sp -%= 2;
|
|
|
|
return self.s[self.sp +% 1];
|
|
|
|
},
|
|
|
|
else => unreachable,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push(self: *Stack, comptime T: type, v: T) void {
|
|
|
|
switch (T) {
|
|
|
|
u8 => {
|
|
|
|
self.sp +%= 1;
|
|
|
|
self.s[self.sp] = v;
|
|
|
|
},
|
|
|
|
u16 => {
|
|
|
|
self.sp +%= 2;
|
|
|
|
self.s[self.sp] = v;
|
|
|
|
},
|
|
|
|
else => unreachable,
|
|
|
|
}
|
|
|
|
}
|
2024-04-20 06:05:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
pub fn loop(self: *Uxn) void {
|
|
|
|
switch (self.mem[self.pc]) {
|
|
|
|
0x00 => {}, // BRK
|
|
|
|
0x01 => inc(&self.ws, false, false), // INC
|
|
|
|
0x02 => pop(&self.ws, false, false), // POP
|
|
|
|
0x03 => nip(&self.ws, false, false), // NIP
|
|
|
|
0x04 => swp(&self.ws, false, false), // SWP
|
2024-04-20 10:01:44 -06:00
|
|
|
0x05 => rot(&self.ws, false, false), // ROT
|
|
|
|
0x06 => dup(&self.ws, false, false), // DUP
|
|
|
|
0x07 => ovr(&self.ws, false, false), // OVR
|
|
|
|
0x08 => equ(&self.ws, false, false), // EQU
|
|
|
|
0x09 => neq(&self.ws, false, false), // NEQ
|
|
|
|
0x0A => gth(&self.ws, false, false), // GTH
|
|
|
|
0x0B => lth(&self.ws, false, false), // LTH
|
|
|
|
0x0C => self.jmp(&self.ws, u8, false), // JMP
|
|
|
|
0x0D => self.jcn(&self.ws, u8, false), // JCN
|
|
|
|
0x0E => self.jsr(&self.ws, u8, false), // JSR
|
|
|
|
0x0F => self.sth(false, u8, false), // STH
|
2024-04-20 06:05:30 -06:00
|
|
|
0x10 => {}, // LDZ
|
|
|
|
0x11 => {}, // STZ
|
|
|
|
0x12 => {}, // LDR
|
|
|
|
0x13 => {}, // STR
|
|
|
|
0x14 => {}, // LDA
|
|
|
|
0x15 => {}, // STA
|
|
|
|
0x16 => {}, // DEI
|
|
|
|
0x17 => {}, // DEO
|
|
|
|
0x18 => {}, // ADD
|
|
|
|
0x19 => {}, // SUB
|
|
|
|
0x1A => {}, // MUL
|
|
|
|
0x1B => {}, // DIV
|
|
|
|
0x1C => {}, // AND
|
|
|
|
0x1D => {}, // ORA
|
|
|
|
0x1E => {}, // EOR
|
|
|
|
0x1F => {}, // SFT
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn brk() void {}
|
|
|
|
|
2024-04-20 10:01:44 -06:00
|
|
|
fn inc(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
const a = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
stack.push(T, a +% 1);
|
|
|
|
// if (keep) {
|
|
|
|
// stack.s[stack.sp +% 1] = stack.s[stack.sp] +% 1;
|
|
|
|
// stack.sp +%= 1;
|
|
|
|
// } else {
|
|
|
|
// stack.s[stack.sp] +%= 1;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
if (keep) return;
|
|
|
|
_ = stack.pop(T);
|
|
|
|
// if (!keep) {
|
|
|
|
// if (short) stack.sp -%= 2 else stack.sp -%= 1;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn nip(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
const b = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
stack.push(T, b);
|
|
|
|
// if (!keep) {
|
|
|
|
// stack.sp -%= 1;
|
|
|
|
// stack.s[stack.sp] = stack.s[stack.sp +% 1];
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn swp(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);
|
|
|
|
stack.push(T, b);
|
|
|
|
stack.push(T, a);
|
|
|
|
// if (keep) {
|
|
|
|
// stack.s[stack.sp +% 1] = stack.s[stack.sp];
|
|
|
|
// stack.s[stack.sp +% 2] = stack.s[stack.sp -% 1];
|
|
|
|
// } else {
|
|
|
|
// const a = stack.s[stack.sp -% 1];
|
|
|
|
// stack.s[stack.sp -% 1] = stack.s[stack.sp];
|
|
|
|
// stack.sp = a;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rot(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 c = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
stack.push(T, b);
|
|
|
|
stack.push(T, c);
|
|
|
|
stack.push(T, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dup(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
const a = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
stack.push(T, a);
|
|
|
|
// stack.s[stack.sp +% 1] = stack.s[stack.sp];
|
|
|
|
// if (keep) {
|
|
|
|
// stack.s[stack.sp +% 2] = stack.s[stack.sp];
|
|
|
|
// stack.sp +%= 2;
|
|
|
|
// } else stack.sp +%= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ovr(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);
|
|
|
|
stack.push(T, a);
|
|
|
|
stack.push(T, b);
|
|
|
|
stack.push(T, a);
|
|
|
|
// if (keep) {
|
|
|
|
// stack.s[stack.sp +% 1] = stack.s[stack.sp -% 1];
|
|
|
|
// stack.s[stack.sp +% 2] = stack.s[stack.sp];
|
|
|
|
// stack.s[stack.sp +% 3] = stack.s[stack.sp -% 1];
|
|
|
|
// stack.sp +%= 3;
|
|
|
|
// } else {
|
|
|
|
// stack.s[stack.sp +% 1] = stack.s[stack.sp -% 1];
|
|
|
|
// stack.sp +%= 1;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn equ(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);
|
|
|
|
if (a == b) stack.push(T, 1) else stack.push(T, 0);
|
|
|
|
// if (keep) {} else {
|
|
|
|
// if (stack.s[stack.sp -% 1] == stack.s[stack.sp])
|
|
|
|
// stack.s[stack.sp +% 1] = 1
|
|
|
|
// else
|
|
|
|
// stack.s[stack.sp +% 1] = 0;
|
|
|
|
// stack.sp +%= 1;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn neq(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);
|
|
|
|
if (a != b) stack.push(T, 1) else stack.push(T, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gth(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);
|
|
|
|
if (a > b) stack.push(T, 1) else stack.push(T, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lth(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);
|
|
|
|
if (a < b) stack.push(T, 1) else stack.push(T, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)),
|
|
|
|
u16 => self.pc = addr,
|
|
|
|
else => unreachable,
|
2024-04-20 06:05:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-20 10:01:44 -06:00
|
|
|
fn jcn(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
const cond = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
const addr = if (keep) stack.peek(T) else stack.pop(T);
|
|
|
|
if (cond == 0) return;
|
|
|
|
switch (T) {
|
|
|
|
u8 => self.pc +%= @as(i8, @bitCast(addr)),
|
|
|
|
u16 => self.pc = addr,
|
|
|
|
else => unreachable,
|
2024-04-20 06:05:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-20 10:01:44 -06:00
|
|
|
fn jsr(self: *Uxn, stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
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)),
|
|
|
|
u16 => self.pc = addr,
|
|
|
|
else => unreachable,
|
2024-04-20 06:05:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-20 10:01:44 -06:00
|
|
|
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;
|
|
|
|
const a = if (keep) src.peek(T) else src.pop(T);
|
|
|
|
dst.push(T, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ldz(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
2024-04-20 06:05:30 -06:00
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
2024-04-20 10:01:44 -06:00
|
|
|
fn stz(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ldr(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn str(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lda(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sta(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn dei(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deo(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sub(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mul(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn div(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn @"and"(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ora(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn eor(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sft(stack: *Stack, comptime T: type, comptime keep: bool) void {
|
|
|
|
_ = short;
|
|
|
|
}
|
2024-04-20 06:05:30 -06:00
|
|
|
};
|