aboutsummaryrefslogtreecommitdiffstats
path: root/usr/libc.s
diff options
context:
space:
mode:
Diffstat (limited to 'usr/libc.s')
-rw-r--r--usr/libc.s304
1 files changed, 304 insertions, 0 deletions
diff --git a/usr/libc.s b/usr/libc.s
new file mode 100644
index 0000000..5b176d9
--- /dev/null
+++ b/usr/libc.s
@@ -0,0 +1,304 @@
+ .module libc
+ .globl _writes, _putc, _puts, _nl, _strlen, _readc, _sexit, _getpid, _getargs
+ .globl _open, _close, _fgetc, _fputc, _flist, _fremove, _pipe, _ssend, _srecv, _srecv_nb, _pollin, _pollcon
+ .globl _sys_net, _gsleep
+ ;; 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:
+ ld b, a
+ ld c, #3 ; SYS_WRITE
+ rst #0x30
+ ret
+
+ ;; 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*/) -> stdout via SYS_PUTC
+_putc:
+ ld e, a
+ ld c, #16 ; SYS_PUTC
+ rst #0x30
+ ret
+
+ ;; void puts(const char *s /*DE*/) - write until NUL (no newline)
+_puts:
+1$: ld a, (de)
+ or a
+ ret z
+ push de
+ ld e, a
+ ld c, #16 ; SYS_PUTC
+ rst #0x30
+ pop de
+ inc de
+ jr 1$
+
+ ;; void nl(void) - CRLF via stdout
+_nl:
+ ld e, #0x0d
+ ld c, #16 ; SYS_PUTC
+ rst #0x30
+ ld e, #0x0a
+ ld c, #16
+ rst #0x30
+ ret
+
+ ;; 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:
+ ld c, #2 ; SYS_READ
+ rst #0x30
+ ret
+
+ ;; void sexit(unsigned char code /*A*/) - never returns
+_sexit:
+ ld b, a
+ ld c, #0 ; SYS_EXIT
+ rst #0x30
+ ret
+
+ ;; unsigned char getpid(void) -> A
+_getpid:
+ ld c, #8 ; SYS_GETPID
+ rst #0x30
+ ret
+
+ ;; unsigned char pipe(void) -> A (read fd; write end is read+1)
+_pipe:
+ ld c, #28 ; SYS_PIPE
+ rst #0x30
+ ret
+
+ ;; void ssend(unsigned char b /*A*/) -- link-port transmit
+_ssend:
+ ld e, a
+ ld c, #29 ; SYS_SSEND
+ rst #0x30
+ ret
+
+ ;; unsigned char srecv(void) -> A -- link-port receive (blocks)
+_srecv:
+ ld c, #30 ; SYS_SRECV
+ rst #0x30
+ ret
+
+ ;; int srecv_nb(void) -> byte, or -1 if none (non-blocking)
+_srecv_nb:
+ ld c, #31 ; SYS_SRECVNB
+ rst #0x30
+ jr c, 1$
+ ld c, a
+ ld b, #0
+ ret
+1$: ld bc, #0xffff
+ ret
+
+ ;; unsigned char sys_net(void *req /*DE*/) -> A -- socket layer trap
+_sys_net:
+ ld c, #33 ; SYS_NET (DE already = &netreq)
+ rst #0x30
+ ret
+
+ ;; void gsleep(unsigned char units /*A*/) - delay units*(1/64)s
+_gsleep:
+ ld b, a
+ ld c, #34 ; SYS_SLEEP
+ rst #0x30
+ ret
+
+ ;; unsigned char pollin(void) -> A (typed OSK char, or 0)
+_pollin:
+ ld c, #32 ; SYS_POLLIN
+ rst #0x30
+ ret
+
+ ;; unsigned char pollcon(void) -> A (queued console byte, or 0)
+_pollcon:
+ ld c, #35 ; SYS_POLLCON
+ rst #0x30
+ ret
+
+ ;; unsigned char open(const char *name /*DE*/, unsigned char mode /*A*/) -> A(fd)
+_open:
+ ld b, a ; B = mode
+ ld c, #4 ; SYS_OPEN
+ rst #0x30
+ ret
+
+ ;; void close(unsigned char fd /*A*/)
+_close:
+ ld b, a
+ ld c, #5 ; SYS_CLOSE
+ rst #0x30
+ ret
+
+ ;; int fgetc(unsigned char fd /*A*/) -> BC (byte, or -1 at EOF)
+_fgetc:
+ ld b, a
+ ld c, #12 ; SYS_GETB
+ rst #0x30
+ jr c, 1$
+ ld c, a
+ ld b, #0
+ ret
+1$: ld bc, #0xffff
+ ret
+
+ ;; void fputc(unsigned char fd /*A*/, char ch /*E*/)
+ ;; byte goes to the kernel in E (the trap clobbers A during dispatch)
+_fputc:
+ ld b, a ; B = fd (ch stays in E)
+ ld c, #13 ; SYS_PUTB
+ rst #0x30
+ ret
+
+ ;; unsigned char flist(unsigned char slot /*A*/, char *namebuf /*DE*/) -> A
+_flist:
+ ld b, a
+ ld c, #14 ; SYS_LIST
+ rst #0x30
+ ret
+
+ ;; void fremove(const char *name /*DE*/)
+_fremove:
+ ld c, #15 ; SYS_REMOVE
+ rst #0x30
+ ret
+
+ .globl _fork, _exec, _wait, _setin, _setout, _lookup
+ ;; unsigned char fork(void) -> A (child pid in parent, 0 in child)
+_fork:
+ ld c, #1 ; SYS_FORK
+ rst #0x30
+ ret
+ ;; void exec(unsigned char id /*A*/) - never returns
+_exec:
+ ld b, a
+ ld c, #6 ; SYS_EXEC
+ rst #0x30
+ ret
+ ;; unsigned char wait(void) -> A (reaped pid)
+_wait:
+ ld c, #7 ; SYS_WAIT
+ rst #0x30
+ ret
+ ;; void setin(unsigned char fd /*A*/)
+_setin:
+ ld b, a
+ ld c, #17 ; SYS_SETIN
+ rst #0x30
+ ret
+ ;; void setout(unsigned char fd /*A*/)
+_setout:
+ ld b, a
+ ld c, #18 ; SYS_SETOUT
+ rst #0x30
+ ret
+ ;; unsigned char lookup(const char *name /*DE*/) -> A (prog id or $FF)
+_lookup:
+ ld c, #19 ; SYS_LOOKUP
+ rst #0x30
+ ret
+
+ .globl _kill, _psget, _progname
+ ;; unsigned char kill(unsigned char pid /*A*/) -> A (0 ok, $FF fail)
+_kill:
+ ld b, a
+ ld c, #9 ; SYS_KILL
+ rst #0x30
+ ret
+ ;; unsigned char psget(unsigned char slot /*A*/, unsigned char *buf /*DE*/) -> A
+_psget:
+ ld b, a
+ ld c, #20 ; SYS_PS
+ rst #0x30
+ ret
+ ;; void progname(unsigned char id /*A*/, char *buf /*DE*/)
+_progname:
+ ld b, a
+ ld c, #21 ; SYS_PROGNAME
+ rst #0x30
+ ret
+
+ .globl _yield, _reap
+ ;; void yield(void)
+_yield:
+ ld c, #11 ; SYS_YIELD
+ rst #0x30
+ ret
+ ;; unsigned char reap(void) -> A (reaped pid, or 0)
+_reap:
+ ld c, #22 ; SYS_REAP
+ rst #0x30
+ ret
+
+ .globl _bfill, _bpeek, _bpeek2
+ ;; void bfill(unsigned char block /*A*/, unsigned char byte /*E*/)
+_bfill:
+ ld b, a
+ ld c, #23 ; SYS_BFILL
+ rst #0x30
+ ret
+ ;; unsigned char bpeek(unsigned char block /*A*/) -> A
+_bpeek:
+ ld b, a
+ ld e, #0
+ ld c, #24 ; SYS_BPEEK
+ rst #0x30
+ ret
+ ;; unsigned char bpeek2(unsigned char block /*A*/, unsigned char off /*E*/) -> A
+_bpeek2:
+ ld b, a
+ ld c, #24 ; SYS_BPEEK (off already in E)
+ rst #0x30
+ ret
+
+
+ .globl _mkdir, _chdir
+ ;; unsigned char mkdir(const char *path /*DE*/) -> A (0 ok / $FF)
+_mkdir:
+ ld c, #25 ; SYS_MKDIR
+ rst #0x30
+ ret
+ ;; unsigned char chdir(const char *path /*DE*/) -> A (0 ok / $FF)
+_chdir:
+ ld c, #26 ; SYS_CHDIR
+ rst #0x30
+ ret
+
+ .globl _opendir
+ ;; unsigned char opendir(const char *path /*DE*/) -> A (0 ok / $FF)
+_opendir:
+ ld c, #27 ; SYS_OPENDIR
+ rst #0x30
+ ret
+
+ .globl _poweroff
+ ;; void poweroff(void) - execute the emulator's clean-exit opcode ($ED)
+_poweroff:
+ .db 0xED
+1$: jr 1$