From d34aff67bbd603d4dfec315b1ed6aebe8b6f3f3a Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Thu, 9 May 2019 15:36:03 -0400 Subject: [PATCH] zasm: Read from and write to streams instead of memory --- apps/zasm/io.asm | 69 ++++++++++++++++++++++++++++++++++++++++ apps/zasm/main.asm | 45 +++++++++++++------------- apps/zasm/parse.asm | 57 ++------------------------------- apps/zasm/tok.asm | 6 ++++ apps/zasm/util.asm | 21 ------------ tools/emul/Makefile | 3 +- tools/emul/zasm_glue.asm | 45 ++++++++++---------------- 7 files changed, 118 insertions(+), 128 deletions(-) create mode 100644 apps/zasm/io.asm diff --git a/apps/zasm/io.asm b/apps/zasm/io.asm new file mode 100644 index 0000000..fb01c92 --- /dev/null +++ b/apps/zasm/io.asm @@ -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 + diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index 9d05056..867af76 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -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 diff --git a/apps/zasm/parse.asm b/apps/zasm/parse.asm index 5036c75..64fe830 100644 --- a/apps/zasm/parse.asm +++ b/apps/zasm/parse.asm @@ -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 - diff --git a/apps/zasm/tok.asm b/apps/zasm/tok.asm index 4c655a9..b4d0bfd 100644 --- a/apps/zasm/tok.asm +++ b/apps/zasm/tok.asm @@ -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 diff --git a/apps/zasm/util.asm b/apps/zasm/util.asm index 7cd4508..16b0bca 100644 --- a/apps/zasm/util.asm +++ b/apps/zasm/util.asm @@ -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 diff --git a/tools/emul/Makefile b/tools/emul/Makefile index b30b402..f1d164f 100644 --- a/tools/emul/Makefile +++ b/tools/emul/Makefile @@ -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) diff --git a/tools/emul/zasm_glue.asm b/tools/emul/zasm_glue.asm index 26f0949..9f4d34f 100644 --- a/tools/emul/zasm_glue.asm +++ b/tools/emul/zasm_glue.asm @@ -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"