aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-07-16 16:06:49 +0200
committergbc dev <gbc@localhost>2026-07-16 16:06:49 +0200
commit0b30297393430450486ce54ba5c3c47155a0dc68 (patch)
tree2d978d65bc50e99a95e7e9c8a56d3cbdfb68d093
parentmain: --shot with --headless dumps final LCD on exit (diff)
downloadsl0pboy-0b30297393430450486ce54ba5c3c47155a0dc68.tar.gz
sl0pboy-0b30297393430450486ce54ba5c3c47155a0dc68.tar.xz
sl0pboy-0b30297393430450486ce54ba5c3c47155a0dc68.zip
main/gb: --keys button-script harness + serial_no_eof for OSK testing
--keys "udlrabse." plays scripted joypad taps (each char = one button held 10 frames then released 10, so the guest sees a clean edge); pairs with --headless --shot to drive on-screen input and capture the result. When --keys is active, serial-RX EOF stays pending instead of sending $04, so a shell blocked on read waits for OSK input instead of exiting.
-rw-r--r--src/gb.c8
-rw-r--r--src/gb.h1
-rw-r--r--src/main.c25
3 files changed, 31 insertions, 3 deletions
diff --git a/src/gb.c b/src/gb.c
index 3caa986..fc19e25 100644
--- a/src/gb.c
+++ b/src/gb.c
@@ -140,9 +140,11 @@ void gb_write(GB *gb, u16 addr, u8 val) {
gb->sc &= ~0x80;
gb_request_interrupt(gb, INT_SERIAL);
} else if (n == 0) {
- gb->sb = 0x04; // EOF -> EOT (Ctrl-D)
- gb->sc &= ~0x80;
- gb_request_interrupt(gb, INT_SERIAL);
+ if (!gb->serial_no_eof) {
+ gb->sb = 0x04; // EOF -> EOT (Ctrl-D)
+ gb->sc &= ~0x80;
+ gb_request_interrupt(gb, INT_SERIAL);
+ } // else: stay pending (OSK provides input)
}
// n < 0 (EAGAIN on a live tty): stay pending, poll again
}
diff --git a/src/gb.h b/src/gb.h
index 7959e60..5192e85 100644
--- a/src/gb.h
+++ b/src/gb.h
@@ -113,6 +113,7 @@ struct GB {
bool hdma_active;
u64 cycles; // total T-cycles elapsed
+ bool serial_no_eof; // if true, serial-RX EOF stays pending (don't send $04)
bool serial_log; // print serial output to stderr (blargg tests)
int serial_out_fd; // if >=0, transmitted serial bytes written here (stdout)
int serial_in_fd; // if >=0, received serial bytes read here (stdin), else 0xFF
diff --git a/src/main.c b/src/main.c
index 6d6379a..40efe29 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,6 +28,22 @@ static void run_frame(GB *gb) {
cpu_step(gb);
}
+// Scripted button taps for testing: each char in `keys` = one token occupying
+// 20 frames (pressed for the first 10, released for the next 10, so the guest
+// sees a clean press+release edge). u/d/l/r=dpad, a/b, s=select, e=start, .=wait.
+static u8 keys_mask(const char *keys, int frame) {
+ int tok = frame / 20;
+ if (tok >= (int)strlen(keys)) return 0;
+ if ((frame % 20) >= 10) return 0;
+ switch (keys[tok]) {
+ case 'u': return BTN_UP; case 'd': return BTN_DOWN;
+ case 'l': return BTN_LEFT; case 'r': return BTN_RIGHT;
+ case 'a': return BTN_A; case 'b': return BTN_B;
+ case 's': return BTN_SELECT; case 'e': return BTN_START;
+ default: return 0;
+ }
+}
+
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s <rom> [--test seconds] [--sixel [scale]] "
@@ -48,6 +64,7 @@ int main(int argc, char **argv) {
bool sixel = false; // use sixel graphics output
int sixel_scale = 2; // integer pixel zoom for sixel
bool headless = false; // no video; serial <-> stdio (OS debug console)
+ const char *keys = NULL; // scripted button taps for testing (u d l r a b s e .)
for (int i = 2; i < argc; i++) {
if (!strcmp(argv[i], "--test")) {
test = true;
@@ -55,6 +72,8 @@ int main(int argc, char **argv) {
} else if (!strcmp(argv[i], "--shot")) {
if (i + 1 < argc) shot_frames = atoi(argv[++i]);
if (i + 1 < argc && argv[i+1][0] != '-') shot_path = argv[++i];
+ } else if (!strcmp(argv[i], "--keys")) {
+ if (i + 1 < argc) keys = argv[++i];
} else if (!strcmp(argv[i], "--fifo")) {
fifo_path = (i + 1 < argc && argv[i+1][0] != '-')
? argv[++i] : "/tmp/gbc.fifo";
@@ -97,6 +116,8 @@ int main(int argc, char **argv) {
if (headless) {
gb->serial_out_fd = STDOUT_FILENO;
gb->serial_in_fd = STDIN_FILENO;
+ gb->serial_no_eof = (keys != NULL); // OSK provides input; don't EOF-exit
+ int keys_frame = 0;
int fl = fcntl(STDIN_FILENO, F_GETFL, 0);
if (fl != -1) fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK);
signal(SIGINT, on_sig);
@@ -121,6 +142,10 @@ int main(int argc, char **argv) {
u64 start_cyc = gb->cycles;
const double HZ = 4194304.0;
while (running && !gb->poweroff) {
+ if (keys) {
+ gb->buttons = keys_mask(keys, keys_frame);
+ if (keys_frame++ > (int)strlen(keys) * 20 + 40) break;
+ }
run_frame(gb); // advance ~a frame's worth of cycles
if (!uncapped) {
double target = start_t + (gb->cycles - start_cyc) / HZ;