aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kdata.asm1
-rw-r--r--src/proc.asm19
-rw-r--r--src/programs.asm181
-rw-r--r--src/syscall.asm146
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
; -----------------------------------------------------------------------------