mirror of
https://github.com/hsoft/collapseos.git
synced 2024-12-24 14:38:05 +11:00
zasm: iiiiiiiincluuuuuuudes!!1!
This commit is contained in:
parent
a2d6cea72f
commit
2f0dd5d668
@ -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
|
||||
|
124
apps/zasm/io.asm
124
apps/zasm/io.asm
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.*
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
3
tools/tests/zasm/test6.asm
Normal file
3
tools/tests/zasm/test6.asm
Normal file
@ -0,0 +1,3 @@
|
||||
add a, b
|
||||
#include "core.asm"
|
||||
inc b
|
Loading…
Reference in New Issue
Block a user