From 12c23f52e06b27ba866e7cdb5da5684ed96922ad Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Mon, 15 Apr 2019 16:53:11 -0400 Subject: [PATCH] Add blockdev part Also, add the ability for parts to define extra shell commands. --- parts/blockdev.asm | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ parts/core.asm | 12 ++++++ parts/shell.asm | 27 ++++++++++---- 3 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 parts/blockdev.asm diff --git a/parts/blockdev.asm b/parts/blockdev.asm new file mode 100644 index 0000000..075fe2b --- /dev/null +++ b/parts/blockdev.asm @@ -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 diff --git a/parts/core.asm b/parts/core.asm index a39269a..9c4e957 100644 --- a/parts/core.asm +++ b/parts/core.asm @@ -41,6 +41,18 @@ addHL: ld l, a 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 ; just jumping it. We use IX because we never use this for arguments. callIX: diff --git a/parts/shell.asm b/parts/shell.asm index 16af7ad..bce4abb 100644 --- a/parts/shell.asm +++ b/parts/shell.asm @@ -14,14 +14,17 @@ ; hexadecimal form, without prefix or suffix. ; *** DEFINES *** -; SHELL_GETC: Macro that calls a GetC routine -; SHELL_PUTC: Macro that calls a PutC routine +; SHELL_GETC: Macro that calls a GetC routine for tty interface +; 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 ; *** CONSTS *** ; 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 ; size of the args variable. @@ -144,6 +147,7 @@ shellParse: pop de jr z, .found inc de + inc de djnz .loop ; exhausted loop? not found @@ -313,7 +317,12 @@ shellParseArgs: ; ; When these commands are called, HL points to the first byte of the ; 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). ; Example: seek 01fe @@ -388,9 +397,9 @@ shellPeek: ret ; 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 -; SHELL_GETC, but a method of selecting IO sources is coming, making this -; command much more useful. +; current memory pointer (which doesn't change). This gets chars from +; SHELL_IO_GETC, which can be different from SHELL_GETC. Coupled with the +; "blockdev" part, this allows you to dynamically select your IO source. ; Control is returned to the shell only after all bytes are read. ; ; Example: load 42 @@ -404,7 +413,7 @@ shellLoad: ld a, (hl) ld b, a ld hl, (SHELL_MEM_PTR) -.loop: SHELL_GETC +.loop: SHELL_IO_GETC ld (hl), a inc hl djnz .loop @@ -455,6 +464,8 @@ shellCall: pop af 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: .dw shellSeekCmd, shellPeekCmd, shellLoadCmd, shellCallCmd