diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/kdata.asm | 1 | ||||
| -rw-r--r-- | src/proc.asm | 19 | ||||
| -rw-r--r-- | src/programs.asm | 181 | ||||
| -rw-r--r-- | src/syscall.asm | 146 |
4 files changed, 193 insertions, 154 deletions
diff --git a/src/kdata.asm b/src/kdata.asm index 9aca466..ea18756 100644 --- a/src/kdata.asm +++ b/src/kdata.asm @@ -45,3 +45,4 @@ wFsMode:: DS 1 wFsSlot:: DS 1 wFsByte:: DS 1 wFsOFPtr:: DS 2 +wKChar:: DS 1 ; scratch for KPutc diff --git a/src/proc.asm b/src/proc.asm index a2b1368..ab1c807 100644 --- a/src/proc.asm +++ b/src/proc.asm @@ -221,7 +221,10 @@ ProcCreate:: ld [hl+], a ; PROC_WRAMB xor a ld [hl+], a ; PROC_PARENT - ld [hl], a ; PROC_EXIT + ld [hl+], a ; PROC_EXIT + ld a, STD_CONSOLE + ld [hl+], a ; PROC_STDIN = console + ld [hl], a ; PROC_STDOUT = console ; build the initial stack frame in the task's RAM bank ld a, [wTmpEntry] @@ -438,7 +441,19 @@ sys_fork:: ld [hl+], a ; PROC_EXIT = 0 xor a - ld [hl], a + ld [hl+], a + ; PROC_STDIN / PROC_STDOUT = inherit from parent + ld a, [wCurProc] + add PROC_STDIN + ld e, a + ld a, [wCurProc+1] + adc 0 + ld d, a + ld a, [de] + ld [hl+], a ; child STDIN = parent STDIN + inc de + ld a, [de] + ld [hl], a ; child STDOUT = parent STDOUT ; ---- return to the parent with child pid ---- ld a, [wForkUserSP] diff --git a/src/programs.asm b/src/programs.asm index 161ee2f..1a7092e 100644 --- a/src/programs.asm +++ b/src/programs.asm @@ -90,149 +90,13 @@ ProgRm: INCBIN "c/rm.bin" ; ----------------------------------------------------------------------------- -; PROG_SH (bank 3) - a tiny shell. -; prompt -> read a line (with echo) -> match a command -> fork+exec+wait. +; PROG_SH (bank 3) - the shell, now written in C (c/sh.c): parses >/</| and +; drives fork+exec+wait with I/O redirection. Command lookup + StrEqual/SkipName +; live in the kernel now (sys_lookup + NameTable + shell_lib). ; ----------------------------------------------------------------------------- SECTION "prog_sh", ROMX[$4000], BANK[3] ProgSh: -.prompt - ld de, .ps1 - ld b, 2 - ld c, SYS_WRITE - rst $30 - - ; read a line into SH_LINEBUF, echoing as we go - ld hl, SH_LINEBUF -.rd - push hl ; syscalls clobber HL (trap uses it to dispatch) - ld c, SYS_READ - rst $30 ; A = input byte - pop hl - cp $04 - jr z, .eof ; Ctrl-D / EOF: exit the shell - cp $0D - jr z, .eol - cp $0A - jr z, .eol - ld [hl], a ; store in the line buffer (A preserved) - inc hl - ld [$FF01], a ; echo the char straight to serial - ld a, $81 - ld [$FF02], a - ld a, l - cp LOW(SH_LINEBUF) + SH_MAXLINE - 1 - jr c, .rd ; keep reading unless the buffer is full - -.eof - ld b, 0 - ld c, SYS_EXIT ; exit init/shell -> system idle - rst $30 - -.eol - ld [hl], 0 ; NUL-terminate - ld de, .crlf - ld b, 2 - ld c, SYS_WRITE - rst $30 - ld a, [SH_LINEBUF] - or a - jp z, .prompt ; empty line - - ; split off the first word: replace the first space with a NUL so command - ; matching sees just the command, and the args survive at SH_LINEBUF+n - ; (inherited by the child through fork, read back via main(char *args)). - ld hl, SH_LINEBUF -.split - ld a, [hl] - or a - jr z, .lookup ; no space -> no args - cp $20 - jr z, .cut - inc hl - jr .split -.cut - ld [hl], 0 ; isolate the command word - -.lookup - ; look the command up in the table - ld de, .cmdtab -.scan - ld a, [de] - or a - jr z, .unknown ; empty name = end of table - push de - ld hl, SH_LINEBUF - call StrEqual ; Z set if equal - pop de - jr z, .match - call SkipName ; DE -> NUL after this name - inc de ; -> program id - inc de ; -> next entry - jr .scan - -.match - call SkipName - inc de ; DE -> program id - ld a, [de] - ld [SH_PROGID], a - ld c, SYS_FORK - rst $30 - or a - jr z, .exec - ld c, SYS_WAIT ; parent: reap the command - rst $30 - jp .prompt -.exec - ld a, [SH_PROGID] - ld b, a - ld c, SYS_EXEC - rst $30 ; child becomes the command - -.unknown - ld de, .huh - ld b, 3 - ld c, SYS_WRITE - rst $30 - jp .prompt - -.ps1 - db "$ " -.crlf - db $0D, $0A -.huh - db "?", $0D, $0A -.cmdtab - db "worker", 0 - db PROG_WORKER - db "hello", 0 - db PROG_HELLO - db "chello", 0 - db PROG_CHELLO - db "echo", 0 - db PROG_ECHO - db "true", 0 - db PROG_TRUE - db "false", 0 - db PROG_FALSE - db "uname", 0 - db PROG_UNAME - db "pid", 0 - db PROG_PID - db "cat", 0 - db PROG_CAT - db "wc", 0 - db PROG_WC - db "head", 0 - db PROG_HEAD - db "args", 0 - db PROG_ARGS - db "ls", 0 - db PROG_LS - db "save", 0 - db PROG_SAVE - db "rm", 0 - db PROG_RM - db 0 ; terminator + INCBIN "c/sh.bin" ; ----------------------------------------------------------------------------- ; Shell string helpers (ROM0, always mapped). @@ -298,3 +162,40 @@ ProgramTable:: dw ProgSave db LOW(BANK(ProgRm)), HIGH(BANK(ProgRm)) dw ProgRm + +; ----------------------------------------------------------------------------- +; NameTable (ROM0) - command name -> program id, searched by sys_lookup. +; ----------------------------------------------------------------------------- +SECTION "nametab", ROM0 +NameTable:: + db "worker", 0 + db PROG_WORKER + db "hello", 0 + db PROG_HELLO + db "chello", 0 + db PROG_CHELLO + db "echo", 0 + db PROG_ECHO + db "true", 0 + db PROG_TRUE + db "false", 0 + db PROG_FALSE + db "uname", 0 + db PROG_UNAME + db "pid", 0 + db PROG_PID + db "cat", 0 + db PROG_CAT + db "wc", 0 + db PROG_WC + db "head", 0 + db PROG_HEAD + db "args", 0 + db PROG_ARGS + db "ls", 0 + db PROG_LS + db "save", 0 + db PROG_SAVE + db "rm", 0 + db PROG_RM + db 0 diff --git a/src/syscall.asm b/src/syscall.asm index 5ed3d6f..f149a76 100644 --- a/src/syscall.asm +++ b/src/syscall.asm @@ -50,6 +50,10 @@ SyscallTable: dw sys_putb ; 13 PUTB dw sys_list ; 14 LIST dw sys_remove ; 15 REMOVE + dw sys_putc ; 16 PUTC + dw sys_setin ; 17 SETIN + dw sys_setout ; 18 SETOUT + dw sys_lookup ; 19 LOOKUP ; ----------------------------------------------------------------------------- sys_nosys: @@ -64,33 +68,151 @@ sys_write: ld a, b or a ret z ; len 0 - ld c, b ; C = remaining .loop ld a, [de] - call PutChar + push de + push bc + ld e, a + call KPutc ; route the byte to this process's stdout + pop bc + pop de inc de - dec c + dec b jr nz, .loop - ld a, b ; return len ret ; ----------------------------------------------------------------------------- -; sys_read() -> A = one input byte from the console (blocking). -; Uses an external-clock serial transfer as a clean RX: it completes only when -; the host has a byte (no stdout echo). While waiting we yield so other procs -; run. Preserves BC/DE/HL (the context switch saves/restores them). +; CurStdin / CurStdout -> A = current process PROC_STDIN / PROC_STDOUT ; ----------------------------------------------------------------------------- -sys_read: +CurStdin: + ld a, [wCurProc] + add PROC_STDIN + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, [hl] + ret +CurStdout: + ld a, [wCurProc] + add PROC_STDOUT + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, [hl] + ret + +; ----------------------------------------------------------------------------- +; KGetc -> A = byte, CF set on EOF. Reads this process's stdin (console/file). +; ----------------------------------------------------------------------------- +KGetc:: + call CurStdin + cp STD_CONSOLE + jr z, .console + ld b, a + jp sys_getb ; B=fd -> A=byte, CF=EOF +.console .poll ld a, $80 - ld [rSC], a ; request a byte (external clock) + ld [rSC], a ld a, [rSC] bit 7, a - jr z, .got ; bit7 clear => transfer completed - call SchedYield ; nothing yet: let others run, then retry + jr z, .got + call SchedYield jr .poll .got ld a, [rSB] + and a ; CF = 0 + ret + +; ----------------------------------------------------------------------------- +; KPutc(E = byte) - write to this process's stdout (console/file). +; ----------------------------------------------------------------------------- +KPutc:: + ld a, e + ld [wKChar], a + call CurStdout + cp STD_CONSOLE + jr z, .console + ld b, a ; fd + ld a, [wKChar] + ld e, a + jp sys_putb ; B=fd, E=byte +.console + ld a, [wKChar] + ld [rSB], a + ld a, $81 + ld [rSC], a + ret + +; ----------------------------------------------------------------------------- +; sys_putc(E = byte), sys_setin/sys_setout(B = fd) +; ----------------------------------------------------------------------------- +sys_putc: + call KPutc + ret +sys_setin: + ld a, [wCurProc] + add PROC_STDIN + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, b + ld [hl], a + ret +sys_setout: + ld a, [wCurProc] + add PROC_STDOUT + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, b + ld [hl], a + ret + +; ----------------------------------------------------------------------------- +; sys_lookup(DE = name) -> A = program id, or $FF if not a known command. +; ----------------------------------------------------------------------------- +sys_lookup: + ld h, d + ld l, e ; HL = query name + ld de, NameTable +.l + ld a, [de] + or a + jr z, .none + push hl + push de + call StrEqual ; HL=query vs DE=table name -> Z if equal + pop de + pop hl + jr z, .match + call SkipName ; DE -> NUL + inc de ; -> id + inc de ; -> next entry + jr .l +.match + call SkipName + inc de ; -> id + ld a, [de] + ret +.none + ld a, $FF + ret + +; ----------------------------------------------------------------------------- +; sys_read() -> A = one input byte from the console (blocking). +; Uses an external-clock serial transfer as a clean RX: it completes only when +; the host has a byte (no stdout echo). While waiting we yield so other procs +; run. Preserves BC/DE/HL (the context switch saves/restores them). +; ----------------------------------------------------------------------------- +sys_read: + call KGetc ; A=byte, CF=EOF (file); console EOF is $04 + ret nc + ld a, $04 ; file EOF -> EOT ret ; ----------------------------------------------------------------------------- |
