//! Standalone GPIO 9P firmware over UART0; the editor is not linked. //! UART0 carries protocol bytes only, including fatal diagnostics. const std = @import("std"); const soc = @import("soc"); const hal = @import("hal"); const config = @import("config"); const ninep = @import("9p.zig"); const gpio = @import("esp32p4_gpio.zig"); const uart = @import("esp32p4/uart.zig"); const Pads = struct { pub fn level(pin: u8) u1 { return hal.gpio.getDrivenLevel(pin); } pub fn drive(pin: u8, want: u1) void { hal.gpio.configureOutput(pin, .{ .readback = true }); if (want == 1) hal.gpio.setHigh(pin) else hal.gpio.setLow(pin); } }; comptime { for (gpio.Header.gpio_pins) |pin| { if (pin > hal.gpio.max_pin) @compileError("JP1 names a pad this chip package does not have"); } } const Fs = gpio.Fs(Pads); const Server = ninep.Server(Fs, ninep.board); comptime { std.debug.assert(@typeInfo(@FieldType(Server, "fids")).array.len == 32); std.debug.assert(@sizeOf(Server) <= 10 * 1024); } const msize: u32 = 1024; var in_buf: [msize]u8 = undefined; var out_buf: [2 * msize]u8 = undefined; var stage: [128]u8 = undefined; const baud: u32 = 921600; var srv: Server = undefined; var fsys: Fs = .{}; export fn zig_main() noreturn { soc.flushFlashCache(); if (config.cpu_mhz != 90) hal.clkrst.setCpuFreq(switch (config.cpu_mhz) { 180 => .mhz180, 360 => .mhz360, else => .mhz90, }); _ = hal.rwdt.disable(); _ = uart.drainInput(); _ = uart.setBaud(baud); srv = Server.init(.{ .in = &in_buf, .out = &out_buf, .root = gpio.root }); var stage_len: usize = 0; while (true) { if (stage_len < stage.len) stage_len += uart.read(stage[stage_len..]); if (stage_len != 0) { const took = srv.push(stage[0..stage_len]); if (took != stage_len) std.mem.copyForwards(u8, stage[0 .. stage_len - took], stage[took..stage_len]); stage_len -= took; } while (srv.retry()) |req| { const a = fsys.handle(req); srv.reply(&a.reply, a.bytes); } while (srv.next()) |req| { const a = fsys.handle(req); srv.reply(&a.reply, a.bytes); } const queued = srv.output(); if (queued.len != 0) srv.wrote(uart.writeSome(queued)); if (srv.protocol.dead) { srv.hangup(); while (srv.next()) |req| { const a = fsys.handle(req); srv.reply(&a.reply, a.bytes); } _ = uart.drainInput(); stage_len = 0; srv = Server.init(.{ .in = &in_buf, .out = &out_buf, .root = gpio.root }); } } } fn die(msg: []const u8) noreturn { var buf: [ninep.errmax + ninep.header_len + 2]u8 = undefined; const bytes = ninep.encode( .{ .rerror = .{ .ename = msg[0..@min(msg.len, ninep.errmax)] } }, ninep.notag, &buf, // unreachable: the message is cut to errmax and buf is sized to it ) catch unreachable; uart.write(bytes); while (true) {} } fn hex8(buf: *[8]u8, v: u32) void { var shift: u5 = 28; for (buf) |*slot| { const nib: u8 = @intCast((v >> shift) & 0xf); slot.* = if (nib < 10) '0' + nib else 'a' + (nib - 10); shift -%= 4; } } export fn trapEntry() linksection(".text.entry") callconv(.naked) noreturn { asm volatile ("j trapReport"); } export fn trapReport() noreturn { const mcause = asm volatile ("csrr %[o], mcause" : [o] "=r" (-> u32), ); const mepc = asm volatile ("csrr %[o], mepc" : [o] "=r" (-> u32), ); const mtval = asm volatile ("csrr %[o], mtval" : [o] "=r" (-> u32), ); var msg = "trap mcause=00000000 mepc=00000000 mtval=00000000".*; hex8(msg[12..20], mcause); hex8(msg[26..34], mepc); hex8(msg[41..49], mtval); die(&msg); } pub const std_options: std.Options = .{ .page_size_min = 4096, .page_size_max = 4096, .logFn = logFn, }; fn logFn( comptime _: std.log.Level, comptime _: @EnumLiteral(), comptime _: []const u8, _: anytype, ) void {} pub const panic = std.debug.FullPanic(panicImpl); fn panicImpl(msg: []const u8, first_trace_addr: ?usize) noreturn { var buf: [ninep.errmax]u8 = undefined; @memcpy(buf[0..7], "panic 0"); buf[7] = 'x'; hex8(buf[8..16], @truncate(first_trace_addr orelse 0)); buf[16] = ' '; const n = @min(msg.len, buf.len - 17); @memcpy(buf[17..][0..n], msg[0..n]); die(buf[0 .. 17 + n]); } export fn _start() linksection(".text.entry") callconv(.naked) noreturn { asm volatile ( \\ li t0, 1 << 13 \\ csrs mstatus, t0 \\ la sp, __stack_top \\ mv fp, sp \\ la t0, trapEntry \\ csrw mtvec, t0 \\ la t0, __bss_start \\ la t1, __bss_end \\ bgeu t0, t1, 2f \\1: \\ sw zero, 0(t0) \\ addi t0, t0, 4 \\ bltu t0, t1, 1b \\2: \\ j zig_main ); }