shell/stdio: decouple from blkdev (again)

Move load/save to blkdev_cmds and add a new "poke" builtin shell cmd
that is the mirror of "peek" and strictly uses stdio (no blkdev
involved).

This allows us to slim the minimal OS size but, more importantly, change
the behavior of "load" so that we don't expect GetC to block until Z is
set. This way, using "load X" with X being larger than the blkdev size
won't block forever.

This also brings our RC2014 minimal kernel below the 1K mark again.
This commit is contained in:
Virgil Dupras 2019-06-02 10:50:18 -04:00
parent 88bf98321e
commit 73c3fc7947
7 changed files with 92 additions and 81 deletions

View File

@ -150,7 +150,9 @@ blkGetC:
blkGetCW: blkGetCW:
ld ix, (BLOCKDEV_GETC) ld ix, (BLOCKDEV_GETC)
.loop: .loop:
push ix ; fs messes with IX a lot
call callIX call callIX
pop ix
jr nz, .loop jr nz, .loop
ret ret

View File

@ -44,3 +44,60 @@ blkSeekCmd:
xor a xor a
ret ret
; Load the specified number of bytes (max 0xff) from IO and write them in the
; current memory pointer (which doesn't change). This gets chars from
; blkGetCW.
; Control is returned to the shell only after all bytes are read.
;
; Example: load 42
blkLoadCmd:
.db "load", 0b001, 0, 0
blkLoad:
push bc
push hl
ld a, (hl)
ld b, a
ld hl, (SHELL_MEM_PTR)
.loop: call blkGetCW
jr nz, .ioError
ld (hl), a
inc hl
djnz .loop
; success
xor a
jr .end
.ioError:
ld a, SHELL_ERR_IO_ERROR
.end:
pop hl
pop bc
ret
; Load the specified number of bytes (max 0xff) from the current memory pointer
; and write them to I/O. Memory pointer doesn't move. This puts chars to
; blkPutC.
; Control is returned to the shell only after all bytes are written.
;
; Example: save 42
blkSaveCmd:
.db "save", 0b001, 0, 0
blkSave:
push bc
push hl
ld a, (hl)
ld b, a
ld hl, (SHELL_MEM_PTR)
.loop:
ld a, (hl)
inc hl
call blkPutC
djnz .loop
.end:
pop hl
pop bc
xor a
ret

View File

@ -22,7 +22,6 @@
; *** REQUIREMENTS *** ; *** REQUIREMENTS ***
; parse ; parse
; stdio ; stdio
; blkdev
; *** DEFINES *** ; *** DEFINES ***
; SHELL_EXTRA_CMD_COUNT: Number of extra cmds to be expected after the regular ; SHELL_EXTRA_CMD_COUNT: Number of extra cmds to be expected after the regular
@ -32,7 +31,7 @@
; *** CONSTS *** ; *** CONSTS ***
; number of entries in shellCmdTbl ; number of entries in shellCmdTbl
.equ SHELL_CMD_COUNT 7+SHELL_EXTRA_CMD_COUNT .equ SHELL_CMD_COUNT 6+SHELL_EXTRA_CMD_COUNT
; maximum number of bytes to receive as args in all commands. Determines the ; maximum number of bytes to receive as args in all commands. Determines the
; size of the args variable. ; size of the args variable.
@ -411,58 +410,29 @@ shellPeek:
xor a xor a
ret ret
; Load the specified number of bytes (max 0xff) from IO and write them in the ; poke byte where memory pointer points and set them to bytes types through
; current memory pointer (which doesn't change). This gets chars from ; stdioGetC. If the optional numerical byte arg is supplied, this number of
; blkGetCW. ; bytes will be expected from stdioGetC. Blocks until all bytes have been
; Control is returned to the shell only after all bytes are read. ; fetched.
; shellPokeCmd:
; Example: load 42 .db "poke", 0b101, 0, 0
shellLoadCmd: shellPoke:
.db "load", 0b001, 0, 0
shellLoad:
push bc push bc
push hl push hl
ld a, (hl) ld a, (hl)
or a ; cp 0
jr nz, .arg1isset ; if arg1 is set, no need for a default
ld a, 1 ; default for arg1
.arg1isset:
ld b, a ld b, a
ld hl, (SHELL_MEM_PTR) ld hl, (SHELL_MEM_PTR)
.loop: call blkGetCW .loop: call stdioGetC
jr nz, .ioError jr nz, .loop ; nothing typed? loop
ld (hl), a ld (hl), a
inc hl inc hl
djnz .loop djnz .loop
; success
xor a
jr .end
.ioError:
ld a, SHELL_ERR_IO_ERROR
.end:
pop hl
pop bc
ret
; Load the specified number of bytes (max 0xff) from the current memory pointer
; and write them to I/O. Memory pointer doesn't move. This puts chars to
; blkPutC.
; Control is returned to the shell only after all bytes are written.
;
; Example: save 42
shellSaveCmd:
.db "save", 0b001, 0, 0
shellSave:
push bc
push hl
ld a, (hl)
ld b, a
ld hl, (SHELL_MEM_PTR)
.loop:
ld a, (hl)
inc hl
call blkPutC
djnz .loop
.end:
pop hl pop hl
pop bc pop bc
xor a xor a
@ -530,6 +500,6 @@ shellIOWRCmd:
; This table is at the very end of the file on purpose. The idea is to be able ; This table is at the very end of the file on purpose. The idea is to be able
; to graft extra commands easily after an include in the glue file. ; to graft extra commands easily after an include in the glue file.
shellCmdTbl: shellCmdTbl:
.dw shellMptrCmd, shellPeekCmd, shellLoadCmd, shellSaveCmd, shellCallCmd .dw shellMptrCmd, shellPeekCmd, shellPokeCmd, shellCallCmd
.dw shellIORDCmd, shellIOWRCmd .dw shellIORDCmd, shellIOWRCmd

View File

@ -1,12 +1,9 @@
; stdio ; stdio
; ;
; Allows other modules to print to "standard out", that is, the console through ; Allows other modules to print to "standard out", and get data from "stamdard
; which the user is connected in a decoupled manner. ; in", that is, the console through which the user is connected in a decoupled
; manner.
; ;
; *** REQUIREMENTS ***
; blkdev. select the block device you want to use as stdio just before you call
; stdioInit.
; *** VARIABLES *** ; *** VARIABLES ***
; Used to store formatted hex values just before printing it. ; Used to store formatted hex values just before printing it.
.equ STDIO_HEX_FMT STDIO_RAMSTART .equ STDIO_HEX_FMT STDIO_RAMSTART
@ -14,14 +11,10 @@
.equ STDIO_PUTC STDIO_GETC+2 .equ STDIO_PUTC STDIO_GETC+2
.equ STDIO_RAMEND STDIO_PUTC+2 .equ STDIO_RAMEND STDIO_PUTC+2
; Select the blockdev to use as stdio before calling this. ; Sets GetC to the routine where HL points to and PutC to DE.
stdioInit: stdioInit:
push hl
ld hl, (BLOCKDEV_GETC)
ld (STDIO_GETC), hl ld (STDIO_GETC), hl
ld hl, (BLOCKDEV_PUTC) ld (STDIO_PUTC), de
ld (STDIO_PUTC), hl
pop hl
ret ret
stdioGetC: stdioGetC:

View File

@ -16,13 +16,7 @@ jp aciaInt
.equ ACIA_RAMSTART RAMSTART .equ ACIA_RAMSTART RAMSTART
#include "acia.asm" #include "acia.asm"
.equ BLOCKDEV_RAMSTART ACIA_RAMEND .equ STDIO_RAMSTART ACIA_RAMEND
.equ BLOCKDEV_COUNT 1
#include "blockdev.asm"
; List of devices
.dw aciaGetC, aciaPutC, 0, 0
.equ STDIO_RAMSTART BLOCKDEV_RAMEND
#include "stdio.asm" #include "stdio.asm"
.equ SHELL_RAMSTART STDIO_RAMEND .equ SHELL_RAMSTART STDIO_RAMEND
@ -37,9 +31,8 @@ init:
im 1 im 1
call aciaInit call aciaInit
xor a ld hl, aciaGetC
ld de, BLOCKDEV_GETC ld de, aciaPutC
call blkSel
call stdioInit call stdioInit
call shellInit call shellInit
ei ei

View File

@ -17,10 +17,9 @@
#include "parse.asm" #include "parse.asm"
.equ BLOCKDEV_RAMSTART RAMSTART .equ BLOCKDEV_RAMSTART RAMSTART
.equ BLOCKDEV_COUNT 4 .equ BLOCKDEV_COUNT 3
#include "blockdev.asm" #include "blockdev.asm"
; List of devices ; List of devices
.dw emulGetC, emulPutC, 0, 0
.dw fsdevGetC, fsdevPutC, fsdevSeek, fsdevTell .dw fsdevGetC, fsdevPutC, fsdevSeek, fsdevTell
.dw stdoutGetC, stdoutPutC, stdoutSeek, stdoutTell .dw stdoutGetC, stdoutPutC, stdoutSeek, stdoutTell
.dw stdinGetC, stdinPutC, stdinSeek, stdinTell .dw stdinGetC, stdinPutC, stdinSeek, stdinTell
@ -36,9 +35,10 @@
#include "fs_cmds.asm" #include "fs_cmds.asm"
.equ SHELL_RAMSTART FS_RAMEND .equ SHELL_RAMSTART FS_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 7 .equ SHELL_EXTRA_CMD_COUNT 9
#include "shell.asm" #include "shell.asm"
.dw blkBselCmd, blkSeekCmd, fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd .dw blkBselCmd, blkSeekCmd, blkLoadCmd, blkSaveCmd
.dw fsOnCmd, flsCmd, fnewCmd, fdelCmd, fopnCmd
.equ PGM_CODEADDR USERCODE .equ PGM_CODEADDR USERCODE
#include "pgm.asm" #include "pgm.asm"
@ -48,18 +48,14 @@ init:
; setup stack ; setup stack
ld hl, KERNEL_RAMEND ld hl, KERNEL_RAMEND
ld sp, hl ld sp, hl
xor a ld hl, emulGetC
ld de, BLOCKDEV_GETC ld de, emulPutC
call blkSel
call stdioInit call stdioInit
call fsInit call fsInit
ld a, 1 ; select fsdev ld a, 0 ; select fsdev
ld de, BLOCKDEV_GETC ld de, BLOCKDEV_GETC
call blkSel call blkSel
call fsOn call fsOn
xor a ; select ACIA
ld de, BLOCKDEV_GETC
call blkSel
call shellInit call shellInit
ld hl, pgmShellHook ld hl, pgmShellHook
ld (SHELL_CMDHOOK), hl ld (SHELL_CMDHOOK), hl

View File

@ -32,8 +32,8 @@ def main():
print("File too big. 0xff bytes max") print("File too big. 0xff bytes max")
return 1 return 1
fd = os.open(args.device, os.O_RDWR) fd = os.open(args.device, os.O_RDWR)
sendcmd(fd, 'load {:x}'.format(st.st_size).encode()) sendcmd(fd, 'poke {:x}'.format(st.st_size).encode())
print("Loading...") print("Poking...")
with open(args.filename, 'rb') as fp: with open(args.filename, 'rb') as fp:
fcontents = fp.read() fcontents = fp.read()
for c in fcontents: for c in fcontents:
@ -41,7 +41,7 @@ def main():
# Let's give the machine a bit of time to breathe. We ain't in a # Let's give the machine a bit of time to breathe. We ain't in a
# hurry now, are we? # hurry now, are we?
time.sleep(0.0001) time.sleep(0.0001)
print("Loaded") print("Poked")
os.read(fd, 5) os.read(fd, 5)
print("Peeking back...") print("Peeking back...")
sendcmd(fd, 'peek {:x}'.format(st.st_size).encode()) sendcmd(fd, 'peek {:x}'.format(st.st_size).encode())