1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-23 15:58:05 +11:00

zasm: Read from and write to streams instead of memory

This commit is contained in:
Virgil Dupras 2019-05-09 15:36:03 -04:00
parent 7f27d63c19
commit d34aff67bb
7 changed files with 118 additions and 128 deletions

69
apps/zasm/io.asm Normal file
View File

@ -0,0 +1,69 @@
; *** Consts ***
.equ IO_MAX_LINELEN 0xff
; *** Variables ***
ioGetCPtr:
.fill 2
ioPutCPtr:
.fill 2
ioLineBuf:
.fill IO_MAX_LINELEN+1
; *** Code ***
ioGetC:
ld ix, (ioGetCPtr)
jp (ix)
ioPutC:
ld ix, (ioPutCPtr)
jp (ix)
; Sets Z is A is CR, LF, or null.
isLineEnd:
or a ; same as cp 0
ret z
cp 0x0d
ret z
cp 0x0a
ret
; Read a single line from ioGetCPtr and place it in ioLineBuf.
; Returns number of chars read in A. 0 means we're at the end of our input
; stream, which happens when GetC unsets Z. Make HL point to ioLineBuf.
; We ignore empty lines and pass through them like butter.
; A null char is written at the end of the line.
ioReadLine:
push bc
; consume ioGetC as long as it yields a line end char.
.loop1:
call ioGetC
jr nz, .eof ; GetC unsets Z? We don't have a line to read,
; we have EOF.
call isLineEnd
jr z, .loop1
; A contains the first char of our line.
ld c, 1
ld (ioLineBuf), a
ld hl, ioLineBuf+1
.loop2:
call ioGetC
call isLineEnd
jr z, .success ; We have end of line
ld (hl), a
inc hl
inc c
jr .loop2
.success:
; write null char at HL before we return
xor a
ld (hl), a
ld a, c
ld hl, ioLineBuf
jr .end
.eof:
xor a
.end:
pop bc
ret

View File

@ -1,4 +1,5 @@
; *** Requirements ***
; blockdev
; JUMP_STRNCMP
; JUMP_ADDDE
; JUMP_UPCASE
@ -6,23 +7,23 @@
; JUMP_INTODE
; *** Code ***
; Parse asm file in (HL) and outputs its upcodes in (DE). Returns the number
; of bytes written in C.
; Read file through GetC routine pointer at HL and outputs its upcodes through
; the PutC routine pointer at DE.
main:
ld bc, 0 ; C is our written bytes counter
ld (ioGetCPtr), hl
ld (ioPutCPtr), de
.loop:
call ioReadLine
or a ; is A 0?
jr z, .stop ; We have EOF
call parseLine
jr nz, .stop
ld a, c
add a, ixl
ld c, a
call gotoNextLine
jr nz, .stop ; error? stop
jr .loop
.stop:
ret
#include "util.asm"
#include "io.asm"
#include "parse.asm"
#include "literal.asm"
#include "instr.asm"
@ -36,38 +37,38 @@ main:
parseLine:
push bc
call gotoNextNotBlankLine
jr nz, .error
call tokenize
ld a, b ; TOK_*
cp TOK_INSTR
jr z, .instr
cp TOK_DIRECTIVE
jr z, .direc
cp TOK_EMPTY
jr z, .success ; empty line? do nothing but don't error out.
jr .error ; token not supported
.instr:
ld a, c ; I_*
call parseInstruction
or a ; is zero?
jr z, .error
ld b, 0
ld c, a ; written bytes
push hl
ld b, a
ld hl, instrUpcode
call copy
pop hl
call JUMP_ADDDE
.loopInstr:
ld a, (hl)
call ioPutC
inc hl
djnz .loopInstr
jr .success
.direc:
ld a, c ; D_*
call parseDirective
ld b, 0
ld c, a ; written bytes
push hl
ld b, a
ld hl, direcData
call copy
pop hl
call JUMP_ADDDE
.loopDirec:
ld a, (hl)
call ioPutC
inc hl
djnz .loopDirec
jr .success
.success:
ld ixl, a

View File

@ -6,19 +6,11 @@ scratchpad:
; *** Code ***
; Sets Z is A is ';', CR, LF, or null.
; Sets Z is A is ';' or null.
isLineEndOrComment:
cp ';'
ret z
; Continues onto isLineEnd...
; Sets Z is A is CR, LF, or null.
isLineEnd:
or a ; same as cp 0
ret z
cp 0x0d
ret z
cp 0x0a
or a ; cp 0
ret
; Sets Z is A is ' ' '\t' or ','
@ -81,48 +73,3 @@ toWord:
.success:
xor a ; ensure Z
ret
; Advance HL to the beginning of the next line, that is, right after the next
; 0x10 or 0x13 or both. If we reach null, we stop and error out.
; Sets Z on success, unsets it on error.
gotoNextLine:
dec hl ; a bit weird, but makes the looping easier
.loop:
inc hl
ld a, (hl)
call isLineEnd
jr nz, .loop
; (HL) is 0x10, 0x13 or 0
or a ; is 0?
jr z, .error
; we might have 0x13 followed by 0x10, let's account for this.
; Yes, 0x10 followed by 0x10 will make us skip two lines, but this is of
; no real consequence in our context.
inc hl
ld a, (hl)
call isLineEnd
jr nz, .success
or a ; is 0?
jr z, .error
; There was another line sep. Skip this char
inc hl
; Continue on to .success
.success:
xor a ; ensure Z
ret
.error:
call JUMP_UNSETZ
ret
; Repeatedly calls gotoNextLine until the line in (HL) points to a line that
; isn't blank or 100% comment. Sets Z if we reach a line, Unset Z if we reach
; EOF
gotoNextNotBlankLine:
call toWord
ret z ; Z set? we have a not-blank line
; Z not set? (HL) is at the end of the line or at the beginning of
; comments.
call gotoNextLine
ret nz
jr gotoNextNotBlankLine

View File

@ -4,6 +4,7 @@
; *** Consts ***
TOK_INSTR .equ 0x01
TOK_DIRECTIVE .equ 0x02
TOK_EMPTY .equ 0xfe ; not a bad token, just an empty line
TOK_BAD .equ 0xff
; *** Code ***
@ -14,6 +15,7 @@ TOK_BAD .equ 0xff
; If no token matches, TOK_BAD is written to B
tokenize:
call toWord
jr nz, .emptyline
call readWord
push hl ; Save advanced HL for later
ld hl, scratchpad
@ -33,3 +35,7 @@ tokenize:
ld c, a
pop hl
ret
.emptyline:
ld b, TOK_EMPTY
; no HL to pop, we jumped before the push
ret

View File

@ -8,27 +8,6 @@ rlaX:
djnz .loop
ret
; Copy BC bytes from (HL) to (DE).
copy:
; first, let's see if BC is zero. if it is, we have nothing to do.
; remember: 16-bit inc/dec don't modify flags. that's why we check B
; and C separately.
inc b
dec b
jr nz, .proceed
inc c
dec c
ret z ; zero? nothing to do
.proceed:
push bc
push de
push hl
ldir
pop hl
pop de
pop bc
ret
callHL:
jp (hl)
ret

View File

@ -1,5 +1,6 @@
TARGETS = shell zasm
KERNEL_HEADERS = shell-kernel.h zasm-kernel.h
USER_HEADERS = zasm-user.h
.PHONY: all
all: $(TARGETS)
@ -23,4 +24,4 @@ libz80/libz80.o: libz80/z80.c
.PHONY: clean
clean:
rm -f $(TARGETS) $(KERNEL_HEADERS)
rm -f $(TARGETS) $(KERNEL_HEADERS) $(USER_HEADERS)

View File

@ -1,8 +1,6 @@
; Glue code for the emulated environment
.equ USER_CODE 0x4000
.equ RAMEND 0xffff
.equ ZASM_INPUT 0xa000
.equ ZASM_OUTPUT 0xd000
.equ STDIO_PORT 0x00
jr init ; 2 bytes
@ -17,35 +15,24 @@ init:
di
ld hl, RAMEND
ld sp, hl
ld hl, ZASM_INPUT
; yes, this means that input can't have null bytes
.inloop:
in a, (STDIO_PORT)
ld (hl), a ; before cond jr so we write a final \0
or a
jr z, .inloopend
inc hl
jr .inloop
.inloopend:
ld hl, ZASM_INPUT
ld de, ZASM_OUTPUT
ld hl, emulGetC
ld de, emulPutC
call USER_CODE
; BC contains the number of written bytes
xor a
cp b
jr nz, .spit
cp c
jr z, .end ; no output
.spit:
ld hl, ZASM_OUTPUT
.outloop:
ld a, (hl)
out (STDIO_PORT), a
cpi ; a trick to inc HL and dec BC at the same time.
; P/V indicates whether BC reached 0
jp pe, .outloop ; BC is not zero, loop
.end:
; signal the emulator we're done
halt
emulGetC:
in a, (STDIO_PORT)
or a ; cp 0
jr z, .eof
cp a ; ensure z
ret
.eof:
call unsetZ
ret
emulPutC:
out (STDIO_PORT), a
ret
#include "core.asm"