.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, _gticks ;; 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 ;; void gticks(unsigned char buf[4] /*DE*/) - 64 Hz uptime ticks, LE _gticks: ld c, #36 ; SYS_UPTIME 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$