summaryrefslogtreecommitdiff
path: root/src/pardes/app.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes/app.zig')
-rw-r--r--src/pardes/app.zig35
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(&copy_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,
});
}
}