From 328f44814eccca487550112022bbf0b30200f92e Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Tue, 28 May 2019 15:56:39 -0400 Subject: [PATCH] Make blockdev pointers 32 bits This allows us to break through the 64K limit for includes CFS in zasm, a limit we were dangerously close to breaking. In fact, this commit makes us go over that limit. Right in time! --- kernel/blockdev.asm | 45 +++++++++++------ kernel/core.asm | 13 +++++ kernel/fs.asm | 108 +++++++++++++++++++++++------------------ tools/emul/shell/shell.c | 17 ++++--- tools/emul/shell/shell_.asm | 5 ++ tools/emul/zasm/glue.asm | 4 ++ tools/emul/zasm/kernel.bin | Bin 1064 -> 1138 bytes tools/emul/zasm/zasm.c | 36 ++++++++------ tools/tests/unit/test_core.asm | 56 +++++++++++++++++++++ 9 files changed, 201 insertions(+), 83 deletions(-) create mode 100644 tools/tests/unit/test_core.asm diff --git a/kernel/blockdev.asm b/kernel/blockdev.asm index 1eccf5b..baa8f7a 100644 --- a/kernel/blockdev.asm +++ b/kernel/blockdev.asm @@ -33,10 +33,12 @@ ; Unsuccessful writes generally mean that we reached EOF. ; ; Seek: -; Place device "pointer" at position dictated by HL. +; Place device "pointer" at position dictated by HL (low 16 bits) and DE (high +; 16 bits). ; ; Tell: -; Return the position of the "pointer" in HL +; Return the position of the "pointer" in HL (low 16 bits) and DE (high 16 +; bits). ; ; All routines are expected to preserve unused registers. @@ -197,12 +199,14 @@ _blkWrite: ret ; Seeks the block device in one of 5 modes, which is the A argument: -; 0 : Move exactly to X, X being the HL argument. -; 1 : Move forward by X bytes, X being the HL argument -; 2 : Move backwards by X bytes, X being the HL argument +; 0 : Move exactly to X, X being the HL/DE argument. +; 1 : Move forward by X bytes, X being the HL argument (no DE) +; 2 : Move backwards by X bytes, X being the HL argument (no DE) ; 3 : Move to the end ; 4 : Move to the beginning -; Set position of selected device to the value specified in HL + +; Set position of selected device to the value specified in HL (low) and DE +; (high). DE is only used for mode 0. ; ; 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 @@ -214,6 +218,8 @@ blkSeek: ld ix, (BLOCKDEV_SEEK) ld iy, (BLOCKDEV_TELL) _blkSeek: + ; we preserve DE so that it's possible to call blkSeek in mode != 0 + ; while not discarding our current DE value. push de cp BLOCKDEV_SEEK_FORWARD jr z, .forward @@ -224,30 +230,41 @@ _blkSeek: cp BLOCKDEV_SEEK_END jr z, .end ; all other modes are considered absolute - jr .seek ; for absolute mode, HL is already correct + jr .seek ; for absolute mode, HL and DE are already + ; correct .forward: - ex de, hl ; DE has our offset + push bc + push hl ; We want to be able to plug our own TELL function, which is why we ; don't call blkTell directly here. ; Calling TELL - call callIY ; HL has our curpos - add hl, de - jr nc, .seek ; no carry? alright! - ; we have carry? out of bounds, set to maximum + ld de, 0 ; in case out Tell routine doesn't return DE + call callIY ; HL/DE now have our curpos + pop bc ; pop HL into BC + add hl, bc + pop bc ; pop orig BC back + jr nc, .seek ; no carry? let's seek. + ; carry, adjust DE + inc de + jr .seek .backward: ; TODO - subtraction are more complicated... jr .seek .beginning: ld hl, 0 + ld de, 0 jr .seek .end: ld hl, 0xffff + ld de, 0xffff .seek: + call _blkCall pop de - jp _blkCall + ret -; Returns the current position of the selected device in HL. +; Returns the current position of the selected device in HL (low) and DE (high). blkTell: + ld de, 0 ; in case device ignores DE. ld ix, (BLOCKDEV_TELL) jp _blkCall diff --git a/kernel/core.asm b/kernel/core.asm index b0d4001..c0a78e6 100644 --- a/kernel/core.asm +++ b/kernel/core.asm @@ -57,6 +57,19 @@ addHL: pop af ret +; subtract the value of A from HL +subHL: + push af + ; To avoid having to swap L and A, we sub "backwards", that is, we add + ; a NEGated value. This means that the carry flag is inverted + neg + add a, l + jr c, .end ; if carry, no carry. :) + dec h +.end: + ld l, a + pop af + ret ; Write the contents of HL in (DE) writeHLinDE: diff --git a/kernel/fs.asm b/kernel/fs.asm index a7e91d0..7f5da51 100644 --- a/kernel/fs.asm +++ b/kernel/fs.asm @@ -85,12 +85,9 @@ .equ FS_META_FSIZE_OFFSET 4 .equ FS_META_FNAME_OFFSET 6 ; Size in bytes of a FS handle: -; * 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). -.equ FS_HANDLE_SIZE 8 +; * 4 bytes for starting offset of the FS block +; * 2 bytes for current position relative to block's position +.equ FS_HANDLE_SIZE 6 .equ FS_ERR_NO_FS 0x5 .equ FS_ERR_NOT_FOUND 0x6 @@ -101,14 +98,17 @@ .equ FS_SEEK FS_PUTC+2 .equ FS_TELL FS_SEEK+2 ; Offset at which our FS start on mounted device +; This pointer is 32 bits. 32 bits pointers are a bit awkward: first two bytes +; are high bytes *low byte first*, and then the low two bytes, same order. +; When loaded in HL/DE, the four bytes are loaded in this order: E, D, L, H .equ FS_START FS_TELL+2 ; Offset at which we are currently pointing to with regards to our routines ; below, which all assume this offset as a context. This offset is not relative -; to FS_START. It can be used directly with fsblkSeek. -.equ FS_PTR FS_START+2 +; to FS_START. It can be used directly with fsblkSeek. 32 bits. +.equ FS_PTR FS_START+4 ; 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. -.equ FS_META FS_PTR+2 +.equ FS_META FS_PTR+4 .equ FS_HANDLES FS_META+FS_METASIZE .equ FS_RAMEND FS_HANDLES+FS_HANDLE_COUNT*FS_HANDLE_SIZE @@ -133,10 +133,11 @@ fsBegin: push hl ld hl, (FS_START) ld (FS_PTR), hl + ld hl, (FS_START+2) + ld (FS_PTR+2), hl pop hl call fsReadMeta - call fsIsValid ; sets Z - ret + jp fsIsValid ; sets Z, returns ; Change current position to the next block with metadata. If it can't (if this ; is the last valid block), doesn't move. @@ -156,8 +157,9 @@ fsNext: call fsblkSeek djnz .loop ; Good, were here. We're going to read meta from our current position. - call fsblkTell ; --> HL - ld (FS_PTR), hl + call fsblkTell ; --> HL, --> DE + ld (FS_PTR), de + ld (FS_PTR+2), hl call fsReadMeta jr nz, .createChainEnd call fsIsValid @@ -226,13 +228,16 @@ fsInitMeta: pop af ret -; Make sure that our underlying blockdev is correcly placed. +; Make sure that our underlying blockdev is correctly placed. fsPlace: push af push hl + push de xor a - ld hl, (FS_PTR) + ld de, (FS_PTR) + ld hl, (FS_PTR+2) call fsblkSeek + pop de pop hl pop af ret @@ -284,7 +289,8 @@ fsAlloc: ; Good, FS_META ready. Now, let's update FS_PTR because it hasn't been ; changed yet. call fsblkTell - ld (FS_PTR), hl + ld (FS_PTR), de + ld (FS_PTR+2), hl ; Ok, now we can write our metadata call fsWriteMeta .end: @@ -361,6 +367,7 @@ fsblkSeek: jp _blkSeek fsblkTell: + ld de, 0 ld ix, (FS_TELL) jp _blkCall @@ -368,57 +375,56 @@ fsblkTell: ; Open file at current position into handle at (HL) fsOpen: + push bc push hl push de push af ex de, hl - 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) + ; Starting pos + ld hl, FS_PTR + ld bc, 4 + ldir + ; Current pos + ld hl, FS_METASIZE call writeHLinDE pop af pop de pop hl + pop bc ret ; Place FS blockdev at proper position for file handle in (DE). fsPlaceH: push af + push bc push hl push de pop ix push ix - ld l, (ix) - ld h, (ix+1) + ld e, (ix) + ld d, (ix+1) + ld l, (ix+2) + ld h, (ix+3) + ld c, (ix+4) + ld b, (ix+5) + add hl, bc + jr nc, .nocarry + inc de +.nocarry: ld a, BLOCKDEV_SEEK_ABSOLUTE call fsblkSeek pop ix pop hl + pop bc pop af ret ; Advance file handle in (IX) by one byte fsAdvanceH: push af - inc (ix) + inc (ix+4) jr nz, .end - inc (ix+1) + inc (ix+5) .end: pop af ret @@ -426,6 +432,7 @@ fsAdvanceH: ; 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. +; TODO: detect end of file fsGetC: push ix call fsPlaceH @@ -441,6 +448,7 @@ fsGetC: ; 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. +; TODO: detect end of block alloc fsPutC: call fsPlaceH push ix @@ -455,15 +463,18 @@ fsPutC: ; Sets Z if offset is within bounds, unsets Z if it isn't. fsSeek: push de \ pop ix - ld (ix), l - ld (ix+1), h + ld a, FS_METASIZE + call addHL + ld (ix+4), l + ld (ix+5), h ret fsTell: push de \ pop ix - ld l, (ix) - ld h, (ix+1) - ret + ld l, (ix+4) + ld h, (ix+5) + ld a, FS_METASIZE + jp subHL ; returns ; Mount the fs subsystem upon the currently selected blockdev at current offset. ; Verify is block is valid and error out if its not, mounting nothing. @@ -479,8 +490,10 @@ fsOn: ld bc, 8 ; we have 8 bytes to copy ldir ; copy! call fsblkTell - ld (FS_START), hl - ld (FS_PTR), hl + ld (FS_START), de + ld (FS_START+2), hl + ld (FS_PTR), de + ld (FS_PTR+2), hl call fsReadMeta jr nz, .error call fsIsValid @@ -491,8 +504,7 @@ fsOn: .error: ; couldn't mount. Let's reset our variables. xor a - ld b, 10 ; blkdev routines + FS_START which is just - ; after. + ld b, FS_META-FS_GETC ; reset routine pointers and FS ptrs ld hl, FS_GETC call fill diff --git a/tools/emul/shell/shell.c b/tools/emul/shell/shell.c index 2e1935e..6079dc2 100644 --- a/tools/emul/shell/shell.c +++ b/tools/emul/shell/shell.c @@ -31,12 +31,13 @@ #define FS_DATA_PORT 0x01 #define FS_SEEKL_PORT 0x02 #define FS_SEEKH_PORT 0x03 +#define FS_SEEKE_PORT 0x04 static Z80Context cpu; static uint8_t mem[0xffff] = {0}; -static uint8_t fsdev[0xffff] = {0}; -static uint16_t fsdev_size = 0; -static uint16_t fsdev_ptr = 0; +static uint8_t fsdev[0x20000] = {0}; +static uint32_t fsdev_size = 0; +static uint32_t fsdev_ptr = 0; static int running; static uint8_t io_read(int unused, uint16_t addr) @@ -57,7 +58,9 @@ static uint8_t io_read(int unused, uint16_t addr) } else if (addr == FS_SEEKL_PORT) { return fsdev_ptr & 0xff; } else if (addr == FS_SEEKH_PORT) { - return fsdev_ptr >> 8; + return (fsdev_ptr >> 8) & 0xff; + } else if (addr == FS_SEEKE_PORT) { + return (fsdev_ptr >> 16) & 0xff; } else { fprintf(stderr, "Out of bounds I/O read: %d\n", addr); return 0; @@ -78,9 +81,11 @@ static void io_write(int unused, uint16_t addr, uint8_t val) fsdev[fsdev_ptr++] = val; } } else if (addr == FS_SEEKL_PORT) { - fsdev_ptr = (fsdev_ptr & 0xff00) | val; + fsdev_ptr = (fsdev_ptr & 0xffff00) | val; } else if (addr == FS_SEEKH_PORT) { - fsdev_ptr = (fsdev_ptr & 0x00ff) | (val << 8); + fsdev_ptr = (fsdev_ptr & 0xff00ff) | (val << 8); + } else if (addr == FS_SEEKE_PORT) { + fsdev_ptr = (fsdev_ptr & 0x00ffff) | (val << 16); } else { fprintf(stderr, "Out of bounds I/O write: %d / %d\n", addr, val); } diff --git a/tools/emul/shell/shell_.asm b/tools/emul/shell/shell_.asm index 6afded7..1dad3d7 100644 --- a/tools/emul/shell/shell_.asm +++ b/tools/emul/shell/shell_.asm @@ -5,6 +5,7 @@ .equ FS_DATA_PORT 0x01 .equ FS_SEEKL_PORT 0x02 .equ FS_SEEKH_PORT 0x03 +.equ FS_SEEKE_PORT 0x04 jp init @@ -80,6 +81,8 @@ fsdevSeek: out (FS_SEEKL_PORT), a ld a, h out (FS_SEEKH_PORT), a + ld a, e + out (FS_SEEKE_PORT), a pop af ret @@ -89,6 +92,8 @@ fsdevTell: ld l, a in a, (FS_SEEKH_PORT) ld h, a + in a, (FS_SEEKE_PORT) + ld e, a pop af ret diff --git a/tools/emul/zasm/glue.asm b/tools/emul/zasm/glue.asm index 1b2c2c5..09dd7a9 100644 --- a/tools/emul/zasm/glue.asm +++ b/tools/emul/zasm/glue.asm @@ -98,6 +98,8 @@ fsdevPutC: fsdevSeek: push af + ld a, e + out (FS_SEEK_PORT), a ld a, h out (FS_SEEK_PORT), a ld a, l @@ -108,6 +110,8 @@ fsdevSeek: fsdevTell: push af in a, (FS_SEEK_PORT) + ld e, a + in a, (FS_SEEK_PORT) ld h, a in a, (FS_SEEK_PORT) ld l, a diff --git a/tools/emul/zasm/kernel.bin b/tools/emul/zasm/kernel.bin index e2e5782c33c39e4ae20b78838c5a19bbe0026b13..e94361c1ccb49875b913826533a58bb0b06de8c9 100644 GIT binary patch literal 1138 zcmZ`(U1%It6h3$E>~@l9vOiI$ySAOlstgI}sKs3ZPOlofEr_86ERA51Li(UISkzYX z10s3y#b*WI1mCtV5)09FxJ>0fTyR(>NSFIC*eR3{ajDZd$m6!<~Hf7AFG%D~ZOG5y(##;e`O6V}axlOcQM>l7 zHIji-XjDtTc0-Jpz4>Fd^24?zGPm_mHtW)DSI7{u7g`6hHln6zieOz{hgSU&eA1m-pk(_#%xG`!3mZMuWCz$Wu_d=O^+c$a7Gw#*N1R+521K5X8<>3&+gaWa`<9v}cb%2-k zS8#k0Uw{Suw7#e>=`S5$fR1gjqAM?hNTy3{YLZP?*wn);mTzgiLW5+s&XDmL`K8wO zhz&%}QPgdo?k-H``*53O$O^S+*Bp@_YjQg>Lbx!?tJG>lRGXkH%DtY;JXv}Qdhr>J!YGrQ_&=FfN& zUi`r`brzQoGg8B7|HyAe3w;sgXDeO}{c;N&1A{oXG0#vWkw-Dd@`Q$tFc!0iv0T)| z$a&kFHgFou_s=mC^vobj*79>ZuY5^T2`Ap~!=|Hk1rjEDAXa;1tw%(kobQum(MLy56X{BiuJ-6!k76x-dbUr` J_bL7k{sjCH&UppHW^iFGL0Vdx+ZeQ2cvVTd@pc4A1j$8TnX;=w-DdtbfRU%mIe zDm4)58mUE6r%Bx;b%E3gQYT5BCACIso79k0fvKOkIx5tALR}H+D?#a}4OV%3q|<8I zuD)f%3y0@%Cb$@ot z7q#L&bAcQy7=O|3=-Y)X-w-z%`o^M8YvxN@J2pyh|FM8?0!H8no7ErO0~z@zC+)z{yomS@Y{ z3+5u}q+XOq=45PMmmtAgioRcCmwqr=I6b3qj`bB%l(1pY3n>**v6 z1S%`-Fa&zBUaq1+sBKR~nwrZn`F#X)1?Wk+S3e}xH*jHASQ4f~6dAa<64SddT~OL* zt5dJ;NZ1kB(M zVfcWe_u15&GNFsEN3vu~WK=&IfxvVA8|;e6tpET3 diff --git a/tools/emul/zasm/zasm.c b/tools/emul/zasm/zasm.c index e470bf8..c91f6d7 100644 --- a/tools/emul/zasm/zasm.c +++ b/tools/emul/zasm/zasm.c @@ -47,10 +47,10 @@ static int inpt_size; static int inpt_ptr; static uint8_t middle_of_seek_tell = 0; -static uint8_t fsdev[0xffff] = {0}; -static uint16_t fsdev_size = 0; -static uint16_t fsdev_ptr = 0; -static uint8_t fsdev_middle_of_seek_tell = 0; +static uint8_t fsdev[0x20000] = {0}; +static uint32_t fsdev_size = 0; +static uint32_t fsdev_ptr = 0; +static uint8_t fsdev_seek_tell_cnt = 0; static uint8_t io_read(int unused, uint16_t addr) { @@ -79,15 +79,18 @@ static uint8_t io_read(int unused, uint16_t addr) return 0; } } else if (addr == FS_SEEK_PORT) { - if (fsdev_middle_of_seek_tell) { - fsdev_middle_of_seek_tell = 0; - return fsdev_ptr & 0xff; - } else { + if (fsdev_seek_tell_cnt == 0) { #ifdef DEBUG fprintf(stderr, "FS tell %d\n", fsdev_ptr); #endif - fsdev_middle_of_seek_tell = 1; - return fsdev_ptr >> 8; + fsdev_seek_tell_cnt = 1; + return fsdev_ptr >> 16; + } else if (fsdev_seek_tell_cnt == 1) { + fsdev_seek_tell_cnt = 2; + return (fsdev_ptr >> 8) & 0xff; + } else { + fsdev_seek_tell_cnt = 0; + return fsdev_ptr & 0xff; } } else { fprintf(stderr, "Out of bounds I/O read: %d\n", addr); @@ -119,15 +122,18 @@ static void io_write(int unused, uint16_t addr, uint8_t val) fsdev[fsdev_ptr++] = val; } } else if (addr == FS_SEEK_PORT) { - if (fsdev_middle_of_seek_tell) { + if (fsdev_seek_tell_cnt == 0) { + fsdev_ptr = val << 16; + fsdev_seek_tell_cnt = 1; + } else if (fsdev_seek_tell_cnt == 1) { + fsdev_ptr |= val << 8; + fsdev_seek_tell_cnt = 2; + } else { fsdev_ptr |= val; - fsdev_middle_of_seek_tell = 0; + fsdev_seek_tell_cnt = 0; #ifdef DEBUG fprintf(stderr, "FS seek %d\n", fsdev_ptr); #endif - } else { - fsdev_ptr = (val << 8) & 0xff00; - fsdev_middle_of_seek_tell = 1; } } else if (addr == STDERR_PORT) { fputc(val, stderr); diff --git a/tools/tests/unit/test_core.asm b/tools/tests/unit/test_core.asm new file mode 100644 index 0000000..aa0c7ab --- /dev/null +++ b/tools/tests/unit/test_core.asm @@ -0,0 +1,56 @@ +jp test + +#include "core.asm" + +testNum: .db 1 + +test: + ld hl, 0xffff + ld sp, hl + + ld hl, 0x123 + ld a, 0x25 + call subHL + ld a, h + cp 0 + jp nz, fail + ld a, l + cp 0xfe + jp nz, fail + call nexttest + + ld hl, 0x125 + ld a, 0x23 + call subHL + ld a, h + cp 1 + jp nz, fail + ld a, l + cp 0x02 + jp nz, fail + call nexttest + + ld hl, 0x125 + ld a, 0x25 + call subHL + ld a, h + cp 1 + jp nz, fail + ld a, l + cp 0 + jp nz, fail + call nexttest + + ; success + xor a + halt + +nexttest: + ld a, (testNum) + inc a + ld (testNum), a + ret + +fail: + ld a, (testNum) + halt