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!
This commit is contained in:
Virgil Dupras 2019-05-28 15:56:39 -04:00
parent 6b1679c811
commit 328f44814e
9 changed files with 201 additions and 83 deletions

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

Binary file not shown.

View File

@ -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);

View File

@ -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