ed: make scratchpad memory only

The dual scraptchpad thing doesn't work. Things become very
complicated when it's time to write that back to the file. We
overwrite our contents and end up with garbage.
This commit is contained in:
Virgil Dupras 2019-07-21 08:47:42 -04:00
parent 942d2a952d
commit 1a5a1b9861
3 changed files with 40 additions and 105 deletions

View File

@ -1,29 +1,19 @@
; buf - manage line buffer ; buf - manage line buffer
; ;
; Lines in edited file aren't loaded in memory, their offsets is referenced to
; in this buffer.
;
; About scratchpad and offsets. There are two scratchpads: file and memory.
; The file one is the contents of the active blkdev. The second one is
; in-memory, for edits. We differentiate between the two with a
; "scatchpad mask". When the high bits of the offset match the mask, then we
; know that this offset is from the scratchpad.
;
; *** Consts *** ; *** Consts ***
; ;
; Maximum number of lines allowed in the buffer. ; Maximum number of lines allowed in the buffer.
.equ BUF_MAXLINES 0x800 .equ BUF_MAXLINES 0x800
; Size of our scratchpad ; Size of our scratchpad
.equ BUF_PADMAXLEN 0x1000 .equ BUF_PADMAXLEN 0x1000
; Scratchpad mask (only applies on high byte)
.equ BUF_SCRATCHPAD_MASK 0b11110000
; *** Variables *** ; *** Variables ***
; Number of lines currently in the buffer ; Number of lines currently in the buffer
.equ BUF_LINECNT BUF_RAMSTART .equ BUF_LINECNT BUF_RAMSTART
; List of words pointing to scratchpad offsets ; List of pointers to strings in scratchpad
.equ BUF_LINES BUF_LINECNT+2 .equ BUF_LINES BUF_LINECNT+2
; Points to the end of the scratchpad ; Points to the end of the scratchpad, that is, one byte after the last written
; char in it.
.equ BUF_PADEND BUF_LINES+BUF_MAXLINES*2 .equ BUF_PADEND BUF_LINES+BUF_MAXLINES*2
; The in-memory scratchpad ; The in-memory scratchpad
.equ BUF_PAD BUF_PADEND+2 .equ BUF_PAD BUF_PADEND+2
@ -35,20 +25,34 @@
; On initialization, we read the whole contents of target blkdev and add lines ; On initialization, we read the whole contents of target blkdev and add lines
; as we go. ; as we go.
bufInit: bufInit:
ld hl, BUF_PAD ld hl, BUF_PAD ; running pointer to end of pad
ld (BUF_PADEND), hl ld de, BUF_PAD ; points to beginning of current line
ld ix, BUF_LINES ld ix, BUF_LINES ; points to current line index
ld bc, 0 ; line count ld bc, 0 ; line count
.loop: .loop:
call ioTell ; --> HL
call ioGetC call ioGetC
jr nz, .loopend jr nz, .loopend
ld (ix), l or a ; null? hum, weird. same as LF
jr z, .lineend
cp 0x0a
jr z, .lineend
ld (hl), a
inc hl
jr .loop
.lineend:
; We've just finished reading a line, writing each char in the pad.
; Null terminate it.
xor a
ld (hl), a
inc hl
; Now, let's register its pointer in BUF_LINES
ld (ix), e
inc ix inc ix
ld (ix), h ld (ix), d
inc ix inc ix
inc bc inc bc
call ioGetLine ld (BUF_PADEND), hl
ld de, (BUF_PADEND)
jr .loop jr .loop
.loopend: .loopend:
ld (BUF_LINECNT), bc ld (BUF_LINECNT), bc
@ -65,45 +69,20 @@ bufLineAddr:
pop de pop de
ret ret
; Read line number specified in HL and loads the I/O buffer with it. ; Read line number specified in HL and make HL point to its contents.
; Like ioGetLine, sets HL to line buffer pointer.
; Sets Z on success, unset if out of bounds. ; Sets Z on success, unset if out of bounds.
bufGetLine: bufGetLine:
push de push de ; --> lvl 1
ld de, (BUF_LINECNT) ld de, (BUF_LINECNT)
call cpHLDE call cpHLDE
jr nc, .outOfBounds ; HL > (BUF_LINECNT)
call bufLineAddr
; HL now points to seek offset in memory
ld e, (hl)
inc hl
ld d, (hl)
; DE has seek offset
ex de, hl
pop de
; is it a scratchpad offset?
ld a, h
and BUF_SCRATCHPAD_MASK
cp BUF_SCRATCHPAD_MASK
jr z, .fromScratchpad
; not from scratchpad
cp a ; ensure Z
jp ioGetLine ; preserves AF
.fromScratchpad:
; remove scratchpad mask
ld a, BUF_SCRATCHPAD_MASK
xor 0xff
and h
ld h, a
; HL is now a mask-less offset to BUF_PAD
push de ; --> lvl 1
ld de, BUF_PAD
add hl, de
pop de ; <-- lvl 1 pop de ; <-- lvl 1
jp nc, unsetZ ; HL > (BUF_LINECNT)
call bufLineAddr
; HL now points to an item in BUF_LINES.
call intoHL
; Now, HL points to our contents
cp a ; ensure Z
ret ret
.outOfBounds:
pop de
jp unsetZ
; Given line indexes in HL and DE where HL < DE < CNT, move all lines between ; Given line indexes in HL and DE where HL < DE < CNT, move all lines between
; DE and CNT by an offset of DE-HL. Also, adjust BUF_LINECNT by DE-HL. ; DE and CNT by an offset of DE-HL. Also, adjust BUF_LINECNT by DE-HL.
@ -150,7 +129,7 @@ bufDelLines:
; Insert string where DE points to memory scratchpad, then insert that line ; Insert string where DE points to memory scratchpad, then insert that line
; at index HL, offsetting all lines by 2 bytes. ; at index HL, offsetting all lines by 2 bytes.
bufInsertLine: bufInsertLine:
push de ; --> lvl 1, scratchpad offset push de ; --> lvl 1, scratchpad ptr
push hl ; --> lvl 2, insert index push hl ; --> lvl 2, insert index
; The logic below is mostly copy-pasted from bufDelLines, but with a ; The logic below is mostly copy-pasted from bufDelLines, but with a
; LDDR logic (to avoid overwriting). I learned, with some pain involved, ; LDDR logic (to avoid overwriting). I learned, with some pain involved,
@ -187,22 +166,15 @@ bufInsertLine:
ld (hl), d ld (hl), d
ret ret
; copy string that HL points to to scratchpad and return its seek offset, in HL. ; copy string that HL points to to scratchpad and return its pointer in
; scratchpad, in HL.
bufScratchpadAdd: bufScratchpadAdd:
push de push de
ld de, (BUF_PADEND) ld de, (BUF_PADEND)
push de ; --> lvl 1 push de ; --> lvl 1
call strcpyM call strcpyM
inc de ; pad end is last char + 1
ld (BUF_PADEND), de ld (BUF_PADEND), de
pop hl ; <-- lvl 1 pop hl ; <-- lvl 1
; we have a memory offset in HL, but it's not what we want! we want a
; seek offset stamped with the "scratchpad mask"
ld de, BUF_PAD
scf \ ccf
sbc hl, de
ld a, h
or BUF_SCRATCHPAD_MASK
ld h, a
; now we're good...
pop de pop de
ret ret

View File

@ -32,7 +32,7 @@ ioInit:
ld ix, IO_FILE_HDL ld ix, IO_FILE_HDL
jp fsPutC jp fsPutC
.blkdev: .blkdev:
.dw .fsGetC, .fsPutC .dw .fsGetC, unsetZ
ioGetC: ioGetC:
push ix push ix
@ -61,34 +61,3 @@ ioTell:
call _blkTell call _blkTell
pop ix pop ix
ret ret
; Given an offset HL, read the line in IO_LINE, without LF and null terminates
; it. Make HL point to IO_LINE.
ioGetLine:
push af
push de
push bc
ld de, 0 ; limit ourselves to 16-bit for now
xor a ; absolute seek
call ioSeek
ld hl, IO_LINE
ld b, IO_MAXLEN
.loop:
call ioGetC
jr nz, .loopend
or a ; null? hum, weird. same as LF
jr z, .loopend
cp 0x0a
jr z, .loopend
ld (hl), a
inc hl
djnz .loop
.loopend:
; null-terminate the string
xor a
ld (hl), a
ld hl, IO_LINE
pop bc
pop de
pop af
ret

View File

@ -15,16 +15,10 @@
; ;
; That doubly linked list on the z80 would use 7 bytes per line (prev, next, ; That doubly linked list on the z80 would use 7 bytes per line (prev, next,
; offset, len), which is a bit much. Moreover, there's that whole "scratchpad ; offset, len), which is a bit much. Moreover, there's that whole "scratchpad
; being loaded in memory" thing that's a bit iffy. We sacrifice speed for ; being loaded in memory" thing that's a bit iffy.
; memory usage.
; ;
; So here's what we do. First, we have two scratchpads. The first one is the ; We sacrifice speed for memory usage by making that linked list into a simple
; file being read itself. The second one is memory, for modifications we ; array of pointers to line contents in scratchpad. This means that we
; make to the file. When reading the file, we note the offset at which it ends.
; All offsets under this limit refer to the first scratchpad. Other offsets
; refer to the second.
;
; Then, our line list is just an array of 16-bit offsets. This means that we
; don't have an easy access to line length and we have to move a lot of memory ; don't have an easy access to line length and we have to move a lot of memory
; around whenever we add or delete lines. Hopefully, "LDIR" will be our friend ; around whenever we add or delete lines. Hopefully, "LDIR" will be our friend
; here... ; here...