From c5c8369ce9562506845cd419f27eb3ec8d712b60 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Wed, 17 Apr 2019 16:04:24 -0400 Subject: [PATCH] zasm: Add support for (NN) constants --- apps/zasm/zasm.asm | 84 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/apps/zasm/zasm.asm b/apps/zasm/zasm.asm index cd7c008..f8a44d8 100644 --- a/apps/zasm/zasm.asm +++ b/apps/zasm/zasm.asm @@ -4,7 +4,7 @@ ; Number of rows in the argspec table ARGSPEC_TBL_CNT .equ 27 ; Number of rows in the primary instructions table -INSTR_TBLP_CNT .equ 56 +INSTR_TBLP_CNT .equ 58 ; size in bytes of each row in the primary instructions table INSTR_TBLP_ROWSIZE .equ 8 @@ -33,6 +33,45 @@ rlaX: djnz .loop ret +; If string at (HL) starts with ( and ends with ), "enter" into the parens +; (advance HL and put a null char at the end of the string) and set Z. +; Otherwise, do nothing and reset Z. +enterParens: + ld a, (hl) + cp '(' + ret nz ; nothing to do + push hl + ld a, 0 ; look for null char + ; advance until we get null +.loop: + cpi + jp z, .found + jr .loop +.found: + dec hl ; cpi over-advances. go back to null-char + dec hl ; looking at the last char before null + ld a, (hl) + cp ')' + jr nz, .doNotEnter + ; We have parens. While we're here, let's put a null + xor a + ld (hl), a + pop hl ; back at the beginning. Let's advance. + inc hl + cp a ; ensure Z + ret ; we're good! +.doNotEnter: + pop hl + call unsetZ + ret + +; Checks whether A is 'N' or 'M' +checkNOrM: + cp 'N' + ret z + cp 'M' + ret + ; Parse the decimal char at A and extract it's 0-9 numerical value. Put the ; result in A. ; @@ -49,10 +88,20 @@ parseDecimal: ; 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. +; If (HL) contains a number inside parens, we properly enter into it. +; Upon successful return, A is set to 'N' for a parens-less number, 'M' for +; a number inside parens. parseNumber: push hl push de + push bc + ; Let's see if we have parens and already set the A result in B. + ld b, 'N' ; if no parens + call enterParens + jr nz, .noparens + ld b, 'M' ; we have parens and entered it. +.noparens: ld ix, 0 .loop: ld a, (hl) @@ -87,6 +136,8 @@ parseNumber: .error: call unsetZ .end: + ld a, b + pop bc pop de pop hl ret @@ -262,13 +313,12 @@ parseArg: call JUMP_ADDDE djnz .loop1 - ; We exhausted the argspecs. Let's see if it's a number + ; We exhausted the argspecs. Let's see if it's a number. This sets + ; A to 'N' or 'M' call parseNumber - jr nz, .notanumber - ; Alright, we have a parsed number in IX. We're done. - ld a, 'N' - jr .end -.notanumber: + jr z, .end ; Alright, we have a parsed number in IX. We're + ; done. + ; not a number ld a, 0xff jr .end .found: @@ -375,16 +425,18 @@ matchArg: cp a, (hl) ret z ; not an exact match, let's check for numerical constants. + call JUMP_UPCASE cp 'N' jr z, .expectsNumber - cp 'n' + cp 'M' jr z, .expectsNumber jr .notNumber .expectsNumber: ld a, (hl) - cp 'N' ; In parsed arg, we don't have 'n', only 'N' - ret ; whether we match or not, the result of Z is the good - ; one + call checkNOrM ; In parsed arg, we don't have 'n' or 'm', only + ; 'N' and 'M' + ret ; whether we match or not, the result of Z is + ; the good one. .notNumber: ; A bit of a delicate situation here: we want A to go in H but also ; (HL) to go in A. If not careful, we overwrite each other. EXX is @@ -516,16 +568,20 @@ parseLine: push hl ; we use HL to point to the currently read arg ld a, (ix+4) ; first argspec ld hl, curArg1 - cp 'N' + call checkNOrM jr z, .withWord cp 'n' jr z, .withByte + cp 'm' + jr z, .withByte ld a, (ix+5) ; second argspec ld hl, curArg2 - cp 'N' + call checkNOrM jr z, .withWord cp 'n' jr z, .withByte + cp 'm' + jr z, .withByte ; nope, no number, aright, only one opcode ld a, 1 jr .end @@ -653,6 +709,7 @@ instrTBlPrimary: .db "EX",0,0, 'd', 'h', 0, 0xeb ; EX DE, HL .db "EXX", 0, 0, 0, 0, 0xd9 ; EXX .db "HALT", 0, 0, 0, 0x76 ; HALT + .db "IN",0,0, 'A', 'm', 0, 0xdb ; IN A, (n) .db "INC", 0, 'l', 0, 0, 0x34 ; INC (HL) .db "INC", 0, 0xb, 0, 3, 0b00000100 ; INC r .db "INC", 0, 0x3, 0, 4, 0b00000011 ; INC s @@ -671,6 +728,7 @@ instrTBlPrimary: .db "NOP", 0, 0, 0, 0, 0x00 ; NOP .db "OR",0,0, 'l', 0, 0, 0xb6 ; OR (HL) .db "OR",0,0, 0xb, 0, 0, 0b10110000 ; OR r + .db "OUT", 0, 'm', 'A', 0, 0xd3 ; OUT (n), A .db "POP", 0, 0x1, 0, 4, 0b11000001 ; POP qq .db "PUSH", 0x1, 0, 4, 0b11000101 ; PUSH qq .db "RET", 0, 0xa, 0, 3, 0b11000000 ; RET cc