diff options
Diffstat (limited to 'src/pardes/app.zig')
| -rw-r--r-- | src/pardes/app.zig | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/src/pardes/app.zig b/src/pardes/app.zig index 5b1431f..34f427d 100644 --- a/src/pardes/app.zig +++ b/src/pardes/app.zig @@ -41,6 +41,17 @@ const config = @import("config"); /// `-Dprof`: time the two phases of a keystroke on the board and print the cycle counts. A /// diagnostic, not a feature - see the loop. const prof = config.prof; + +/// Every byte this loop has taken off the UART, for `-Dprof`. Ground truth for "did the burst +/// arrive", which a screen reconstruction cannot answer: a character can be missing from the screen +/// because it never arrived, because the editor never applied it, or because the viewport does not +/// show that column. +var rx_total: u32 = 0; + +/// How many input bytes to hand the editor before draining the receiver again. Chosen against the +/// FIFO rather than against the editor: 128 bytes of FIFO is 11 ms of wire at 115200, and 32 +/// keystrokes cost about 2 ms even on a long line, which leaves five times the margin needed. +const input_chunk = 8; const hal = @import("hal"); const heapmod = @import("heap"); const uart = @import("uart.zig"); @@ -247,10 +258,27 @@ export fn zig_main() noreturn { // reads per phase and quantises at one cycle, which is four orders of magnitude below the // milliseconds being attributed. Gated on `prof` so the shipping build carries none of it. const n = uart.read(&in); + rx_total +%= @intCast(n); + var input_cy: u64 = 0; if (n > 0) { const t0 = if (prof) soc.cycles() else 0; - pardes_p4_input(&in, n); + // IN CHUNKS, rescuing the receiver between them. Applying a keystroke is not free and + // gets dearer as the line grows - measured at 44 us on an empty line and 63 us at 640 + // characters - so handing over a full 128-byte batch is up to 8 ms in which nothing + // drains the receiver, against a FIFO that holds only 11 ms of wire. A 600-byte paste + // lost 93 bytes to exactly that window even with the transmitter's own rescue in place. + // + // Splitting a burst at an arbitrary byte is safe: `pardes_p4_input` keeps whatever it + // could not parse, which is how it already survives an escape sequence split across two + // UART reads. One render still happens per loop iteration, so this costs no extra wire. + var off: usize = 0; + while (off < n) { + const chunk = @min(input_chunk, n - off); + pardes_p4_input(in[off..].ptr, chunk); + off += chunk; + if (off < n) uart.rescueNow(); + } if (prof) input_cy = soc.cycles() - t0; } @@ -279,13 +307,16 @@ export fn zig_main() noreturn { var vx_cy: u64 = 0; var flush_cy: u64 = 0; pardes_p4_frame_prof(©_cy, &vx_cy, &flush_cy); - soc.rom.print("PROF in=%u render=%u idle=%u copy=%u vaxis=%u flush=%u\r\n", .{ + soc.rom.print("PROF in=%u render=%u idle=%u copy=%u vaxis=%u flush=%u rx=%u rxdrop=%u txdrop=%u\r\n", .{ @as(u32, @intCast(input_cy)), @as(u32, @intCast(render_cy)), @as(u32, @intCast(idle_cy)), @as(u32, @intCast(copy_cy)), @as(u32, @intCast(vx_cy)), @as(u32, @intCast(flush_cy)), + rx_total, + uart.inputDropped(), + uart.dropped, }); } } |
