aboutsummaryrefslogtreecommitdiffstats
path: root/src/wasm.c
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-09-22 19:49:47 +0200
committergbc dev <gbc@localhost>2026-09-22 19:49:47 +0200
commit1537eff38cd86e1d0b1980bf8f4412dfa2a11056 (patch)
tree6783e69a449db2bfa1488e4517228077283036fb /src/wasm.c
parentweb: boot a demo ROM on arrival, and a deploy script for gbc.sl0p.foo (diff)
downloadsl0pboy-1537eff38cd86e1d0b1980bf8f4412dfa2a11056.tar.gz
sl0pboy-1537eff38cd86e1d0b1980bf8f4412dfa2a11056.tar.xz
sl0pboy-1537eff38cd86e1d0b1980bf8f4412dfa2a11056.zip
wasm: expose the link port as host-drained byte queues
A browser has no file descriptors, so the wasm build's link port was inert. Give it a pair of ring buffers instead: the guest's transmitted bytes pile up in one, the host pushes received bytes into the other, and the external-clock RX path pops from it (staying pending when empty, exactly like a quiet link). gbw_serial_drain / gbw_serial_push hand them to JS through a fixed staging buffer, so nothing allocates per frame. That is enough to be a real link. SLIP-framed bytes are IP packets; unframed bytes are console I/O - the same split tools/gbhub makes natively, which is what lets a page type into the link port and reach the shell's stdin. One machine per wasm instance, so the queues are plain statics: several Game Boys on a page are several instantiations of the one compiled module, each with its own linear memory. The native link is untouched: the fd paths sit in the #else and, preprocessed for a native target, gb.c comes out byte-identical to the previous commit (verified with gcc -E). blargg cpu_instrs still passes and the golden-frame tests are still pixel-exact.
Diffstat (limited to 'src/wasm.c')
-rw-r--r--src/wasm.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/wasm.c b/src/wasm.c
index e1051a1..cf7e74e 100644
--- a/src/wasm.c
+++ b/src/wasm.c
@@ -124,3 +124,31 @@ int EXPORT(gbw_sram_load)(const u8 *data, int len) {
// Total T-cycles since power-on; handy for pacing checks and debugging.
double EXPORT(gbw_cycles)(void) { return (double)gb.cycles; }
+
+// ---- link cable -----------------------------------------------------------
+// The page plays the part tools/gbhub plays natively: drain what this Game Boy
+// transmitted, decide where it goes, push bytes back in. SLIP-framed bytes are
+// IP packets; unframed bytes are console I/O (which is why typing into the
+// link port lands on the shell's stdin).
+//
+// A fixed staging buffer avoids allocating per frame; the page reads it
+// through a typed array right after the call.
+static u8 serial_buf[2048];
+
+// Bytes this Game Boy put on the wire since the last drain. Returns the count;
+// the data sits at gbw_serial_buf().
+int EXPORT(gbw_serial_drain)(void) {
+ return gb_serial_tx_drain(serial_buf, (int)sizeof serial_buf);
+}
+u8 *EXPORT(gbw_serial_buf)(void) { return serial_buf; }
+
+// Hand bytes to this Game Boy's link port (write them into gbw_serial_buf()
+// first, then call this with the length).
+void EXPORT(gbw_serial_push)(int n) {
+ if (n > 0)
+ gb_serial_rx_push(serial_buf, n > (int)sizeof serial_buf ? (int)sizeof serial_buf : n);
+}
+
+// RX bytes dropped because the guest wasn't consuming - a wedged link shows up
+// here as a climbing number instead of silently losing packets.
+int EXPORT(gbw_serial_dropped)(void) { return gb_serial_rx_dropped(); }