; 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 *** BLOCKDEV_ERR_OUT_OF_BOUNDS .equ 0x03 ; *** VARIABLES *** ; A memory pointer to a device table. A device table is a list of addresses ; pointing to GetC, PutC and Seek routines. BLOCKDEV_TBL .equ BLOCKDEV_RAMSTART ; Pointer to the selected block device. A block device is a 6 bytes block of ; memory with pointers to GetC, PutC and Seek routines, in that order. 0 means ; unsupported. BLOCKDEV_SEL .equ BLOCKDEV_TBL+(BLOCKDEV_COUNT*2) BLOCKDEV_RAMEND .equ BLOCKDEV_SEL+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 .loop: inc de inc de djnz .loop pop bc ret ; Set the pointer of device id A to the value in HL blkSet: call blkFind call writeHLinDE ret ; Select block index specified in A blkSel: push de push hl call blkFind ld hl, BLOCKDEV_SEL ex hl, de ldi pop hl pop de ret blkBselCmd: .db "bsel", 0b001, 0, 0 blkBsel: ld a, (hl) ; argument supplied cp BLOCKDEV_COUNT jr nc, .error ; if selection >= device count, error call blkSel xor a ret .error: ld a, BLOCKDEV_ERR_OUT_OF_BOUNDS ret ; In those routines below, IY is destroyed (we don't push it to the stack). We ; seldom use it anyways... ; call routine in BLOCKDEV_SEL with offset IYL. _blkCall: push ix push de ld de, (BLOCKDEV_SEL) ; DE now points to the *address table*, not the routine addresses ; themselves. One layer of indirection left. ; slide by offset push af ld a, iyl call addDE ; slide by offset pop af call intoDE ; Alright, now de points to what we want to call ld ixh, d ld ixl, e pop de call callIX pop ix 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: ld iyl, 0 jr _blkCall blkPutC: ld iyl, 2 jr _blkCall blkSeek: ld iyl, 4 jr _blkCall