Compare commits

..

1 Commits

Author SHA1 Message Date
Rekai Nyangadzayi Musuka d3655e8f61 chore: update to latest zig 2023-08-06 22:08:03 +01:00
6 changed files with 62 additions and 165 deletions

View File

@ -1,38 +1,16 @@
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// 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
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const net_dep = b.dependency("zig-network", .{}); // https://github.com/MasterQ32/zig-network
_ = b.addModule("gdbstub", .{
.source_file = .{ .path = "src/lib.zig" },
.dependencies = &.{},
.dependencies = &.{.{ .name = "network", .module = net_dep.module("network") }},
});
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const lib_tests = b.addTest(.{
.root_source_file = .{ .path = "src/lib.zig" },
.target = target,
.optimize = optimize,
});
const lib_test = b.addTest(.{ .root_source_file = .{ .path = "src/lib.zig" }, .target = target });
const run_lib_tests = b.addRunArtifact(lib_tests);
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build test`
// This will evaluate the `test` step rather than the default, which is "install".
const test_step = b.step("test", "Run library tests");
test_step.dependOn(&run_lib_tests.step);
const test_step = b.step("test", "Run Library Tests");
test_step.dependOn(&lib_test.step);
}

View File

@ -1,5 +1,10 @@
.{
.name = "zba-gdbstub",
.version = "0.1.0",
.dependencies = .{},
.dependencies = .{
.@"zig-network" = .{
.url = "https://github.com/MasterQ32/zig-network/archive/02ffa0fc310ff0746f06c9bfb73b008ce4fca200.tar.gz",
.hash = "1220fe0d4ca564aa15f3fd7f9f84ba04e031bb70c3a1432257e0d35c74b183550c24",
},
},
}

View File

@ -1,11 +1,11 @@
const std = @import("std");
const network = @import("network");
const Packet = @import("Packet.zig");
const Emulator = @import("lib.zig").Emulator;
const Atomic = std.atomic.Atomic;
const Socket = network.Socket;
const Allocator = std.mem.Allocator;
const Server = std.net.StreamServer;
const Connection = Server.Connection;
const Atomic = std.atomic.Atomic;
const Emulator = @import("lib.zig").Emulator;
const Self = @This();
const log = std.log.scoped(.Server);
@ -57,20 +57,32 @@ pub const memory_map: []const u8 =
// FIXME: Shouldn't this be a Packet Struct?
pkt_cache: ?[]const u8 = null,
server: Server,
client: Socket,
_socket: Socket,
emu: Emulator,
pub fn init(emulator: Emulator) !Self {
var server = std.net.StreamServer.init(.{});
try server.listen(std.net.Address.initIp4([_]u8{0} ** 4, port));
try network.init();
return .{ .emu = emulator, .server = server };
var socket = try Socket.create(.ipv4, .tcp);
try socket.bindToPort(port);
try socket.listen();
var client = try socket.accept(); // TODO: This blocks, is this OK?
const endpoint = try client.getLocalEndPoint();
log.info("client connected from {}", .{endpoint});
return .{ .emu = emulator, ._socket = socket, .client = client };
}
pub fn deinit(self: *Self, allocator: Allocator) void {
self.reset(allocator);
self.server.deinit();
self.client.close();
self._socket.close();
network.deinit();
self.* = undefined;
}
@ -86,17 +98,13 @@ const Action = union(enum) {
pub fn run(self: *Self, allocator: Allocator, quit: *Atomic(bool)) !void {
var buf: [Packet.max_len]u8 = undefined;
var client = try self.server.accept();
log.info("client connected from {}", .{client.address});
while (true) {
const len = try client.stream.readAll(&buf);
const len = try self.client.receive(&buf);
if (len == 0) break;
if (quit.load(.Monotonic)) break;
const action = try self.parse(allocator, buf[0..len]);
try self.send(allocator, client, action);
try self.send(allocator, action);
}
// Just in case its the gdbstub that exited first,
@ -105,7 +113,7 @@ pub fn run(self: *Self, allocator: Allocator, quit: *Atomic(bool)) !void {
}
fn parse(self: *Self, allocator: Allocator, input: []const u8) !Action {
log.debug("-> {s}", .{input});
// log.debug("-> {s}", .{input});
return switch (input[0]) {
'+' => blk: {
@ -138,11 +146,11 @@ fn handlePacket(self: *Self, allocator: Allocator, input: []const u8) !Action {
return .{ .send = response };
}
fn send(self: *Self, allocator: Allocator, client: Server.Connection, action: Action) !void {
fn send(self: *Self, allocator: Allocator, action: Action) !void {
switch (action) {
.send => |pkt| {
_ = try client.stream.writeAll(pkt);
log.debug("<- {s}", .{pkt});
_ = try self.client.send(pkt);
// log.debug("<- {s}", .{pkt});
self.reset(allocator);
self.pkt_cache = pkt;
@ -151,19 +159,19 @@ fn send(self: *Self, allocator: Allocator, client: Server.Connection, action: Ac
log.warn("received nack, resending: \"{?s}\"", .{self.pkt_cache});
if (self.pkt_cache) |pkt| {
_ = try client.stream.writeAll(pkt);
log.debug("<- {s}", .{pkt});
_ = try self.client.send(pkt);
// log.debug("<- {s}", .{pkt});
}
},
.ack => {
_ = try client.stream.writeAll("+");
log.debug("<- +", .{});
_ = try self.client.send("+");
// log.debug("<- +", .{});
self.reset(allocator);
},
.nack => {
_ = try client.stream.writeAll("-");
log.debug("<- -", .{});
_ = try self.client.send("-");
// log.debug("<- -", .{});
self.reset(allocator);
},

View File

@ -142,7 +142,3 @@ pub const Emulator = struct {
}
}
};
test {
_ = @import("test.zig");
}

18
src/main.zig Normal file
View File

@ -0,0 +1,18 @@
const std = @import("std");
const Server = @import("gdbstub").Server;
pub fn main() !void {
const log = std.log.scoped(.Main);
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(!gpa.deinit());
const allocator = gpa.allocator();
var server = try Server.init();
defer server.deinit(allocator);
try server.run(allocator);
log.info("Client disconnected", .{});
}

View File

@ -1,108 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
const Emulator = @import("lib.zig").Emulator;
const Server = @import("Server.zig");
const Allocator = std.mem.Allocator;
const BarebonesEmulator = struct {
r: [16]u32 = [_]u32{0} ** 16,
pub fn interface(self: *@This(), allocator: Allocator) Emulator {
return Emulator.init(allocator, self);
}
pub fn read(_: *const @This(), _: u32) u8 {
return 0;
}
pub fn write(_: *@This(), _: u32, _: u8) void {}
pub fn registers(self: *@This()) *[16]u32 {
return &self.r;
}
pub fn cpsr(_: *const @This()) u32 {
return 0;
}
pub fn step(_: *@This()) void {
// execute 1 instruction
}
};
test Server {
// https://github.com/ziglang/zig/blob/225fe6ddbfae016395762850e0cd5c51f9e7751c/lib/std/net/test.zig#L146C1-L156
if (builtin.single_threaded) return error.SkipZigTest;
if (builtin.os.tag == .wasi) return error.SkipZigTest;
if (builtin.os.tag == .windows)
_ = try std.os.windows.WSAStartup(2, 2);
defer if (builtin.os.tag == .windows) std.os.windows.WSACleanup() catch unreachable;
const allocator = std.testing.allocator;
var impl = BarebonesEmulator{};
var iface = impl.interface(allocator);
defer iface.deinit();
const clientFn = struct {
fn inner(address: std.net.Address) !void {
const socket = try std.net.tcpConnectToAddress(address);
defer socket.close();
_ = try socket.writer().writeAll("+");
}
}.inner;
var server = try Server.init(iface);
defer server.deinit(allocator);
const t = try std.Thread.spawn(.{}, clientFn, .{server.server.listen_address});
defer t.join();
var should_quit = std.atomic.Atomic(bool).init(false);
try server.run(std.testing.allocator, &should_quit);
}
test Emulator {
const ExampleImpl = struct {
r: [16]u32 = [_]u32{0} ** 16,
pub fn interface(self: *@This(), allocator: std.mem.Allocator) Emulator {
return Emulator.init(allocator, self);
}
pub fn read(_: *const @This(), _: u32) u8 {
return 0;
}
pub fn write(_: *@This(), _: u32, _: u8) void {}
pub fn registers(self: *@This()) *[16]u32 {
return &self.r;
}
pub fn cpsr(_: *const @This()) u32 {
return 0;
}
pub fn step(_: *@This()) void {
// execute 1 instruction
}
};
var impl = ExampleImpl{};
var emu = Emulator.init(std.testing.allocator, &impl);
_ = emu.read(0x0000_0000);
emu.write(0x0000_0000, 0x00);
_ = emu.registers();
_ = emu.cpsr();
_ = emu.step();
}