From a391f85c00a374b2077dc74d8660018276329436 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 23 Apr 2019 19:42:10 -0400 Subject: [PATCH] fs: implement GetC, PutC, Seek and Tell on file handle Very coarse, but I got them to work. --- parts/blockdev.asm | 11 ++++++ parts/core.asm | 1 + parts/fs.asm | 111 +++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/parts/blockdev.asm b/parts/blockdev.asm index 9b0d262..5ab541a 100644 --- a/parts/blockdev.asm +++ b/parts/blockdev.asm @@ -111,6 +111,7 @@ blkRead: ld ix, (BLOCKDEV_GETC) _blkRead: push hl + push bc .loop: call _blkCall jr nz, .end ; Z already unset @@ -119,6 +120,7 @@ _blkRead: djnz .loop cp a ; ensure Z .end: + pop bc pop hl ret @@ -134,6 +136,7 @@ blkWrite: ld ix, (BLOCKDEV_PUTC) _blkWrite: push hl + push bc .loop: ld a, (hl) call _blkCall @@ -142,6 +145,7 @@ _blkWrite: djnz .loop cp a ; ensure Z .end: + pop bc pop hl ret @@ -152,6 +156,13 @@ _blkWrite: ; 3 : Move to the end ; 4 : Move to the beginning ; Set position of selected device to the value specified in HL +; +; When seeking to an out-of-bounds position, the resulting position will be +; one position ahead of the last valid position. Therefore, GetC after a seek +; to end would always fail. +; +; If the device is "growable", it's possible that seeking to end when calling +; PutC doesn't necessarily result in a failure. blkSeek: ld ix, (BLOCKDEV_SEEK) ld iy, (BLOCKDEV_TELL) diff --git a/parts/core.asm b/parts/core.asm index 3825db2..b96afac 100644 --- a/parts/core.asm +++ b/parts/core.asm @@ -62,6 +62,7 @@ writeHLinDE: inc de ld a, h ld (de), a + dec de pop af ret diff --git a/parts/fs.asm b/parts/fs.asm index 7b45332..a567966 100644 --- a/parts/fs.asm +++ b/parts/fs.asm @@ -79,18 +79,18 @@ ; *** CONSTS *** FS_MAX_NAME_SIZE .equ 0x1a FS_BLOCKSIZE .equ 0x100 +FS_METASIZE .equ 0x20 FS_META_ALLOC_OFFSET .equ 3 FS_META_FSIZE_OFFSET .equ 4 FS_META_FNAME_OFFSET .equ 6 ; Size in bytes of a FS handle: -; * 2 bytes for starting offset +; * 2 bytes for current position. (absolute) +; * 2 bytes for starting offset, after metadata +; * 2 bytes for maximum offset ; * 2 bytes for file size (we could fetch it from metadata all the time, but it ; could be time consuming depending on the underlying device). -; * 2 bytes for current position. -; Starting offset is the *metadata* offset. We need, when we write to a handle, -; to change the size of the file. -FS_HANDLE_SIZE .equ 6 +FS_HANDLE_SIZE .equ 8 FS_ERR_NO_FS .equ 0x5 FS_ERR_NOT_FOUND .equ 0x6 @@ -109,7 +109,7 @@ FS_PTR .equ FS_START+2 ; This variable below contain the metadata of the last block FS_PTR was moved ; to. We read this data in memory to avoid constant seek+read operations. FS_META .equ FS_PTR+2 -FS_HANDLES .equ FS_META+0x20 +FS_HANDLES .equ FS_META+FS_METASIZE FS_RAMEND .equ FS_HANDLES+(FS_HANDLE_COUNT*FS_HANDLE_SIZE) ; *** DATA *** @@ -186,7 +186,7 @@ fsReadMeta: call fsPlace push bc push hl - ld b, 0x20 + ld b, FS_METASIZE ld hl, FS_META call fsblkRead ; Sets Z pop hl @@ -199,7 +199,7 @@ fsWriteMeta: call fsPlace push bc push hl - ld b, 0x20 + ld b, FS_METASIZE ld hl, FS_META call fsblkWrite ; Sets Z pop hl @@ -217,7 +217,7 @@ fsInitMeta: ld bc, 3 ldir xor a - ld b, 0x20-3 + ld b, FS_METASIZE-3 call fill pop hl pop de @@ -319,10 +319,18 @@ fsIsDeleted: ; we can still access the FS even if blkdev selection changes. These routines ; below mimic blkdev's methods, but for our private mount. +fsblkGetC: + ld ix, (FS_GETC) + jp _blkCall + fsblkRead: ld ix, (FS_GETC) jp _blkRead +fsblkPutC: + ld ix, (FS_PUTC) + jp _blkCall + fsblkWrite: ld ix, (FS_PUTC) jp _blkWrite @@ -340,27 +348,95 @@ fsblkTell: ; Open file at current position into handle at (HL) fsOpen: + push hl + push de + push af + ex hl, de + ld hl, (FS_PTR) + ld a, FS_METASIZE + call addHL + call writeHLinDE + inc de + inc de + call writeHLinDE + inc de + inc de + ; Maximum offset is starting offset + (numblocks * 0x100) - 1 + ld a, (FS_META+FS_META_ALLOC_OFFSET) + ; Because our blocks are exactly 0x100 in size, we simple have to + ; increase the H in HL to have our result. + add a, h + ld h, a + call writeHLinDE + inc de + inc de + ld hl, (FS_META+FS_META_FSIZE_OFFSET) + call writeHLinDE + pop af + pop de + pop hl ret -; Ensures that file size in metadata corresponds to file size in handle as (HL). -fsCommit: +fsPlaceH: + push af + push hl + ld ixh, d + ld ixl, e + push ix + ld l, (ix) + ld h, (ix+1) + ld a, BLOCKDEV_SEEK_ABSOLUTE + call fsblkSeek + pop ix + pop hl + pop af ret -; Read a byte in handle at (HL), put it into A and advance the handle's +fsAdvanceH: + inc (ix) + ld a, (ix) + ret nc ; no carry + inc (ix+1) + ret + +; Read a byte in handle at (DE), put it into A and advance the handle's ; position. ; Z is set on success, unset if handle is at the end of the file. -fsRead: +fsGetC: + call fsPlaceH + push ix + call fsblkGetC + ; increase current pos + pop ix ; recall + call fsAdvanceH ret -; Write byte A in handle at (HL) and advance the handle's position. -; Z is set on success, unset if handle is at the end of the allocated space. -fsWrite: +; Write byte A in handle (DE) and advance the handle's position. +; Z is set on success, unset if handle is at the end of the file. +fsPutC: + call fsPlaceH + push ix + call fsblkPutC + ; increase current pos + pop ix ; recall + call fsAdvanceH ret -; Sets position of handle (HL) to DE. This position does *not* include metadata. +; Sets position of handle (DE) to HL. This position does *not* include metadata. ; It is an offset that starts at actual data. ; Sets Z if offset is within bounds, unsets Z if it isn't. fsSeek: + ld ixh, d + ld ixl, e + ld (ix), l + ld (ix+1), h + ret + +fsTell: + ld ixh, d + ld ixl, e + ld l, (ix) + ld h, (ix+1) ret ; *** SHELL COMMANDS *** @@ -369,6 +445,7 @@ fsSeek: ; Upon mounting, copy currently selected device in FS_GETC/PUTC/SEEK/TELL. fsOnCmd: .db "fson", 0, 0, 0 +fsOn: push hl push de push bc