Skip to content

Commit

Permalink
[atari] Buffer line on minimal getchar
Browse files Browse the repository at this point in the history
The Atari OS expects that IOCB screen editor inputs are line-atomic; it
corrupts the cursor if writes happen in the meantime. It's generally
expected in C that one can interleave getchar and putchar, and that
putchars only take effect after a line is entered. Accordingly, this
change line-buffers the minimal getchar for Atari targets.

Fixes #378
  • Loading branch information
mysterymath committed Oct 11, 2024
1 parent 80d3c4b commit 4fc7b2d
Showing 1 changed file with 33 additions and 6 deletions.
39 changes: 33 additions & 6 deletions mos-platform/atari8-common/getchar.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <atari.h>
#include <stdbool.h>
#include <stdio.h>

__attribute__((always_inline, weak)) int __to_ascii(void *ctx,
Expand All @@ -18,12 +19,38 @@ __attribute__((always_inline, weak)) int __to_ascii(void *ctx,
}
}

int __getchar() {
OS.iocb[0].command = IOCB_GETCHR;
OS.iocb[0].buflen = 0;
// The Atari OS screen editor expects that screen editor reads are atomic with
// line granularity. Corruption results if characters are output while a read is
// in progress. Since this is unusual on other C targets (it's usually fine to
// interleave getchar and putchar), getchar is line buffered, even in the
// minimal stdio here.

// Provide space for a full logical line (3 screen lines and a newline).
static char buf[40 * 3 + 1];
// Index of next character to be read.
static char buf_idx;
// Length of the filled region of the buffer.
static char buf_len;

// Fill the input buffer and return true on error.
static bool fill_buf(void) {
buf_idx = 0;
buf_len = 0;
OS.iocb[0].command = IOCB_GETREC;
OS.iocb[0].buffer = buf;
OS.iocb[0].buflen = sizeof(buf) - 1;
const unsigned char channel = 0;
unsigned char c;
unsigned char status;
asm volatile("jsr $e456\n" : "=a"(c), "=y"(status) : "x"(channel) : "p");
return status < 0x80 ? c : EOF;
asm volatile("jsr $e456\n" : "=y"(status) : "x"(channel) : "p");
if (status >= 0x80)
return EOF;
buf_len = OS.iocb[0].buflen;
return status >= 0x80;
}

int __getchar() {
if (buf_idx == buf_len)
if (fill_buf())
return EOF;
return buf[buf_idx++];
}

0 comments on commit 4fc7b2d

Please sign in to comment.