.module libc .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: 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*/) _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 ld a, #0x81 ld (0xff02), a ld a, #0x0a ld (0xff01), a ld a, #0x81 ld (0xff02), a 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