From dde5161fc1c15da068402f90af7eb8b590c0552b Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 1 May 2019 11:26:41 -0400 Subject: [PATCH] zasm: add support for ".db" directive --- apps/zasm/directive.asm | 40 ++++++++++++- apps/zasm/emul/Makefile | 2 +- apps/zasm/instr.asm | 120 ++++++++++---------------------------- apps/zasm/literal.asm | 59 +++++++++++++++++++ apps/zasm/main.asm | 22 +++++-- apps/zasm/tests/test1.asm | 1 + apps/zasm/tok.asm | 4 -- 7 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 apps/zasm/literal.asm diff --git a/apps/zasm/directive.asm b/apps/zasm/directive.asm index 6baf14f..080d82f 100644 --- a/apps/zasm/directive.asm +++ b/apps/zasm/directive.asm @@ -9,6 +9,27 @@ D_BAD .equ 0xff directiveNames: .db ".DB", 0 +; This is a list of handlers corresponding to indexes in directiveNames +directiveHandlers: + .dw handleDB + +handleDB: + push de + push hl + call toWord + ld de, scratchpad + ld a, 8 + call readWord + ld hl, scratchpad + call parseNumber + ld a, ixl + ld (direcData), a + ld a, 1 + pop hl + pop de + ret + + ; Reads string in (HL) and returns the corresponding ID (D_*) in A. Sets Z if ; there's a match. getDirectiveID: @@ -22,6 +43,21 @@ getDirectiveID: pop bc ret +; Parse directive specified in A (D_* const) with args in (HL) and act in +; an appropriate manner. If the directive results in writing data at its +; current location, that data is in (direcData) and A is the number of bytes +; in it. parseDirective: - xor a - ret + push de + ; double A to have a proper offset in directiveHandlers + add a, a + ld de, directiveHandlers + call JUMP_ADDDE + ld ixh, d + ld ixl, e + pop de + jp (ix) + +; *** Variables *** +direcData: + .fill 2 diff --git a/apps/zasm/emul/Makefile b/apps/zasm/emul/Makefile index 4677893..e938f20 100644 --- a/apps/zasm/emul/Makefile +++ b/apps/zasm/emul/Makefile @@ -8,5 +8,5 @@ libz80/libz80.o: libz80/z80.c kernel.h: glue.asm scas -o - -I ../../../parts/z80 $< | ./bin2c.sh KERNEL | tee $@ > /dev/null -zasm.h: $(addprefix ../, main.asm instr.asm tok.asm util.asm) +zasm.h: $(addprefix ../, main.asm instr.asm directive.asm tok.asm literal.asm util.asm) scas -o - -I.. $< | ./bin2c.sh ZASM | tee $@ > /dev/null diff --git a/apps/zasm/instr.asm b/apps/zasm/instr.asm index 19c3ad9..45b29a6 100644 --- a/apps/zasm/instr.asm +++ b/apps/zasm/instr.asm @@ -89,66 +89,6 @@ getInstID: pop bc ret -; Parse the decimal char at A and extract it's 0-9 numerical value. Put the -; result in A. -; -; On success, the carry flag is reset. On error, it is set. -parseDecimal: - ; First, let's see if we have an easy 0-9 case - cp '0' - ret c ; if < '0', we have a problem - cp '9'+1 - ; We are in the 0-9 range - sub a, '0' ; C is clear - ret - -; Parses the string at (HL) and returns the 16-bit value in IX. -; As soon as the number doesn't fit 16-bit any more, parsing stops and the -; number is invalid. If the number is valid, Z is set, otherwise, unset. -parseNumber: - push hl - push de - push bc - - ld ix, 0 -.loop: - ld a, (hl) - cp 0 - jr z, .end ; success! - call parseDecimal - jr c, .error - - ; Now, let's add A to IX. First, multiply by 10. - ld d, ixh ; we need a copy of the initial copy for later - ld e, ixl - add ix, ix ; x2 - add ix, ix ; x4 - add ix, ix ; x8 - add ix, de ; x9 - add ix, de ; x10 - add a, ixl - jr nc, .nocarry - inc ixh -.nocarry: - ld ixl, a - - ; We didn't bother checking for the C flag at each step because we - ; check for overflow afterwards. If ixh < d, we overflowed - ld a, ixh - cp d - jr c, .error ; carry is set? overflow - - inc hl - jr .loop - -.error: - call JUMP_UNSETZ -.end: - pop bc - pop de - pop hl - ret - ; Parse the string at (HL) and check if it starts with IX+, IY+, IX- or IY-. ; Sets Z if yes, unset if no. parseIXY: @@ -450,13 +390,13 @@ handleJPIX: handleJPIY: ld a, 0xfd handleJPIXY: - ld (curUpcode), a + ld (instrUpcode), a ld a, (curArg1+1) cp 0 ; numerical argument *must* be zero jr nz, .error ; ok, we're good ld a, 0xe9 ; second upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a ld c, 2 ret .error: @@ -481,12 +421,12 @@ handleBITHL: call handleBIT ret nz ; error ld a, 0xcb ; first upcode - ld (curUpcode), a + ld (instrUpcode), a ld a, (curArg1+1) ; 0-7 ld b, 3 ; displacement call rlaX or 0b01000110 ; 2nd upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a ld c, 2 ret @@ -496,18 +436,18 @@ handleBITIX: handleBITIY: ld a, 0xfd handleBITIXY: - ld (curUpcode), a ; first upcode + ld (instrUpcode), a ; first upcode call handleBIT ret nz ; error ld a, 0xcb ; 2nd upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a ld a, (curArg2+1) ; IXY displacement - ld (curUpcode+2), a + ld (instrUpcode+2), a ld a, (curArg1+1) ; 0-7 ld b, 3 ; displacement call rlaX or 0b01000110 ; 4th upcode - ld (curUpcode+3), a + ld (instrUpcode+3), a ld c, 4 ret @@ -519,7 +459,7 @@ handleBITR: ld c, a ; write first upcode ld a, 0xcb ; first upcode - ld (curUpcode), a + ld (instrUpcode), a ; get bit value ld a, (curArg1+1) ; 0-7 ld b, 3 ; displacement @@ -529,7 +469,7 @@ handleBITR: or c ; Now we have our ORed value or 0b01000000 ; and with the constant value for that byte... ; we're good! - ld (curUpcode+1), a + ld (instrUpcode+1), a ld c, 2 ret @@ -553,9 +493,9 @@ handleIM: .im2: ld a, 0x5e .proceed: - ld (curUpcode+1), a + ld (instrUpcode+1), a ld a, 0xed - ld (curUpcode), a + ld (instrUpcode), a ld c, 2 ret @@ -565,13 +505,13 @@ handleLDIXn: handleLDIYn: ld a, 0xfd handleLDIXYn: - ld (curUpcode), a + ld (instrUpcode), a ld a, 0x36 ; second upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a ld a, (curArg1+1) ; IXY displacement - ld (curUpcode+2), a + ld (instrUpcode+2), a ld a, (curArg2+1) ; N - ld (curUpcode+3), a + ld (instrUpcode+3), a ld c, 4 ret .error: @@ -584,12 +524,12 @@ handleLDIXr: handleLDIYr: ld a, 0xfd handleLDIXYr: - ld (curUpcode), a + ld (instrUpcode), a ld a, (curArg2+1) ; group value or 0b01110000 ; second upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a ld a, (curArg1+1) ; IXY displacement - ld (curUpcode+2), a + ld (instrUpcode+2), a ld c, 3 ret .error: @@ -597,8 +537,8 @@ handleLDIXYr: ret ; Compute the upcode for argspec row at (DE) and arguments in curArg{1,2} and -; writes the resulting upcode in curUpcode. A is the number if bytes written -; to curUpcode (can be zero if something went wrong). +; writes the resulting upcode in instrUpcode. A is the number if bytes written +; to instrUpcode (can be zero if something went wrong). getUpcode: push ix push de @@ -615,14 +555,14 @@ getUpcode: ld l, (ix+4) ld h, (ix+5) call callHL - ; We have our result written in curUpcode and C is set. + ; We have our result written in instrUpcode and C is set. jp .end .normalInstr: ; we begin by writing our "base upcode", which can be one or two bytes ld a, (ix+4) ; first upcode - ld (curUpcode), a - ld de, curUpcode ; from this point, DE points to "where we are" + ld (instrUpcode), a + ld de, instrUpcode ; from this point, DE points to "where we are" ; in terms of upcode writing. inc de ; make DE point to where we should write next. ld a, (ix+5) ; second upcode @@ -667,11 +607,11 @@ getUpcode: bit 6, (ix+3) jr z, .firstUpcode ; not set: first upcode or (ix+5) ; second upcode - ld (curUpcode+1), a + ld (instrUpcode+1), a jr .writeExtraBytes .firstUpcode: or (ix+4) ; first upcode - ld (curUpcode), a + ld (instrUpcode), a jr .writeExtraBytes .writeExtraBytes: ; Good, we are probably finished here for many primary opcodes. However, @@ -679,7 +619,7 @@ getUpcode: ; if that's the case here, we need to write it too. ; We still have our instruction row in IX and we have DE pointing to ; where we should write next (which could be the second or the third - ; byte of curUpcode). + ; byte of instrUpcode). ld a, (ix+1) ; first argspec ld hl, curArg1 call checkNOrM @@ -724,7 +664,7 @@ getUpcode: ld c, 3 jr .computeBytesWritten .computeBytesWritten: - ; At this point, everything that we needed to write in curUpcode is + ; At this point, everything that we needed to write in instrUpcode is ; written an C is 1 if we have no extra byte, 2 if we have an extra ; byte and 3 if we have an extra word. What we need to do here is check ; if ix+5 is non-zero and increase C if it is. @@ -784,7 +724,7 @@ processArg: ret ; Parse instruction specified in A (I_* const) with args in (HL) and write -; resulting opcode(s) in (curUpcode). Returns the number of bytes written in A. +; resulting opcode(s) in (instrUpcode). Returns the number of bytes written in A. parseInstruction: push bc push hl @@ -1119,6 +1059,6 @@ curArg1: curArg2: .db 0, 0, 0 -curUpcode: +instrUpcode: .db 0, 0, 0, 0 diff --git a/apps/zasm/literal.asm b/apps/zasm/literal.asm new file mode 100644 index 0000000..13f6569 --- /dev/null +++ b/apps/zasm/literal.asm @@ -0,0 +1,59 @@ +; Parse the decimal char at A and extract it's 0-9 numerical value. Put the +; result in A. +; +; On success, the carry flag is reset. On error, it is set. +parseDecimal: + ; First, let's see if we have an easy 0-9 case + cp '0' + ret c ; if < '0', we have a problem + cp '9'+1 + ; We are in the 0-9 range + sub a, '0' ; C is clear + ret + +; Parses the string at (HL) and returns the 16-bit value in IX. +; As soon as the number doesn't fit 16-bit any more, parsing stops and the +; number is invalid. If the number is valid, Z is set, otherwise, unset. +parseNumber: + push hl + push de + push bc + + ld ix, 0 +.loop: + ld a, (hl) + cp 0 + jr z, .end ; success! + call parseDecimal + jr c, .error + + ; Now, let's add A to IX. First, multiply by 10. + ld d, ixh ; we need a copy of the initial copy for later + ld e, ixl + add ix, ix ; x2 + add ix, ix ; x4 + add ix, ix ; x8 + add ix, de ; x9 + add ix, de ; x10 + add a, ixl + jr nc, .nocarry + inc ixh +.nocarry: + ld ixl, a + + ; We didn't bother checking for the C flag at each step because we + ; check for overflow afterwards. If ixh < d, we overflowed + ld a, ixh + cp d + jr c, .error ; carry is set? overflow + + inc hl + jr .loop + +.error: + call JUMP_UNSETZ +.end: + pop bc + pop de + pop hl + ret diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index 9f4c09b..dbfa5f1 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -20,8 +20,9 @@ main: ret #include "util.asm" -#include "tok.asm" +#include "literal.asm" #include "instr.asm" +#include "tok.asm" #include "directive.asm" ; Parse line in (HL), write the resulting opcode(s) in (DE) and returns the @@ -35,11 +36,11 @@ parseLine: jr nz, .error call tokenize ld a, b ; TOK_* - cp TOK_BAD - jr z, .error cp TOK_INSTR jr z, .instr - jr .error ; directive not supported yet + cp TOK_DIRECTIVE + jr z, .direc + jr .error ; token not supported .instr: ld a, c ; I_* call parseInstruction @@ -48,7 +49,18 @@ parseLine: ld b, 0 ld c, a ; written bytes push hl - ld hl, curUpcode + ld hl, instrUpcode + call copy + pop hl + call JUMP_ADDDE + jr .success +.direc: + ld a, c ; D_* + call parseDirective + ld b, 0 + ld c, a ; written bytes + push hl + ld hl, direcData call copy pop hl call JUMP_ADDDE diff --git a/apps/zasm/tests/test1.asm b/apps/zasm/tests/test1.asm index c2b0fbc..812b7d7 100644 --- a/apps/zasm/tests/test1.asm +++ b/apps/zasm/tests/test1.asm @@ -2,3 +2,4 @@ add a, b ; comment inc a ; comment ; comment + .db 42 diff --git a/apps/zasm/tok.asm b/apps/zasm/tok.asm index bb7256a..d400af3 100644 --- a/apps/zasm/tok.asm +++ b/apps/zasm/tok.asm @@ -94,10 +94,6 @@ readWord: ld (de), a ld a, 4 sub a, b - jr .end -.error: - xor a - ld (de), a .end: pop de pop bc