Add blockdev part

Also, add the ability for parts to define extra shell commands.
This commit is contained in:
Virgil Dupras 2019-04-15 16:53:11 -04:00
parent 4600b5299c
commit 12c23f52e0
3 changed files with 139 additions and 8 deletions

108
parts/blockdev.asm Normal file
View File

@ -0,0 +1,108 @@
; blockdev
;
; A block device is an abstraction over something we can read from, write to.
;
; A device that fits this abstraction puts the properly hook into itself, and
; then the glue code assigns a blockdev ID to that device. It then becomes easy
; to access arbitrary devices in a convenient manner.
;
; This part exposes a new "bsel" command to select the currently active block
; device.
; *** DEFINES ***
; BLOCKDEV_COUNT: The number of devices we manage.
; *** CONSTS ***
; *** VARIABLES ***
; A memory pointer to a device table. A device table is a list of addresses
; pointing to GetC and PutC routines.
BLOCKDEV_TBL .equ BLOCKDEV_RAMSTART
; Index of the current blockdev selection
BLOCKDEV_SELIDX .equ BLOCKDEV_TBL+(BLOCKDEV_COUNT*4)
; Address of the current GetC routine
BLOCKDEV_GETC .equ BLOCKDEV_SELIDX+1
; Address of the current PutC routine
BLOCKDEV_PUTC .equ BLOCKDEV_GETC+2
BLOCKDEV_RAMEND .equ BLOCKDEV_PUTC+2
; *** CODE ***
; set DE to point to the table entry at index A.
blkFind:
ld de, BLOCKDEV_TBL
cp 0
ret z ; index is zero? don't loop
push bc
ld b, a
push af
ld a, 4
.loop:
call addDE
djnz .loop
pop af
pop bc
ret
; Set the GetC pointer of device id A to the value in HL
blkSetGetC:
call blkFind
call writeHLinDE
ret
; Set the GetC pointer of device id A to the value in HL
blkSetPutC:
call blkFind
inc de
inc de
call writeHLinDE
ret
; Select block index specified in A
blkSel:
call blkFind
ld (BLOCKDEV_SELIDX), a
ex hl, de
; now, HL points to the table entry
ld de, BLOCKDEV_GETC
ldi ; copy (HL) into (BLOCKDEV_GETC)
ldi ; .. and into +1
ld de, BLOCKDEV_PUTC
ldi ; same thing for (BLOCKDEV_PUTC)
ldi
ret
blkBselCmd:
.db "bsel", 0b001, 0, 0
blkBsel:
ret
push af
ld a, (hl) ; argument supplied
cp BLOCKDEV_COUNT
ret nz ; if selection >= device count, don't do anything
; (will devise a unified cmd error system later)
call blkSel
pop af
ret
; Reads one character from blockdev ID specified at A and returns its value
; in A. Always returns a character and waits until read if it has to.
blkGetC:
push ix
push de
ld de, (BLOCKDEV_GETC)
ld ixh, d
ld ixl, e
pop de
call callIX
pop ix
ret
blkPutC:
push ix
push de
ld de, (BLOCKDEV_PUTC)
ld ixh, d
ld ixl, e
pop de
call callIX
pop ix
ret

View File

@ -41,6 +41,18 @@ addHL:
ld l, a ld l, a
ret ret
; Write the contents of HL in (DE)
writeHLinDE:
push af
ld a, l
ld (de), a
inc de
ld a, h
ld (de), a
pop af
ret
; jump to the location pointed to by IX. This allows us to call IX instead of ; jump to the location pointed to by IX. This allows us to call IX instead of
; just jumping it. We use IX because we never use this for arguments. ; just jumping it. We use IX because we never use this for arguments.
callIX: callIX:

View File

@ -14,14 +14,17 @@
; hexadecimal form, without prefix or suffix. ; hexadecimal form, without prefix or suffix.
; *** DEFINES *** ; *** DEFINES ***
; SHELL_GETC: Macro that calls a GetC routine ; SHELL_GETC: Macro that calls a GetC routine for tty interface
; SHELL_PUTC: Macro that calls a PutC routine ; SHELL_PUTC: Macro that calls a PutC routine for tty interface
; SHELL_IO_GETC: Macro that calls a GetC routine for I/O ("load" cmd)
; SHELL_EXTRA_CMD_COUNT: Number of extra cmds to be expected after the regular
; ones. See comment in COMMANDS section for details.
; SHELL_RAMSTART ; SHELL_RAMSTART
; *** CONSTS *** ; *** CONSTS ***
; number of entries in shellCmdTbl ; number of entries in shellCmdTbl
SHELL_CMD_COUNT .equ 4 SHELL_CMD_COUNT .equ 4+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.
@ -144,6 +147,7 @@ shellParse:
pop de pop de
jr z, .found jr z, .found
inc de inc de
inc de
djnz .loop djnz .loop
; exhausted loop? not found ; exhausted loop? not found
@ -313,7 +317,12 @@ shellParseArgs:
; ;
; When these commands are called, HL points to the first byte of the ; When these commands are called, HL points to the first byte of the
; parsed command args. ; parsed command args.
;
; Extra commands: Other parts might define new commands. You can add these
; commands to your shell. First, set SHELL_EXTRA_CMD_COUNT to
; the number of extra commands to add, then add a ".dw"
; directive *just* after your '#include "shell.asm"'. Voila!
;
; Set memory pointer to the specified address (word). ; Set memory pointer to the specified address (word).
; Example: seek 01fe ; Example: seek 01fe
@ -388,9 +397,9 @@ shellPeek:
ret ret
; Load the specified number of bytes (max 0xff) from IO and write them in the ; Load the specified number of bytes (max 0xff) from IO and write them in the
; current memory pointer (which doesn't change). For now, we can only load from ; current memory pointer (which doesn't change). This gets chars from
; SHELL_GETC, but a method of selecting IO sources is coming, making this ; SHELL_IO_GETC, which can be different from SHELL_GETC. Coupled with the
; command much more useful. ; "blockdev" part, this allows you to dynamically select your IO source.
; Control is returned to the shell only after all bytes are read. ; Control is returned to the shell only after all bytes are read.
; ;
; Example: load 42 ; Example: load 42
@ -404,7 +413,7 @@ shellLoad:
ld a, (hl) ld a, (hl)
ld b, a ld b, a
ld hl, (SHELL_MEM_PTR) ld hl, (SHELL_MEM_PTR)
.loop: SHELL_GETC .loop: SHELL_IO_GETC
ld (hl), a ld (hl), a
inc hl inc hl
djnz .loop djnz .loop
@ -455,6 +464,8 @@ shellCall:
pop af pop af
ret ret
; 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: shellCmdTbl:
.dw shellSeekCmd, shellPeekCmd, shellLoadCmd, shellCallCmd .dw shellSeekCmd, shellPeekCmd, shellLoadCmd, shellCallCmd