zasm: iiiiiiiincluuuuuuudes!!1!

This commit is contained in:
Virgil Dupras 2019-05-16 21:15:00 -04:00
parent a2d6cea72f
commit 2f0dd5d668
10 changed files with 192 additions and 32 deletions

View File

@ -3,6 +3,7 @@
.equ D_DB 0x00
.equ D_DW 0x01
.equ D_EQU 0x02
.equ D_INC 0x03
.equ D_BAD 0xff
; *** Variables ***
@ -15,12 +16,14 @@ directiveNames:
.db ".DB", 0
.db ".DW", 0
.db ".EQU"
.db "#inc"
; This is a list of handlers corresponding to indexes in directiveNames
directiveHandlers:
.dw handleDB
.dw handleDW
.dw handleEQU
.dw handleINC
handleDB:
push hl
@ -84,12 +87,38 @@ handleEQU:
pop hl
ret
handleINC:
call readWord
jr nz, .end
; HL points to scratchpad
; First, let's verify that our string is enquoted
ld a, (hl)
cp '"'
jr nz, .end
; We have opening quote
inc hl
xor a
call JUMP_FINDCHAR ; go to end of string
dec hl
ld a, (hl)
cp '"'
jr nz, .end
; we have ending quote, let's replace with null char
xor a
ld (hl), a
; Good, let's go back
ld hl, scratchpad+1 ; +1 because of the opening quote
call ioOpenInclude
.end:
xor a ; zero bytes written
ret
; Reads string in (HL) and returns the corresponding ID (D_*) in A. Sets Z if
; there's a match.
getDirectiveID:
push bc
push de
ld b, D_EQU+1 ; D_EQU is last
ld b, D_INC+1 ; D_INC is last
ld c, 4
ld de, directiveNames
call findStringInList

View File

@ -1,3 +1,36 @@
; I/Os in zasm
;
; As a general rule, I/O in zasm is pretty straightfoward. We receive, as a
; parameter, two blockdevs: One that we can read and seek and one that we can
; write to (we never seek into it).
;
; zasm doesn't buffers its reads during tokenization, which simplifies its
; process. However, it also means that it needs, in certain cases, a "putback"
; mechanism, that is, a way to say "you see that character I've just read? that
; was out of my bounds. Could you make it as if I had never read it?". That
; buffer is one character big and is made with the expectation that ioPutBack
; is always called right after a ioGetC (when it's called).
;
; ioPutBack will mess up seek and tell offsets, so thath "put back" should be
; consumed before having to seek and tell.
;
; That's for the general rules.
;
; Now, let's enter includes. To simplify processing, we make include mostly
; transparent to all other units. They always read from ioGetC and a include
; directive should have the exact same effect as copy/pasting the contents of
; the included file in the caller.
;
; By the way: we don't support multiple level of inclusion. Only top level files
; can include.
;
; When we include, all we do here is open the file with fsOpen and set a flag
; indicating that we're inside an include. When that flag is on, GetC, Seek and
; Tell are transparently redirected to their fs* counterpart.
;
; When we reach EOF in an included file, we transparently unset the "in include"
; flag and continue on the general IN stream.
; *** Variables ***
.equ IO_IN_GETC IO_RAMSTART
.equ IO_IN_PUTC IO_IN_GETC+2
@ -7,21 +40,50 @@
.equ IO_OUT_PUTC IO_OUT_GETC+2
.equ IO_OUT_SEEK IO_OUT_PUTC+2
.equ IO_OUT_TELL IO_OUT_SEEK+2
; Save pos for ioSavePos and ioRecallPos
.equ IO_SAVED_POS IO_OUT_TELL+2
; File handle for included source
.equ IO_INCLUDE_HDL IO_SAVED_POS+2
; see ioPutBack below
.equ IO_PUTBACK_BUF IO_OUT_TELL+2
.equ IO_RAMEND IO_PUTBACK_BUF+1
.equ IO_PUTBACK_BUF IO_INCLUDE_HDL+FS_HANDLE_SIZE
.equ IO_IN_INCLUDE IO_PUTBACK_BUF+1
.equ IO_RAMEND IO_IN_INCLUDE+1
; *** Code ***
ioInit:
xor a
ld (IO_PUTBACK_BUF), a
ld (IO_IN_INCLUDE), a
ret
ioGetC:
ld a, (IO_PUTBACK_BUF)
or a ; cp 0
jr nz, .getback
call ioInInclude
jr z, .normalmode
; We're in "include mode", read from FS
push de
ld de, IO_INCLUDE_HDL
call JUMP_FSGETC
pop de
or a ; cp 0
ret nz ; not zero, all good
; We reached EOF. What we do depends on whether we're in Local Pass
; mode. Yes, I know, a bit hackish. Normally, we *should* be
; transparently getting of include mode and avoid meddling with global
; states, but here, we need to tell main.asm that the local scope if
; over *before* we get off include mode, otherwise, our IO_SAVED_POS
; will be wrong (an include IO_SAVED_POS used in global IN stream).
call zasmIsLocalPass
ld a, 0 ; doesn't affect Z flag
ret z ; local pass? return EOF
; regular pass (first or second)? transparently get off include mode.
ld (IO_IN_INCLUDE), a ; A already 0
; continue on to "normal" reading. We don't want to return our zero
.normalmode:
; normal mode, read from IN stream
ld ix, (IO_IN_GETC)
jp (ix)
.getback:
@ -42,10 +104,64 @@ ioPutC:
ld ix, (IO_OUT_PUTC)
jp (ix)
ioSeek:
ioSavePos:
call _ioTell
ld (IO_SAVED_POS), hl
ret
ioRecallPos:
ld hl, (IO_SAVED_POS)
jr _ioSeek
ioRewind:
ld hl, 0
jr _ioSeek
; always in absolute mode (A = 0)
_ioSeek:
call ioInInclude
ld a, 0 ; don't alter flags
jr nz, .include
; normal mode, seek in IN stream
ld ix, (IO_IN_SEEK)
jp (ix)
.include:
; We're in "include mode", seek in FS
push de
ld de, IO_INCLUDE_HDL
call JUMP_FSSEEK
pop de
ret
ioTell:
_ioTell:
call ioInInclude
jp nz, .include
; normal mode, seek in IN stream
ld ix, (IO_IN_TELL)
jp (ix)
.include:
; We're in "include mode", tell from FS
push de
ld de, IO_INCLUDE_HDL
call JUMP_FSTELL
pop de
ret
; Sets Z according to whether we're inside an include
ioInInclude:
ld a, (IO_IN_INCLUDE)
or a ; cp 0
ret
; Open include file name specified in (HL).
; Sets Z on success, unset on error.
ioOpenInclude:
call JUMP_FSFINDFN
ret nz
ld hl, IO_INCLUDE_HDL
call JUMP_FSOPEN
ld a, 1
ld (IO_IN_INCLUDE), a
cp a ; ensure Z
ret

View File

@ -28,7 +28,13 @@
; JUMP_INTOHL
; JUMP_FINDCHAR
; JUMP_BLKSEL
; JUMP_FSFINDFN
; JUMP_FSOPEN
; JUMP_FSGETC
; JUMP_FSSEEK
; JUMP_FSTELL
; RAMSTART (where we put our variables in RAM)
; FS_HANDLE_SIZE
; *** Variables ***
@ -43,11 +49,8 @@
; this special pass, ZASM_FIRST_PASS will also be set so that the rest of the
; code behaves as is we were in the first pass.
.equ ZASM_LOCAL_PASS ZASM_PC+2
; I/O position (in terms of ioSeek/ioTell) of the current context. Used to
; rewind to it after having parsed local labels.
.equ ZASM_CTX_POS ZASM_LOCAL_PASS+1
; What ZASM_PC was when we started our context
.equ ZASM_CTX_PC ZASM_CTX_POS+2
.equ ZASM_CTX_PC ZASM_LOCAL_PASS+1
.equ ZASM_RAMEND ZASM_CTX_PC+2
; *** Code ***
@ -88,8 +91,7 @@ zasmMain:
call zasmParseFile
ret nz
; Second pass
ld hl, 0
call ioSeek
call ioRewind
xor a
ld (ZASM_FIRST_PASS), a
call zasmParseFile
@ -244,8 +246,7 @@ _parseLabel:
_beginLocalPass:
; remember were I/O was
call ioTell
ld (ZASM_CTX_POS), hl
call ioSavePos
; Remember where PC was
ld hl, (ZASM_PC)
ld (ZASM_CTX_PC), hl
@ -264,8 +265,7 @@ _beginLocalPass:
_endLocalPass:
call symSelectGlobalRegistry
; recall I/O pos
ld hl, (ZASM_CTX_POS)
call ioSeek
call ioRecallPos
; recall PC
ld hl, (ZASM_CTX_PC)
ld (ZASM_PC), hl

View File

@ -401,8 +401,8 @@ fsOpen:
fsPlaceH:
push af
push hl
ld ixh, d
ld ixl, e
push de
pop ix
push ix
ld l, (ix)
ld h, (ix+1)
@ -417,8 +417,7 @@ fsPlaceH:
fsAdvanceH:
push af
inc (ix)
ld a, (ix)
jr nc, .end
jr nz, .end
inc (ix+1)
.end:
pop af

View File

@ -14,12 +14,15 @@ $(KERNEL_HEADERS):
zasm-user.h: zasm_user.asm
scas -o - -I ../../apps/zasm $< | ./bin2c.sh USERSPACE | tee $@ > /dev/null
zasm-includes.h: ../../parts/z80 $(CFSPACK)
zasm-includes.cfs: ../../parts/z80 $(CFSPACK)
cp -rf $< zasm-includes
rm zasm-includes/README.md
$(CFSPACK) zasm-includes | ./bin2c.sh FSDEV | tee $@ > /dev/null
$(CFSPACK) zasm-includes > $@
rm -rf zasm-includes
zasm-includes.h: zasm-includes.cfs
./bin2c.sh FSDEV < $< | tee $@ > /dev/null
shell: shell.c libz80/libz80.o shell-kernel.h $(CFSPACK)
zasm: zasm.c libz80/libz80.o zasm-kernel.h zasm-user.h zasm-includes.h
$(TARGETS):
@ -34,4 +37,4 @@ $(CFSPACK):
.PHONY: clean
clean:
rm -f $(TARGETS) $(KERNEL_HEADERS) $(USER_HEADERS)
rm -f $(TARGETS) $(KERNEL_HEADERS) $(USER_HEADERS) zasm-includes.*

View File

@ -83,7 +83,7 @@ static uint8_t io_read(int unused, uint16_t addr)
return fsdev_ptr & 0xff;
} else {
#ifdef DEBUG
fprintf(stderr, "tell %d\n", fsdev_ptr);
fprintf(stderr, "FS tell %d\n", fsdev_ptr);
#endif
fsdev_middle_of_seek_tell = 1;
return fsdev_ptr >> 8;
@ -122,7 +122,7 @@ static void io_write(int unused, uint16_t addr, uint8_t val)
fsdev_ptr |= val;
fsdev_middle_of_seek_tell = 0;
#ifdef DEBUG
fprintf(stderr, "seek %d\n", fsdev_ptr);
fprintf(stderr, "FS seek %d\n", fsdev_ptr);
#endif
} else {
fsdev_ptr = (val << 8) & 0xff00;
@ -155,6 +155,7 @@ int main()
for (int i=0; i<sizeof(FSDEV); i++) {
fsdev[i] = FSDEV[i];
}
fsdev_size = sizeof(FSDEV);
// read stdin in buffer
inpt_size = 0;
inpt_ptr = 0;

View File

@ -18,6 +18,11 @@ jp intoHL
jp findchar
jp parseHexPair
jp blkSel
jp fsFindFN
jp fsOpen
jp fsGetC
jp fsSeek
jp fsTell
#include "core.asm"
.equ BLOCKDEV_RAMSTART RAMSTART
@ -89,19 +94,19 @@ fsdevPutC:
fsdevSeek:
push af
ld a, l
out (FS_SEEK_PORT), a
ld a, h
out (FS_SEEK_PORT), a
ld a, l
out (FS_SEEK_PORT), a
pop af
ret
fsdevTell:
push af
in a, (FS_SEEK_PORT)
ld l, a
in a, (FS_SEEK_PORT)
ld h, a
in a, (FS_SEEK_PORT)
ld l, a
pop af
ret

View File

@ -9,7 +9,13 @@ JUMP_INTOHL .equ 0x15
JUMP_FINDCHAR .equ 0x18
JUMP_PARSEHEXPAIR .equ 0x1b
JUMP_BLKSEL .equ 0x1e
JUMP_FSFINDFN .equ 0x21
JUMP_FSOPEN .equ 0x24
JUMP_FSGETC .equ 0x27
JUMP_FSSEEK .equ 0x2a
JUMP_FSTELL .equ 0x2d
.equ FS_HANDLE_SIZE 8
.equ USER_CODE 0x4800
.equ RAMSTART 0x5800
.org USER_CODE

View File

@ -4,11 +4,12 @@ set -e
TMPFILE=$(mktemp)
SCAS=scas
PARTS=../../../parts/z80
ZASM=../../emul/zasm
ASMFILE=../../../apps/zasm/instr.asm
cmpas() {
EXPECTED=$($SCAS -o - "$1" | xxd)
EXPECTED=$($SCAS -I ${PARTS} -o - "$1" | xxd)
ACTUAL=$(cat $1 | $ZASM | xxd)
if [ "$ACTUAL" == "$EXPECTED" ]; then
echo ok
@ -21,9 +22,6 @@ cmpas() {
fi
}
echo "Comparing core.asm"
cmpas ../../../parts/z80/core.asm
for fn in *.asm; do
echo "Comparing ${fn}"
cmpas $fn

View File

@ -0,0 +1,3 @@
add a, b
#include "core.asm"
inc b