Skip to content

Commit

Permalink
more tail
Browse files Browse the repository at this point in the history
  • Loading branch information
190n committed May 16, 2024
1 parent 0761620 commit 5fa2502
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 32 deletions.
30 changes: 21 additions & 9 deletions src/bench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ const std = @import("std");

const Cpu = @import("./tail.zig").Cpu;

// pub const std_options = std.Options{
// .log_level = .warn,
// };

pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const allocator = arena.allocator();
Expand All @@ -19,16 +15,19 @@ pub fn main() !void {

const rom = try std.fs.cwd().readFileAlloc(allocator, argv[1], 4096 - 512);
defer allocator.free(rom);
var instructions = try std.fmt.parseInt(usize, argv[2], 10);
const instructions = try std.fmt.parseInt(usize, argv[2], 10);
var instructions_remaining = instructions;

var cpu = Cpu.init(rom);

const before = std.posix.getrusage(std.posix.rusage.SELF);

while (instructions > 0) {
const to_run = @min(instructions, std.math.maxInt(u16));
while (instructions_remaining > 0) {
// const to_run = @min(instructions_remaining, std.math.maxInt(u16));
const to_run = 250;
cpu.run(to_run);
instructions -= to_run;
cpu.timerTick();
instructions_remaining -|= to_run;
}

const after = std.posix.getrusage(std.posix.rusage.SELF);
Expand All @@ -40,6 +39,19 @@ pub fn main() !void {
const ins_per_sec = @as(f64, @floatFromInt(instructions)) / total_cpu_time;

var s: [64]u8 = undefined;
const written = try std.fmt.bufPrint(&s, "{}", .{std.fmt.fmtIntSizeDec(@intFromFloat(ins_per_sec))});
const written = try std.fmt.bufPrint(&s, "{}", .{std.fmt.fmtIntSizeDec(std.math.lossyCast(u64, ins_per_sec))});
std.debug.print("{s} ins/sec\n", .{written[0 .. written.len - 1]});

for (0..32) |y| {
for (0..64) |x| {
const pix: u1 = @truncate(cpu.display[(64 * y + x) / 8] >> @truncate(x));
std.debug.print("{s}", .{
if (pix == 0)
" "
else
"##",
});
}
std.debug.print("\n", .{});
}
}
29 changes: 20 additions & 9 deletions src/tail.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub const Cpu = struct {
mem: [4096]u8,
code: [4096]Inst,
instructions: u16 = 0,
dt: u8 = 0,
st: u8 = 0,
random: std.rand.DefaultPrng,

pub fn init(rom: []const u8) Cpu {
Expand All @@ -30,14 +32,19 @@ pub const Cpu = struct {
@memcpy(cpu.mem[0x200..][0..rom.len], rom);
@memset(cpu.mem[0x200 + rom.len ..], 0);
@memset(&cpu.display, 0);
@memset(&cpu.code, .{ .func = &decode, .decoded = undefined });
@memset(&cpu.code, .{ .func = &decode, .decoded = .{ .none = {} } });
return cpu;
}

pub fn run(self: *Cpu, instructions: u16) void {
self.instructions = instructions;
self.code[self.pc].func(self, self.code[self.pc].decoded.toInt());
}

pub fn timerTick(self: *Cpu) void {
self.dt -|= 1;
self.st -|= 1;
}
};

const GadgetFunc = *const fn (*Cpu, u32) void;
Expand All @@ -47,6 +54,7 @@ pub const Decoded = union {
xnn: struct { u4, u8 },
nnn: u12,
xyn: [3]u4,
none: void,

pub const Int = @Type(.{ .Int = .{
.signedness = .unsigned,
Expand Down Expand Up @@ -93,17 +101,17 @@ pub fn decode(cpu: *Cpu, _: Decoded.Int) void {
const opcode = std.mem.readInt(u16, cpu.mem[cpu.pc..][0..2], .big);
const inst: Inst = switch (@as(u4, @truncate(opcode >> 12))) {
0x0 => switch (opcode & 0xff) {
0xE0 => .{ .func = &tailfuncs.clear, .decoded = undefined },
0xEE => .{ .func = &tailfuncs.ret, .decoded = undefined },
else => .{ .func = &invalid, .decoded = undefined },
0xE0 => .{ .func = &tailfuncs.clear, .decoded = .{ .none = {} } },
0xEE => .{ .func = &tailfuncs.ret, .decoded = .{ .none = {} } },
else => .{ .func = &invalid, .decoded = .{ .none = {} } },
},
0x1 => .{ .func = &tailfuncs.jump, .decoded = Decoded.decode(opcode, .nnn) },
0x2 => .{ .func = &tailfuncs.call, .decoded = Decoded.decode(opcode, .nnn) },
0x3 => .{ .func = &tailfuncs.skipIfEqual, .decoded = Decoded.decode(opcode, .xnn) },
0x4 => .{ .func = &tailfuncs.skipIfNotEqual, .decoded = Decoded.decode(opcode, .xnn) },
0x5 => switch (opcode & 0xf) {
0x0 => .{ .func = &tailfuncs.skipIfRegistersEqual, .decoded = Decoded.decode(opcode, .xy) },
else => .{ .func = &invalid, .decoded = undefined },
else => .{ .func = &invalid, .decoded = .{ .none = {} } },
},
0x6 => .{ .func = &tailfuncs.setRegister, .decoded = Decoded.decode(opcode, .xnn) },
0x7 => .{ .func = &tailfuncs.addImmediate, .decoded = Decoded.decode(opcode, .xnn) },
Expand All @@ -124,7 +132,7 @@ pub fn decode(cpu: *Cpu, _: Decoded.Int) void {
},
0x9 => switch (opcode & 0xf) {
0x0 => .{ .func = &tailfuncs.skipIfRegistersNotEqual, .decoded = Decoded.decode(opcode, .xy) },
else => .{ .func = &invalid, .decoded = undefined },
else => .{ .func = &invalid, .decoded = .{ .none = {} } },
},
0xA => .{ .func = &tailfuncs.setI, .decoded = Decoded.decode(opcode, .nnn) },
0xB => .{ .func = &tailfuncs.jumpV0, .decoded = Decoded.decode(opcode, .nnn) },
Expand All @@ -133,7 +141,7 @@ pub fn decode(cpu: *Cpu, _: Decoded.Int) void {
0xE => switch (opcode & 0xff) {
0x9E => .{ .func = &tailfuncs.skipIfPressed, .decoded = Decoded.decode(opcode, .xnn) },
0xA1 => .{ .func = &tailfuncs.skipIfNotPressed, .decoded = Decoded.decode(opcode, .xnn) },
else => .{ .func = &invalid, .decoded = undefined },
else => .{ .func = &invalid, .decoded = .{ .none = {} } },
},
0xF => .{
.func = switch (opcode & 0xff) {
Expand All @@ -159,7 +167,10 @@ pub fn decode(cpu: *Cpu, _: Decoded.Int) void {

fn invalid(cpu: *Cpu, _: Decoded.Int) void {
std.debug.panic(
"invalid instruction: {x:0>4}",
.{std.mem.readInt(u16, cpu.mem[cpu.pc..][0..2], .big)},
"invalid instruction: {X:0>4} at 0x{X:0>3}",
.{
std.mem.readInt(u16, cpu.mem[cpu.pc..][0..2], .big),
cpu.pc,
},
);
}
48 changes: 34 additions & 14 deletions src/tailfuncs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ inline fn cont(cpu: *Cpu, comptime inc_by_2: bool) void {

/// 00E0: clear the screen
pub fn clear(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
_ = Decoded.fromInt(decoded).none;
@memset(&cpu.display, 0);
cont(cpu, true);
}

/// 00EE: return
pub fn ret(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
_ = Decoded.fromInt(decoded).none;
cpu.pc = cpu.stack.popOrNull() orelse @panic("empty stack");
cont(cpu, false);
}
Expand Down Expand Up @@ -127,8 +127,10 @@ pub fn shiftRight(cpu: *Cpu, decoded: Decoded.Int) void {

/// 8XY7: set VX to VY - VX; set VF to 0 if borrow occurred, 1 otherwise
pub fn subRegistersReverse(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
std.debug.panic("subRegistersReverse at {x:0>3}", .{cpu.pc});
const x, const y = Decoded.fromInt(decoded).xy;
cpu.v[x], const overflow = @subWithOverflow(cpu.v[y], cpu.v[x]);
cpu.v[0xF] = ~overflow;
cont(cpu, true);
}

/// 8XYE: set VX to VY << 1, set VF to the former most significant bit of VY
Expand Down Expand Up @@ -168,9 +170,25 @@ pub fn random(cpu: *Cpu, decoded: Decoded.Int) void {
/// DXYN: draw an 8xN sprite from memory starting at I at (VX, VY); set VF to 1 if any pixel was
/// turned off, 0 otherwise
pub fn draw(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
// std.debug.panic("draw at {x:0>3}, {} to go", .{ cpu.pc, cpu.instructions });
std.log.warn("draw", .{});
const x_reg, const y_reg, const n = Decoded.fromInt(decoded).xyn;
const x: u16 = cpu.v[x_reg] % 64;
const y: u16 = cpu.v[y_reg] % 32;
var intersect: u8 = 0;
for (0..@min(n, 32 - y)) |row| {
const left = @bitReverse(cpu.mem[cpu.i + row]) << @truncate(x % 8);
const right = if (x % 8 == 0)
0
else
@bitReverse(cpu.mem[cpu.i + row]) >> @truncate(8 - (x % 8));
const index = (64 * (y + row) + x) / 8;
intersect |= (cpu.display[index] & left);
cpu.display[index] ^= left;
if (x < 56) {
intersect |= (cpu.display[index + 1] & right);
cpu.display[index + 1] ^= right;
}
}
cpu.v[0xF] = @intFromBool(intersect != 0);
cont(cpu, true);
}

Expand All @@ -188,8 +206,9 @@ pub fn skipIfNotPressed(cpu: *Cpu, decoded: Decoded.Int) void {

/// FX07: store the value of the delay timer in VX
pub fn readDt(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
std.debug.panic("readDt at {x:0>3}", .{cpu.pc});
const x, _ = Decoded.fromInt(decoded).xnn;
cpu.v[x] = cpu.dt;
cont(cpu, true);
}

/// FX0A: wait until any key is pressed, then store the key that was pressed in VX
Expand All @@ -200,8 +219,9 @@ pub fn waitForKey(cpu: *Cpu, decoded: Decoded.Int) void {

/// FX15: set the delay timer to the value of VX
pub fn setDt(cpu: *Cpu, decoded: Decoded.Int) void {
_ = decoded;
std.debug.panic("setDt at {x:0>3}", .{cpu.pc});
const x, _ = Decoded.fromInt(decoded).xnn;
cpu.dt = cpu.v[x];
cont(cpu, true);
}

/// FX18: set the sound timer to the value of VX
Expand Down Expand Up @@ -237,16 +257,16 @@ pub fn storeBcd(cpu: *Cpu, decoded: Decoded.Int) void {

/// FX55: store registers [V0, VX] in memory starting at I; set I to I + X + 1
pub fn store(cpu: *Cpu, decoded: Decoded.Int) void {
const x, _ = Decoded.fromInt(decoded).xnn;
const x: u8, _ = Decoded.fromInt(decoded).xnn;
@memcpy(cpu.mem[cpu.i..][0 .. x + 1], cpu.v[0 .. x + 1]);
@memset(cpu.code[cpu.i..][0 .. x + 1], .{ .func = &tail.decode, .decoded = undefined });
@memset(cpu.code[cpu.i - 1 ..][0 .. x + 2], .{ .func = &tail.decode, .decoded = undefined });
cpu.i = cpu.i + x + 1;
cont(cpu, true);
}

/// FX65: load values from memory starting at I into registers [V0, VX]; set I to I + X + 1
pub fn load(cpu: *Cpu, decoded: Decoded.Int) void {
const x, _ = Decoded.fromInt(decoded).xnn;
const x: u8, _ = Decoded.fromInt(decoded).xnn;
@memcpy(cpu.v[0 .. x + 1], cpu.mem[cpu.i .. cpu.i + x + 1]);
cpu.i = cpu.i + x + 1;
cont(cpu, true);
Expand Down

0 comments on commit 5fa2502

Please sign in to comment.