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:
ld ix, (BLOCKDEV_GETC)
.loop:
push ix ; fs messes with IX a lot
call callIX
pop ix
jr nz, .loop
ret

View File

@ -44,3 +44,60 @@ blkSeekCmd:
xor a
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 ***
; parse
; stdio
; blkdev
; *** DEFINES ***
; SHELL_EXTRA_CMD_COUNT: Number of extra cmds to be expected after the regular
@ -32,7 +31,7 @@
; *** CONSTS ***
; 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
; size of the args variable.
@ -411,58 +410,29 @@ shellPeek:
xor a
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
shellLoadCmd:
.db "load", 0b001, 0, 0
shellLoad:
; poke byte where memory pointer points and set them to bytes types through
; stdioGetC. If the optional numerical byte arg is supplied, this number of
; bytes will be expected from stdioGetC. Blocks until all bytes have been
; fetched.
shellPokeCmd:
.db "poke", 0b101, 0, 0
shellPoke:
push bc
push 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 hl, (SHELL_MEM_PTR)
.loop: call blkGetCW
jr nz, .ioError
.loop: call stdioGetC
jr nz, .loop ; nothing typed? loop
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
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 bc
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
; to graft extra commands easily after an include in the glue file.
shellCmdTbl:
.dw shellMptrCmd, shellPeekCmd, shellLoadCmd, shellSaveCmd, shellCallCmd
.dw shellMptrCmd, shellPeekCmd, shellPokeCmd, shellCallCmd
.dw shellIORDCmd, shellIOWRCmd

View File

@ -1,12 +1,9 @@
; stdio
;
; Allows other modules to print to "standard out", that is, the console through
; which the user is connected in a decoupled manner.
; Allows other modules to print to "standard out", and get data from "stamdard
; 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 ***
; Used to store formatted hex values just before printing it.
.equ STDIO_HEX_FMT STDIO_RAMSTART
@ -14,14 +11,10 @@
.equ STDIO_PUTC STDIO_GETC+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:
push hl
ld hl, (BLOCKDEV_GETC)
ld (STDIO_GETC), hl
ld hl, (BLOCKDEV_PUTC)
ld (STDIO_PUTC), hl
pop hl
ld (STDIO_PUTC), de
ret
stdioGetC:

View File

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

View File

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

View File

@ -32,8 +32,8 @@ def main():
print("File too big. 0xff bytes max")
return 1
fd = os.open(args.device, os.O_RDWR)
sendcmd(fd, 'load {:x}'.format(st.st_size).encode())
print("Loading...")
sendcmd(fd, 'poke {:x}'.format(st.st_size).encode())
print("Poking...")
with open(args.filename, 'rb') as fp:
fcontents = fp.read()
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
# hurry now, are we?
time.sleep(0.0001)
print("Loaded")
print("Poked")
os.read(fd, 5)
print("Peeking back...")
sendcmd(fd, 'peek {:x}'.format(st.st_size).encode())