Skip to content

Commit d22556b

Browse files
committed
fixes for zig 0.12 (except AVR)
1 parent 5a00f0c commit d22556b

File tree

8 files changed

+104
-56
lines changed

8 files changed

+104
-56
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
zig-cache
22
zig-out
3+
.vscode

build.zig

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ pub fn build(b: *std.Build) void {
1313
// Standard optimization options allow the person running `zig build` to select
1414
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
1515
// set a preferred release mode, allowing the user to decide how to optimize.
16-
const optimize = b.standardOptimizeOption(.{});
16+
const optimize = b.standardOptimizeOption(.{
17+
.preferred_optimize_mode = .ReleaseSmall,
18+
});
1719

1820
const use_avr_gcc = b.option(
1921
bool,
@@ -44,23 +46,27 @@ pub fn build(b: *std.Build) void {
4446
.target = target,
4547
.optimize = optimize,
4648
});
47-
native_library.addModule("build_options", options_module);
48-
const native_library_install = b.addInstallLibFile(native_library.getEmittedBin(), "libzip8.a");
49+
native_library.root_module.addImport("build_options", options_module);
50+
const native_library_install = b.addInstallLibFile(
51+
native_library.getEmittedBin(),
52+
b.fmt("libzip8{s}", .{target.result.dynamicLibSuffix()}),
53+
);
4954

50-
const wasm_library = b.addSharedLibrary(.{
55+
const wasm_library = b.addExecutable(.{
5156
.name = "zip8",
5257
// In this case the main source file is merely a path, however, in more
5358
// complicated build scripts, this could be a generated file.
5459
.root_source_file = .{ .path = "src/main.zig" },
55-
.target = .{
60+
.target = b.resolveTargetQuery(.{
5661
.cpu_arch = .wasm32,
5762
.os_tag = .freestanding,
5863
.cpu_features_add = std.Target.wasm.featureSet(&.{.bulk_memory}),
59-
},
64+
}),
6065
.optimize = optimize,
6166
});
67+
wasm_library.entry = .disabled;
68+
wasm_library.root_module.addImport("build_options", options_module);
6269
wasm_library.rdynamic = true;
63-
wasm_library.addModule("build_options", options_module);
6470

6571
const wasm_step = b.step("wasm", "Build WebAssembly library");
6672

@@ -91,49 +97,46 @@ pub fn build(b: *std.Build) void {
9197
// In this case the main source file is merely a path, however, in more
9298
// complicated build scripts, this could be a generated file.
9399
.root_source_file = .{ .path = "src/main.zig" },
94-
.target = .{
100+
.target = b.resolveTargetQuery(.{
95101
.cpu_arch = .thumb,
96102
.os_tag = .freestanding,
97103
.abi = .eabi,
98104
.cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m0plus },
99-
},
105+
}),
100106
.optimize = optimize,
101107
});
102-
m0plus_library.addModule("build_options", options_module);
108+
m0plus_library.root_module.addImport("build_options", options_module);
103109
const m0plus_library_install = b.addInstallLibFile(m0plus_library.getEmittedBin(), "cortex-m0plus/libzip8.a");
104110

105111
// build a static library for AVR
106112
const atmega4809_library = b.addStaticLibrary(.{
107113
.name = "zip8",
108114
.root_source_file = .{ .path = "src/main.zig" },
109-
.target = .{
115+
.target = b.resolveTargetQuery(.{
110116
.cpu_arch = .avr,
111117
.os_tag = .freestanding,
112118
.cpu_model = .{ .explicit = &std.Target.avr.cpu.atmega4809 },
113119
.ofmt = if (use_avr_gcc) .c else null,
114-
},
120+
}),
115121
.optimize = optimize,
116122
});
117-
atmega4809_library.addModule("build_options", options_module);
123+
atmega4809_library.root_module.addImport("build_options", options_module);
118124

119125
const atmega4809_library_file = if (use_avr_gcc) bin: {
120-
// we use this to get the lib_dir from our zig installation as that directory contains zig.h
121-
const zig_lib_dir_cmd = b.addSystemCommand(&.{ "sh", "-c", "$0 env | jq -r .lib_dir", b.zig_exe });
122-
const zig_lib_dir_file = zig_lib_dir_cmd.captureStdOut();
123-
124126
const gcc_cmd = b.addSystemCommand(&.{
125127
"sh",
126128
"-c",
127-
"avr-gcc -c -Wno-incompatible-pointer-types -Wno-builtin-declaration-mismatch -mmcu=atmega4809 $0 -I $(cat $1) $2 -o $3",
129+
"avr-gcc -c -Wno-incompatible-pointer-types -Wno-builtin-declaration-mismatch -mmcu=atmega4809 $0 -I $1 $2 -o $3",
128130
switch (optimize) {
129131
.Debug => "-g",
130132
.ReleaseSafe => "-O3",
131133
.ReleaseFast => "-O3",
132134
.ReleaseSmall => "-Oz",
133135
},
134136
});
135-
gcc_cmd.addFileArg(zig_lib_dir_file);
137+
gcc_cmd.addArg(b.lib_dir);
136138
gcc_cmd.addFileArg(atmega4809_library.getEmittedBin());
139+
137140
const avr_object_path = gcc_cmd.addOutputFileArg("zip8.o");
138141

139142
const ar_cmd = b.addSystemCommand(&.{ "ar", "-rcs" });
@@ -150,8 +153,8 @@ pub fn build(b: *std.Build) void {
150153
const write_files_step = b.addWriteFiles();
151154
_ = write_files_step.addCopyFile(m0plus_library.getEmittedBin(), "zip8/src/cortex-m0plus/libzip8.a");
152155
_ = write_files_step.addCopyFile(atmega4809_library_file, "zip8/src/atmega4809/libzip8.a");
153-
_ = write_files_step.addCopyFile(std.build.LazyPath.relative("src/zip8.h"), "zip8/src/zip8.h");
154-
_ = write_files_step.addCopyFile(std.build.LazyPath.relative("library.properties"), "zip8/library.properties");
156+
_ = write_files_step.addCopyFile(b.path("src/zip8.h"), "zip8/src/zip8.h");
157+
_ = write_files_step.addCopyFile(b.path("library.properties"), "zip8/library.properties");
155158
const zip_step = b.addSystemCommand(&.{ "sh", "-c", "cd $0; zip -r $1 zip8" });
156159
zip_step.addDirectoryArg(write_files_step.getDirectory());
157160
const zip_output = zip_step.addOutputFileArg("zip8.zip");
@@ -174,12 +177,12 @@ pub fn build(b: *std.Build) void {
174177
.target = target,
175178
.optimize = optimize,
176179
});
177-
exe_tests.addModule("build_options", options_module);
180+
exe_tests.root_module.addImport("build_options", options_module);
178181

179182
// Similar to creating the run step earlier, this exposes a `test` step to
180183
// the `zig build --help` menu, providing a way for the user to request
181184
// running the unit tests.
182185
const test_step = b.step("test", "Run unit tests");
183-
const test_run_cmd = b.addRunArtifact(exe_tests.step.cast(std.build.Step.Compile).?);
186+
const test_run_cmd = b.addRunArtifact(exe_tests.step.cast(std.Build.Step.Compile).?);
184187
test_step.dependOn(&test_run_cmd.step);
185188
}

src/bindings.zig

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,28 @@ export fn zip8CpuSetFlagsNotDirty(cpu: ?*anyopaque) callconv(.C) void {
107107
cpuPtrCast(cpu).flags_dirty = false;
108108
}
109109

110-
fn zip8CpuAlloc() callconv(.C) ?[*]u8 {
111-
return (std.heap.wasm_allocator.alignedAlloc(u8, @alignOf(Cpu), @sizeOf(Cpu)) catch return null).ptr;
110+
export fn zip8CpuGetDrawBytes(cpu: ?*const anyopaque) callconv(.C) usize {
111+
return cpuPtrCast(cpu).draw_bytes_this_frame;
112112
}
113113

114-
fn wasmAlloc(n: usize) callconv(.C) ?[*]u8 {
115-
return (std.heap.wasm_allocator.alignedAlloc(u8, @import("builtin").target.maxIntAlignment(), n) catch return null).ptr;
114+
export fn zip8CpuResetDrawBytes(cpu: ?*anyopaque) callconv(.C) void {
115+
cpuPtrCast(cpu).draw_bytes_this_frame = 0;
116116
}
117117

118118
comptime {
119119
if (@import("builtin").target.isWasm()) {
120-
@export(zip8CpuAlloc, .{ .name = "zip8CpuAlloc" });
121-
@export(wasmAlloc, .{ .name = "wasmAlloc" });
120+
const wasm_only_functions = struct {
121+
fn zip8CpuAlloc() callconv(.C) ?[*]u8 {
122+
return (std.heap.wasm_allocator.alignedAlloc(u8, @alignOf(Cpu), @sizeOf(Cpu)) catch return null).ptr;
123+
}
124+
125+
fn wasmAlloc(n: usize) callconv(.C) ?[*]u8 {
126+
return (std.heap.wasm_allocator.alignedAlloc(u8, @import("builtin").target.maxIntAlignment(), n) catch return null).ptr;
127+
}
128+
};
129+
130+
@export(wasm_only_functions.zip8CpuAlloc, .{ .name = "zip8CpuAlloc" });
131+
@export(wasm_only_functions.wasmAlloc, .{ .name = "wasmAlloc" });
122132
}
123133
}
124134

src/cpu.zig

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,20 @@ const log = if (@import("builtin").is_test) struct {
3636
V: [16]u8 = .{0} ** 16,
3737
/// 12-bit register I for indexing memory
3838
I: u12 = 0,
39-
/// 4 KiB of memory
40-
mem: [memory_size]u8 = [_]u8{0} ** memory_size,
4139
/// program counter
4240
pc: u12 = initial_pc,
4341
/// call stack
4442
stack: std.BoundedArray(u12, 16),
4543
/// random number generator to use
4644
rand: std.rand.DefaultPrng,
4745

46+
/// 4 KiB of memory
47+
mem: [memory_size]u8 = .{0x00} ** memory_size,
48+
/// track which memory has not been synchronized to clients
49+
mem_dirty: [memory_size / 8]u8 = .{0xff} ** (memory_size / 8),
50+
51+
draw_bytes_this_frame: usize = 0,
52+
4853
/// display is 64x32 stored row-major
4954
display: [display_width * display_height / 8]u8 = .{0} ** (display_width * display_height / 8),
5055
/// whether the contents of the screen have changed since the last time this flag was set to false

src/instruction.zig

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ opcode: u16,
2323

2424
const testing_seed = 1337;
2525

26+
const draw_log = std.log.scoped(.draw);
27+
2628
/// split up an opcode into useful parts
2729
pub fn decode(opcode: u16) Instruction {
2830
const nibbles = [4]u4{
@@ -113,6 +115,8 @@ fn op00EX(self: Instruction, cpu: *Cpu) !?u12 {
113115
0x00E0 => {
114116
@memset(&cpu.display, 0);
115117
cpu.display_dirty = true;
118+
draw_log.info("clear", .{});
119+
cpu.draw_bytes_this_frame += 4;
116120
return null;
117121
},
118122
0x00EE => {
@@ -639,20 +643,16 @@ test "CXNN random" {
639643
try std.testing.expectEqual(@as(u8, 0x00), cpu.V[0x0]);
640644
}
641645

642-
export fn draw(ptr: ?*anyopaque, xReg: u8, yReg: u8, rows: u8) callconv(.C) void {
643-
const cpu: *Cpu = @alignCast(@ptrCast(ptr.?));
644-
const inst = Instruction.decode(0xd000 | (@as(u16, xReg) << 8) | (yReg << 4) | rows);
645-
_ = inst.exec(cpu) catch unreachable;
646-
cpu.pc +%= 2;
647-
}
648-
649646
/// DXYN: draw an 8xN sprite from memory starting at I at (VX, VY); set VF to 1 if any pixel was
650647
/// turned off, 0 otherwise
651648
fn opDraw(self: Instruction, cpu: *Cpu) !?u12 {
652649
cpu.V[0xF] = 0;
653-
const sprite: []const u8 = cpu.mem[(cpu.I)..(cpu.I + self.low4)];
650+
const sprite: []const u8 = cpu.mem[cpu.I..][0..self.low4];
654651
const x_start = cpu.V[self.regX] % Cpu.display_width;
655652
const y_start = cpu.V[self.regY] % Cpu.display_height;
653+
654+
var any_bytes_dirty = false;
655+
656656
for (sprite, 0..) |row, y_sprite| {
657657
for (0..8) |x_sprite| {
658658
const pixel: u1 = @truncate(row >> @intCast(7 - x_sprite));
@@ -668,8 +668,21 @@ fn opDraw(self: Instruction, cpu: *Cpu) !?u12 {
668668
cpu.invertPixel(x, y);
669669
cpu.display_dirty = true;
670670
}
671+
672+
const mem_index = y_sprite + cpu.I;
673+
if ((cpu.mem_dirty[mem_index / 8] >> @truncate(mem_index)) & 0x01 != 0) {
674+
any_bytes_dirty = true;
675+
cpu.mem_dirty[mem_index / 8] ^= (@as(u8, 1) << @truncate(mem_index));
676+
}
671677
}
672678
}
679+
680+
if (any_bytes_dirty) {
681+
draw_log.info("untaint: [{}, {})", .{ cpu.I, cpu.I + self.low4 });
682+
cpu.draw_bytes_this_frame += self.low4;
683+
}
684+
draw_log.info("sprite: {} rows at ({}, {})", .{ sprite.len, x_start, y_start });
685+
cpu.draw_bytes_this_frame += 4;
673686
return null;
674687
}
675688

@@ -934,6 +947,7 @@ fn opStore(self: Instruction, cpu: *Cpu) !?u12 {
934947
for (0..(@as(u8, self.regX) + 1)) |offset| {
935948
cpu.mem[cpu.I] = cpu.V[offset];
936949
cpu.I +%= 1;
950+
cpu.mem_dirty[cpu.I / 8] |= (@as(u8, 1) << @truncate(cpu.I));
937951
}
938952
return null;
939953
}

src/main.zig

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,26 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_
1010
while (true) {}
1111
}
1212

13-
pub const std_options = struct {
14-
pub const log_level = .info;
13+
pub fn logFn(
14+
comptime level: std.log.Level,
15+
comptime scope: @Type(.EnumLiteral),
16+
comptime format: []const u8,
17+
args: anytype,
18+
) void {
19+
const level_prefix = comptime level.asText();
20+
const prefix = comptime level_prefix ++ switch (scope) {
21+
.default => ": ",
22+
else => " (" ++ @tagName(scope) ++ "): ",
23+
};
1524

16-
pub fn logFn(
17-
comptime level: std.log.Level,
18-
comptime scope: @TypeOf(.EnumLiteral),
19-
comptime format: []const u8,
20-
args: anytype,
21-
) void {
22-
const level_prefix = comptime level.asText();
23-
const prefix = comptime level_prefix ++ switch (scope) {
24-
.default => ": ",
25-
else => " (" ++ @tagName(scope) ++ "): ",
26-
};
25+
var buf: [1024:0]u8 = undefined;
26+
const string = std.fmt.bufPrintZ(&buf, prefix ++ format, args) catch &buf;
27+
zip8Log(string.ptr, string.len);
28+
}
2729

28-
var buf: [1024:0]u8 = undefined;
29-
const string = std.fmt.bufPrintZ(&buf, prefix ++ format, args) catch &buf;
30-
zip8Log(string.ptr, string.len);
31-
}
30+
pub const std_options = std.Options{
31+
.log_level = .info,
32+
.logFn = logFn,
3233
};
3334

3435
comptime {

web-host/src/cpu.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ interface Zip8Exports {
3131
zip8CpuFlagsAreDirty(cpuPtr: number): boolean;
3232
zip8CpuSetFlagsNotDirty(cpuPtr: number): void;
3333
zip8CpuAlloc(): number;
34+
zip8CpuGetDrawBytes(cpuPtr: number): number;
35+
zip8CpuResetDrawBytes(cpuPtr: number): void;
3436
wasmAlloc(size: number): number;
3537
}
3638

@@ -202,4 +204,12 @@ export default class CPU {
202204
}
203205
return flags;
204206
}
207+
208+
getDrawBytes(): number {
209+
return this.exports.zip8CpuGetDrawBytes(this.cpuPtr);
210+
}
211+
212+
resetDrawBytes() {
213+
this.exports.zip8CpuResetDrawBytes(this.cpuPtr);
214+
}
205215
}

web-host/src/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ async function run(rom: ArrayBuffer) {
9292
cpu.setKeys(keys);
9393
}
9494

95+
cpu.resetDrawBytes();
96+
9597
if (!cpu.isWaitingForKey()) {
9698
for (let i = 0; i < instructionsPerTick && !halt; i++) {
9799
try {
@@ -116,6 +118,8 @@ async function run(rom: ArrayBuffer) {
116118
localStorage.setItem(key, JSON.stringify(flags));
117119
}
118120
}
121+
122+
console.log(cpu.getDrawBytes());
119123
}
120124

121125
tick();

0 commit comments

Comments
 (0)