mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 12:18:07 +11:00
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:
parent
6b1679c811
commit
328f44814e
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
108
kernel/fs.asm
108
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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
@ -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);
|
||||
|
56
tools/tests/unit/test_core.asm
Normal file
56
tools/tests/unit/test_core.asm
Normal 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
|
Loading…
Reference in New Issue
Block a user