aboutsummaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
Diffstat (limited to 'c')
-rw-r--r--c/cat.c10
-rw-r--r--c/crt0.s6
-rw-r--r--c/echo.c5
-rw-r--r--c/false.c2
-rw-r--r--c/gbos.h16
-rw-r--r--c/libc.s84
-rw-r--r--c/pid.c9
-rw-r--r--c/true.c2
-rw-r--r--c/uname.c2
9 files changed, 102 insertions, 34 deletions
diff --git a/c/cat.c b/c/cat.c
new file mode 100644
index 0000000..4092778
--- /dev/null
+++ b/c/cat.c
@@ -0,0 +1,10 @@
+#include "gbos.h"
+/* cat: copy stdin to stdout until EOF (Ctrl-D / pipe end). */
+void main(void) {
+ char c;
+ for (;;) {
+ c = readc();
+ if (c == EOF) break;
+ putc(c);
+ }
+}
diff --git a/c/crt0.s b/c/crt0.s
index cde4b67..0d8371f 100644
--- a/c/crt0.s
+++ b/c/crt0.s
@@ -1,11 +1,11 @@
.module crt0
.globl _main
- ;; gbos C entry. exec() maps our ROM bank and jumps to the start of _CODE
- ;; (linked at 0x4000). Call main(), then exit(0). exec() already set SP.
+ ;; gbos C entry. exec() maps our ROM bank and jumps here ($4000).
+ ;; Call main(), then exit(0). (Args are fetched on demand via getargs().)
.area _CODE
_start::
call _main
ld b, #0
- ld c, #0 ; SYS_EXIT
+ ld c, #0 ; SYS_EXIT
rst #0x30
1$: jr 1$
diff --git a/c/echo.c b/c/echo.c
new file mode 100644
index 0000000..f8d5125
--- /dev/null
+++ b/c/echo.c
@@ -0,0 +1,5 @@
+#include "gbos.h"
+void main(void) {
+ puts(getargs());
+ nl();
+}
diff --git a/c/false.c b/c/false.c
new file mode 100644
index 0000000..a124951
--- /dev/null
+++ b/c/false.c
@@ -0,0 +1,2 @@
+#include "gbos.h"
+void main(void) { sexit(1); }
diff --git a/c/gbos.h b/c/gbos.h
index 9a09a5d..3a10e06 100644
--- a/c/gbos.h
+++ b/c/gbos.h
@@ -1,9 +1,15 @@
-/* gbos userland C API (thin wrappers over rst $30 syscalls; see c/libc.asm) */
+/* gbos userland C API (thin wrappers over rst $30 syscalls; see c/libc.s) */
#ifndef GBOS_H
#define GBOS_H
-void writes(const char *buf, unsigned char len); /* write to console */
-void nl(void); /* newline (CRLF) */
-unsigned char readc(void); /* read one byte */
-void sexit(unsigned char code); /* exit(code) */
+#define EOF 4 /* readc() returns this at end of input */
+
+void writes(const char *buf, unsigned char len);
+void putc(char c);
+void puts(const char *s); /* write a NUL-terminated string */
+void nl(void); /* newline (CRLF) */
+unsigned char strlen(const char *s);
+char *getargs(void); /* this program's argument string */
+char readc(void); /* one input byte, EOF at end */
+void sexit(unsigned char code);
unsigned char getpid(void);
#endif
diff --git a/c/libc.s b/c/libc.s
index 4fca5e3..29031e9 100644
--- a/c/libc.s
+++ b/c/libc.s
@@ -1,19 +1,48 @@
.module libc
- .globl _writes, _nl, _readc, _sexit, _getpid
+ .globl _writes, _putc, _puts, _nl, _strlen, _readc, _sexit, _getpid, _getargs
+ ;; SDCC sm83 sdcccall(1): 1st arg -> A (byte) or DE (pointer); ret A / BC.
+ ;; rst $30 (the trap) clobbers BC/DE/HL; SDCC treats them caller-saved, so
+ ;; wrappers need not preserve them - but we compute cleanly regardless.
.area _CODE
+
;; void writes(const char *buf /*DE*/, unsigned char len /*A*/)
_writes:
- push hl
- push de
- push bc
ld b, a
- ld c, #3 ; SYS_WRITE
+ ld c, #3 ; SYS_WRITE
rst #0x30
- pop bc
- pop de
- pop hl
ret
- ;; void nl(void) - CRLF straight to serial
+
+ ;; char *getargs(void) -> BC : the arg string (command line past word 1).
+ ;; The shell leaves "cmd\0args\0" at 0xA000, inherited by the child via fork.
+_getargs:
+ ld hl, #0xa000
+1$: ld a, (hl)
+ inc hl
+ or a
+ jr nz, 1$
+ ld b, h
+ ld c, l
+ ret
+
+ ;; void putc(char c /*A*/)
+_putc:
+ ld (0xff01), a
+ ld a, #0x81
+ ld (0xff02), a
+ ret
+
+ ;; void puts(const char *s /*DE*/) - write until NUL (no newline)
+_puts:
+1$: ld a, (de)
+ or a
+ ret z
+ ld (0xff01), a
+ ld a, #0x81
+ ld (0xff02), a
+ inc de
+ jr 1$
+
+ ;; void nl(void) - CRLF
_nl:
ld a, #0x0d
ld (0xff01), a
@@ -24,31 +53,34 @@ _nl:
ld a, #0x81
ld (0xff02), a
ret
- ;; unsigned char readc(void) -> A
+
+ ;; unsigned char strlen(const char *s /*DE*/) -> A
+_strlen:
+ ld c, #0
+1$: ld a, (de)
+ or a
+ jr z, 2$
+ inc c
+ inc de
+ jr 1$
+2$: ld a, c
+ ret
+
+ ;; char readc(void) -> A (4 = EOF)
_readc:
- push hl
- push de
- push bc
- ld c, #2 ; SYS_READ
+ ld c, #2 ; SYS_READ
rst #0x30
- pop bc
- pop de
- pop hl
ret
- ;; void sexit(unsigned char code /*A*/)
+
+ ;; void sexit(unsigned char code /*A*/) - never returns
_sexit:
ld b, a
- ld c, #0 ; SYS_EXIT
+ ld c, #0 ; SYS_EXIT
rst #0x30
ret
+
;; unsigned char getpid(void) -> A
_getpid:
- push hl
- push de
- push bc
- ld c, #8 ; SYS_GETPID
+ ld c, #8 ; SYS_GETPID
rst #0x30
- pop bc
- pop de
- pop hl
ret
diff --git a/c/pid.c b/c/pid.c
new file mode 100644
index 0000000..a282a89
--- /dev/null
+++ b/c/pid.c
@@ -0,0 +1,9 @@
+#include "gbos.h"
+/* print an unsigned byte as decimal (no runtime division: subtract-based) */
+static void putu(unsigned char n) {
+ char buf[3]; unsigned char i = 0;
+ if (n == 0) { putc('0'); return; }
+ while (n) { buf[i++] = '0' + (n % 10); n = n / 10; }
+ while (i) putc(buf[--i]);
+}
+void main(void) { putu(getpid()); nl(); }
diff --git a/c/true.c b/c/true.c
new file mode 100644
index 0000000..4cf437e
--- /dev/null
+++ b/c/true.c
@@ -0,0 +1,2 @@
+#include "gbos.h"
+void main(void) { sexit(0); }
diff --git a/c/uname.c b/c/uname.c
new file mode 100644
index 0000000..511501d
--- /dev/null
+++ b/c/uname.c
@@ -0,0 +1,2 @@
+#include "gbos.h"
+void main(void) { puts("gbos sm83 (Game Boy Color)"); nl(); }