chore: upgrade to zig v0.15.1
This commit is contained in:
70
build.zig
70
build.zig
@@ -1,35 +1,63 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
// Although this function looks imperative, it does not perform the build
|
||||||
// declaratively construct a build graph that will be executed by an external
|
// directly and instead it mutates the build graph (`b`) that will be then
|
||||||
// runner.
|
// executed by an external runner. The functions in `std.Build` implement a DSL
|
||||||
|
// for defining build steps and express dependencies between them, allowing the
|
||||||
|
// build runner to parallelize the build automatically (and the cache system to
|
||||||
|
// know when a step doesn't need to be re-run).
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
// Standard target options allows the person running `zig build` to choose
|
// Standard target options allow the person running `zig build` to choose
|
||||||
// what target to build for. Here we do not override the defaults, which
|
// what target to build for. Here we do not override the defaults, which
|
||||||
// means any target is allowed, and the default is native. Other options
|
// means any target is allowed, and the default is native. Other options
|
||||||
// for restricting supported target set are available.
|
// for restricting supported target set are available.
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
// Standard optimization options allow the person running `zig build` to select
|
// This creates a module, which represents a collection of source files alongside
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
// some compilation options, such as optimization mode and linked system libraries.
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
// Zig modules are the preferred way of making Zig code available to consumers.
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
// addModule defines a module that we intend to make available for importing
|
||||||
|
// to our consumers. We must give it a name because a Zig package can expose
|
||||||
_ = b.addModule("zba-gdbstub", .{ .root_source_file = b.path("src/lib.zig") });
|
// multiple modules and consumers will need to be able to specify which
|
||||||
|
// module they want to access.
|
||||||
// Creates a step for unit testing. This only builds the test executable
|
const mod = b.addModule("zba_gdbstub", .{
|
||||||
// but does not run it.
|
// The root source file is the "entry point" of this module. Users of
|
||||||
const lib_unit_tests = b.addTest(.{
|
// this module will only be able to access public declarations contained
|
||||||
|
// in this file, which means that if you have declarations that you
|
||||||
|
// intend to expose to consumers that were defined in other files part
|
||||||
|
// of this module, you will have to make sure to re-export them from
|
||||||
|
// the root file.
|
||||||
.root_source_file = b.path("src/lib.zig"),
|
.root_source_file = b.path("src/lib.zig"),
|
||||||
|
// Later on we'll use this module as the root module of a test executable
|
||||||
|
// which requires us to specify a target.
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
// Creates an executable that will run `test` blocks from the provided module.
|
||||||
|
// Here `mod` needs to define a target, which is why earlier we made sure to
|
||||||
|
// set the releative field.
|
||||||
|
const mod_tests = b.addTest(.{
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
|
||||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
// A run step that will run the test executable.
|
||||||
// the `zig build --help` menu, providing a way for the user to request
|
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
// running the unit tests.
|
|
||||||
const test_step = b.step("test", "Run unit tests");
|
// A top level step for running all tests. dependOn can be called multiple
|
||||||
test_step.dependOn(&run_lib_unit_tests.step);
|
// times and since the two run steps do not depend on one another, this will
|
||||||
|
// make the two of them run in parallel.
|
||||||
|
const test_step = b.step("test", "Run tests");
|
||||||
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
|
|
||||||
|
// Just like flags, top level steps are also listed in the `--help` menu.
|
||||||
|
//
|
||||||
|
// The Zig build system is entirely implemented in userland, which means
|
||||||
|
// that it cannot hook into private compiler APIs. All compilation work
|
||||||
|
// orchestrated by the build system will result in other Zig compiler
|
||||||
|
// subcommands being invoked with the right flags defined. You can observe
|
||||||
|
// these invocations when one fails (or you pass a flag to increase
|
||||||
|
// verbosity) to validate assumptions and diagnose problems.
|
||||||
|
//
|
||||||
|
// Lastly, the Zig build system is relatively simple and self-contained,
|
||||||
|
// and reading its source code will allow you to master it.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,26 @@
|
|||||||
//
|
//
|
||||||
// It is redundant to include "zig" in this name because it is already
|
// It is redundant to include "zig" in this name because it is already
|
||||||
// within the Zig package namespace.
|
// within the Zig package namespace.
|
||||||
.name = "zba-gdbstub",
|
.name = .zba_gdbstub,
|
||||||
|
|
||||||
// This is a [Semantic Version](https://semver.org/).
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
// In a future version of Zig it will be used for package deduplication.
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
.version = "0.1.0",
|
.version = "0.0.0",
|
||||||
|
// Together with name, this represents a globally unique package
|
||||||
// This field is optional.
|
// identifier. This field is generated by the Zig toolchain when the
|
||||||
// This is currently advisory only; Zig does not yet do anything
|
// package is first created, and then *never changes*. This allows
|
||||||
// with this value.
|
// unambiguous detection of one package being an updated version of
|
||||||
//.minimum_zig_version = "0.11.0",
|
// another.
|
||||||
|
//
|
||||||
|
// When forking a Zig project, this id should be regenerated (delete the
|
||||||
|
// field and run `zig build`) if the upstream project is still maintained.
|
||||||
|
// Otherwise, the fork is *hostile*, attempting to take control over the
|
||||||
|
// original project's identity. Thus it is recommended to leave the comment
|
||||||
|
// on the following line intact, so that it shows up in code reviews that
|
||||||
|
// modify the field.
|
||||||
|
.fingerprint = 0x8006426818f63728, // Changing this has security and trust implications.
|
||||||
|
// Tracks the earliest Zig version that the package considers to be a
|
||||||
|
// supported use case.
|
||||||
|
.minimum_zig_version = "0.15.1",
|
||||||
// This field is optional.
|
// This field is optional.
|
||||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||||
@@ -27,7 +36,8 @@
|
|||||||
//.example = .{
|
//.example = .{
|
||||||
// // When updating this field to a new URL, be sure to delete the corresponding
|
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||||
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||||
// // the new URL.
|
// // the new URL. If the contents of a URL change this will result in a hash mismatch
|
||||||
|
// // which will prevent zig from using it.
|
||||||
// .url = "https://example.com/foo.tar.gz",
|
// .url = "https://example.com/foo.tar.gz",
|
||||||
//
|
//
|
||||||
// // This is computed from the file contents of the directory of files that is
|
// // This is computed from the file contents of the directory of files that is
|
||||||
@@ -45,14 +55,13 @@
|
|||||||
// // build root. In this case the package's hash is irrelevant and therefore not
|
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||||
// // computed. This field and `url` are mutually exclusive.
|
// // computed. This field and `url` are mutually exclusive.
|
||||||
// .path = "foo",
|
// .path = "foo",
|
||||||
|
//
|
||||||
// // When this is set to `true`, a package is declared to be lazily
|
// // When this is set to `true`, a package is declared to be lazily
|
||||||
// // fetched. This makes the dependency only get fetched if it is
|
// // fetched. This makes the dependency only get fetched if it is
|
||||||
// // actually used.
|
// // actually used.
|
||||||
// .lazy = false,
|
// .lazy = false,
|
||||||
//},
|
//},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Specifies the set of files and directories that are included in this package.
|
// Specifies the set of files and directories that are included in this package.
|
||||||
// Only files and directories listed here are included in the `hash` that
|
// Only files and directories listed here are included in the `hash` that
|
||||||
// is computed for this package. Only files listed here will remain on disk
|
// is computed for this package. Only files listed here will remain on disk
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub const max_len: usize = 0x1000;
|
|||||||
contents: []const u8,
|
contents: []const u8,
|
||||||
|
|
||||||
pub fn from(allocator: Allocator, str: []const u8) !Self {
|
pub fn from(allocator: Allocator, str: []const u8) !Self {
|
||||||
var tokens = std.mem.tokenize(u8, str, "$#");
|
var tokens = std.mem.tokenizeAny(u8, str, "$#");
|
||||||
const contents = tokens.next() orelse return error.InvalidPacket;
|
const contents = tokens.next() orelse return error.InvalidPacket;
|
||||||
|
|
||||||
const chksum_str = tokens.next() orelse return error.MissingCheckSum;
|
const chksum_str = tokens.next() orelse return error.MissingCheckSum;
|
||||||
@@ -63,7 +63,9 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
|
|
||||||
// writes the formatted integer to the buffer, returns a slice to the buffer but we ignore that
|
// writes the formatted integer to the buffer, returns a slice to the buffer but we ignore that
|
||||||
// GDB also expects the bytes to be in the opposite order for whatever reason
|
// GDB also expects the bytes to be in the opposite order for whatever reason
|
||||||
_ = std.fmt.bufPrintIntToSlice(ret[i * 8 ..][0..8], @byteSwap(reg), 16, .lower, .{ .fill = '0', .width = 8 });
|
|
||||||
|
_ = try std.fmt.bufPrint(ret[i * 8 ..][0..8], "{x:0>8}", .{@byteSwap(reg)});
|
||||||
|
// _ = std.fmt.bufPrintIntToSlice(ret[i * 8 ..][0..8], @byteSwap(reg), 16, .lower, .{ .fill = '0', .width = 8 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
},
|
},
|
||||||
'G' => @panic("TODO: Register Write"),
|
'G' => @panic("TODO: Register Write"),
|
||||||
'm' => {
|
'm' => {
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[1..], ",");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[1..], ",");
|
||||||
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
const length_str = tokens.next() orelse return error.InvalidPacket;
|
const length_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
|
|
||||||
@@ -84,14 +86,16 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
while (i < len) : (i += 1) {
|
while (i < len) : (i += 1) {
|
||||||
// writes the formatted integer to the buffer, returns a slice to the buffer but we ignore that
|
// writes the formatted integer to the buffer, returns a slice to the buffer but we ignore that
|
||||||
_ = std.fmt.bufPrintIntToSlice(ret[i * 2 ..][0..2], emu.read(addr + i), 16, .lower, .{ .fill = '0', .width = 2 });
|
|
||||||
|
_ = try std.fmt.bufPrint(ret[i * 2 ..][0..2], "{x:0>2}", .{emu.read(addr + i)});
|
||||||
|
// _ = std.fmt.bufPrintIntToSlice(ret[i * 2 ..][0..2], emu.read(addr + i), 16, .lower, .{ .fill = '0', .width = 2 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{ .alloc = ret };
|
return .{ .alloc = ret };
|
||||||
},
|
},
|
||||||
'M' => {
|
'M' => {
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[1..], ",:");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[1..], ",:");
|
||||||
|
|
||||||
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
const length_str = tokens.next() orelse return error.InvalidPacket;
|
const length_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
@@ -122,7 +126,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
's' => {
|
's' => {
|
||||||
// var tokens = std.mem.tokenize(u8, self.contents[1..], " ");
|
// var tokens = std.mem.tokenizeAny(u8, self.contents[1..], " ");
|
||||||
// const addr = if (tokens.next()) |s| try std.fmt.parseInt(u32, s, 16) else null;
|
// const addr = if (tokens.next()) |s| try std.fmt.parseInt(u32, s, 16) else null;
|
||||||
|
|
||||||
switch (emu.step()) {
|
switch (emu.step()) {
|
||||||
@@ -136,7 +140,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
|
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
'z' => {
|
'z' => {
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[2..], ",");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[2..], ",");
|
||||||
|
|
||||||
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
const addr = try std.fmt.parseInt(u32, addr_str, 16);
|
const addr = try std.fmt.parseInt(u32, addr_str, 16);
|
||||||
@@ -157,7 +161,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Z' => {
|
'Z' => {
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[2..], ",");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[2..], ",");
|
||||||
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
const addr_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
const kind_str = tokens.next() orelse return error.InvalidPacket;
|
const kind_str = tokens.next() orelse return error.InvalidPacket;
|
||||||
|
|
||||||
@@ -166,11 +170,11 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
|
|
||||||
switch (self.contents[1]) {
|
switch (self.contents[1]) {
|
||||||
'0' => {
|
'0' => {
|
||||||
try emu.addBkpt(.Software, addr, kind);
|
try emu.addBkpt(.Software, allocator, addr, kind);
|
||||||
return .{ .static = "OK" };
|
return .{ .static = "OK" };
|
||||||
},
|
},
|
||||||
'1' => {
|
'1' => {
|
||||||
emu.addBkpt(.Hardware, addr, kind) catch |e| {
|
emu.addBkpt(.Hardware, allocator, addr, kind) catch |e| {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
error.OutOfSpace => return .{ .static = "E22" }, // FIXME: which errno?
|
error.OutOfSpace => return .{ .static = "E22" }, // FIXME: which errno?
|
||||||
else => return e,
|
else => return e,
|
||||||
@@ -232,7 +236,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (substr(self.contents[1..], "Xfer:features:read")) {
|
if (substr(self.contents[1..], "Xfer:features:read")) {
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[1..], ":,");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[1..], ":,");
|
||||||
_ = tokens.next(); // Xfer
|
_ = tokens.next(); // Xfer
|
||||||
_ = tokens.next(); // features
|
_ = tokens.next(); // features
|
||||||
_ = tokens.next(); // read
|
_ = tokens.next(); // read
|
||||||
@@ -266,7 +270,7 @@ pub fn parse(self: *Self, allocator: Allocator, state: *Server.State, emu: *Emul
|
|||||||
if (substr(self.contents[1..], "Xfer:memory-map:read")) {
|
if (substr(self.contents[1..], "Xfer:memory-map:read")) {
|
||||||
const mem_map = state.memmap_xml.?;
|
const mem_map = state.memmap_xml.?;
|
||||||
|
|
||||||
var tokens = std.mem.tokenize(u8, self.contents[1..], ":,");
|
var tokens = std.mem.tokenizeAny(u8, self.contents[1..], ":,");
|
||||||
_ = tokens.next(); // Xfer
|
_ = tokens.next(); // Xfer
|
||||||
_ = tokens.next(); // memory-map
|
_ = tokens.next(); // memory-map
|
||||||
_ = tokens.next(); // read
|
_ = tokens.next(); // read
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub fn run(self: *Self, allocator: Allocator, should_quit: *std.atomic.Value(boo
|
|||||||
var buf: [Packet.max_len]u8 = undefined;
|
var buf: [Packet.max_len]u8 = undefined;
|
||||||
|
|
||||||
var client = try self.socket.accept();
|
var client = try self.socket.accept();
|
||||||
log.info("client connected from {}", .{client.address});
|
log.info("client connected from {f}", .{client.address});
|
||||||
|
|
||||||
while (!should_quit.load(.monotonic)) {
|
while (!should_quit.load(.monotonic)) {
|
||||||
if (self.state.should_quit) {
|
if (self.state.should_quit) {
|
||||||
|
|||||||
@@ -1,31 +1,21 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArrayList = std.ArrayList;
|
|
||||||
|
|
||||||
hw_bkpt: HwBkpt = .{},
|
hw_bkpt: HwBkpt = .{},
|
||||||
sw_bkpt: SwBkpt,
|
sw_bkpt: SwBkpt = .{},
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) @This() {
|
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||||
return .{ .sw_bkpt = SwBkpt.init(allocator) };
|
self.sw_bkpt.deinit(allocator);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
|
||||||
self.sw_bkpt.deinit();
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SwBkpt = struct {
|
const SwBkpt = struct {
|
||||||
const log = std.log.scoped(.SwBkpt);
|
const log = std.log.scoped(.SwBkpt);
|
||||||
|
|
||||||
list: std.ArrayList(Bkpt),
|
list: std.ArrayList(Bkpt) = .empty,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) @This() {
|
pub fn deinit(self: *@This(), allocator: Allocator) void {
|
||||||
return .{ .list = ArrayList(Bkpt).init(allocator) };
|
self.list.deinit(allocator);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
|
||||||
self.list.deinit();
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,12 +27,12 @@ const SwBkpt = struct {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(self: *@This(), addr: u32, kind: u32) !void {
|
pub fn add(self: *@This(), allocator: Allocator, addr: u32, kind: u32) !void {
|
||||||
for (self.list.items) |bkpt| {
|
for (self.list.items) |bkpt| {
|
||||||
if (bkpt.addr == addr) return; // indempotent
|
if (bkpt.addr == addr) return; // indempotent
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.list.append(.{ .addr = addr, .kind = try Bkpt.Kind.from(u32, kind) });
|
try self.list.append(allocator, .{ .addr = addr, .kind = try Bkpt.Kind.from(u32, kind) });
|
||||||
log.warn("Added Breakpoint at 0x{X:0>8}", .{addr});
|
log.warn("Added Breakpoint at 0x{X:0>8}", .{addr});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +100,7 @@ const Bkpt = struct {
|
|||||||
Thumb = 4,
|
Thumb = 4,
|
||||||
|
|
||||||
pub fn from(comptime T: type, num: T) !@This() {
|
pub fn from(comptime T: type, num: T) !@This() {
|
||||||
comptime std.debug.assert(@typeInfo(T) == .Int);
|
comptime std.debug.assert(@typeInfo(T) == .int);
|
||||||
|
|
||||||
return switch (num) {
|
return switch (num) {
|
||||||
2 => .Arm,
|
2 => .Arm,
|
||||||
|
|||||||
28
src/lib.zig
28
src/lib.zig
@@ -16,7 +16,7 @@ pub const Emulator = struct {
|
|||||||
SingleStep: void,
|
SingleStep: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
state: State,
|
state: State = .{},
|
||||||
|
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
|
|
||||||
@@ -28,42 +28,42 @@ pub const Emulator = struct {
|
|||||||
|
|
||||||
stepFn: *const fn (*anyopaque) void,
|
stepFn: *const fn (*anyopaque) void,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, ptr: anytype) Self {
|
pub fn init(ptr: anytype) Self {
|
||||||
const Ptr = @TypeOf(ptr);
|
const Ptr = @TypeOf(ptr);
|
||||||
const ptr_info = @typeInfo(Ptr);
|
const ptr_info = @typeInfo(Ptr);
|
||||||
|
|
||||||
if (ptr_info != .Pointer) @compileError("ptr must be a pointer");
|
if (ptr_info != .pointer) @compileError("ptr must be a pointer");
|
||||||
if (ptr_info.Pointer.size != .One) @compileError("ptr must be a single-item pointer");
|
if (ptr_info.pointer.size != .one) @compileError("ptr must be a single-item pointer");
|
||||||
|
|
||||||
const gen = struct {
|
const gen = struct {
|
||||||
pub fn readImpl(pointer: *anyopaque, addr: u32) u8 {
|
pub fn readImpl(pointer: *anyopaque, addr: u32) u8 {
|
||||||
const self: Ptr = @ptrCast(@alignCast(pointer));
|
const self: Ptr = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
return @call(.always_inline, ptr_info.Pointer.child.read, .{ self, addr });
|
return @call(.always_inline, ptr_info.pointer.child.read, .{ self, addr });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeImpl(pointer: *anyopaque, addr: u32, value: u8) void {
|
pub fn writeImpl(pointer: *anyopaque, addr: u32, value: u8) void {
|
||||||
const self: Ptr = @ptrCast(@alignCast(pointer));
|
const self: Ptr = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
return @call(.always_inline, ptr_info.Pointer.child.write, .{ self, addr, value });
|
return @call(.always_inline, ptr_info.pointer.child.write, .{ self, addr, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registersImpl(pointer: *anyopaque) *[16]u32 {
|
pub fn registersImpl(pointer: *anyopaque) *[16]u32 {
|
||||||
const self: Ptr = @ptrCast(@alignCast(pointer));
|
const self: Ptr = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
return @call(.always_inline, ptr_info.Pointer.child.registers, .{self});
|
return @call(.always_inline, ptr_info.pointer.child.registers, .{self});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cpsrImpl(pointer: *anyopaque) u32 {
|
pub fn cpsrImpl(pointer: *anyopaque) u32 {
|
||||||
const self: Ptr = @ptrCast(@alignCast(pointer));
|
const self: Ptr = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
return @call(.always_inline, ptr_info.Pointer.child.cpsr, .{self});
|
return @call(.always_inline, ptr_info.pointer.child.cpsr, .{self});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stepImpl(pointer: *anyopaque) void {
|
pub fn stepImpl(pointer: *anyopaque) void {
|
||||||
const self: Ptr = @ptrCast(@alignCast(pointer));
|
const self: Ptr = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
return @call(.always_inline, ptr_info.Pointer.child.step, .{self});
|
return @call(.always_inline, ptr_info.pointer.child.step, .{self});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,13 +74,11 @@ pub const Emulator = struct {
|
|||||||
.registersFn = gen.registersImpl,
|
.registersFn = gen.registersImpl,
|
||||||
.cpsrFn = gen.cpsrImpl,
|
.cpsrFn = gen.cpsrImpl,
|
||||||
.stepFn = gen.stepImpl,
|
.stepFn = gen.stepImpl,
|
||||||
|
|
||||||
.state = State.init(allocator),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
self.state.deinit();
|
self.state.deinit(allocator);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +126,10 @@ pub const Emulator = struct {
|
|||||||
const BkptType = enum { Hardware, Software };
|
const BkptType = enum { Hardware, Software };
|
||||||
|
|
||||||
// TODO: Consider properly implementing Software interrupts?
|
// TODO: Consider properly implementing Software interrupts?
|
||||||
pub fn addBkpt(self: *Self, comptime @"type": BkptType, addr: u32, kind: u32) !void {
|
pub fn addBkpt(self: *Self, comptime @"type": BkptType, allocator: Allocator, addr: u32, kind: u32) !void {
|
||||||
switch (@"type") {
|
switch (@"type") {
|
||||||
.Hardware => try self.state.hw_bkpt.add(addr, kind),
|
.Hardware => try self.state.hw_bkpt.add(addr, kind),
|
||||||
.Software => try self.state.sw_bkpt.add(addr, kind),
|
.Software => try self.state.sw_bkpt.add(allocator, addr, kind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/test.zig
16
src/test.zig
@@ -52,8 +52,8 @@ const BarebonesEmulator = struct {
|
|||||||
|
|
||||||
r: [16]u32 = [_]u32{0} ** 16,
|
r: [16]u32 = [_]u32{0} ** 16,
|
||||||
|
|
||||||
pub fn interface(self: *@This(), allocator: Allocator) Emulator {
|
pub fn interface(self: *@This()) Emulator {
|
||||||
return Emulator.init(allocator, self);
|
return Emulator.init(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(_: *const @This(), _: u32) u8 {
|
pub fn read(_: *const @This(), _: u32) u8 {
|
||||||
@@ -88,15 +88,19 @@ test Server {
|
|||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
var impl = BarebonesEmulator{};
|
var impl = BarebonesEmulator{};
|
||||||
var iface = impl.interface(allocator);
|
var iface = impl.interface();
|
||||||
defer iface.deinit();
|
defer iface.deinit(allocator);
|
||||||
|
|
||||||
const clientFn = struct {
|
const clientFn = struct {
|
||||||
fn inner(address: std.net.Address) !void {
|
fn inner(address: std.net.Address) !void {
|
||||||
const socket = try std.net.tcpConnectToAddress(address);
|
const socket = try std.net.tcpConnectToAddress(address);
|
||||||
defer socket.close();
|
defer socket.close();
|
||||||
|
|
||||||
_ = try socket.writer().writeAll("+");
|
var buf: [1024]u8 = undefined;
|
||||||
|
|
||||||
|
var writer = socket.writer(&buf).interface;
|
||||||
|
|
||||||
|
_ = try writer.writeAll("+");
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
|
|
||||||
@@ -142,7 +146,7 @@ test Emulator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var impl = ExampleImpl{};
|
var impl = ExampleImpl{};
|
||||||
var emu = Emulator.init(std.testing.allocator, &impl);
|
var emu = Emulator.init(&impl);
|
||||||
|
|
||||||
_ = emu.read(0x0000_0000);
|
_ = emu.read(0x0000_0000);
|
||||||
emu.write(0x0000_0000, 0x00);
|
emu.write(0x0000_0000, 0x00);
|
||||||
|
|||||||
Reference in New Issue
Block a user