; cmd - parse and interpret command ; ; *** Consts *** ; address type .equ ABSOLUTE 0 ; handles +, - and ".". For +, easy. For -, addr is negative. For ., it's 0. .equ RELATIVE 1 .equ EOF 2 ; *** Variables *** ; An address is a one byte type and a two bytes line number (0-indexed) .equ CMD_ADDR1 CMD_RAMSTART .equ CMD_ADDR2 @+3 .equ CMD_TYPE @+3 .equ CMD_RAMEND @+1 ; *** Code *** ; Parse command line that HL points to and set unit's variables ; Sets Z on success, unset on error. cmdParse: ld a, (hl) cp 'q' jr z, .simpleCmd cp 'w' jr z, .simpleCmd ld ix, CMD_ADDR1 call .readAddr ret nz ; Before we check for the existence of a second addr, let's set that ; second addr to the same value as the first. That's going to be its ; value if we have to ",". ld a, (ix) ld (CMD_ADDR2), a ld a, (ix+1) ld (CMD_ADDR2+1), a ld a, (ix+2) ld (CMD_ADDR2+2), a ld a, (hl) cp ',' jr nz, .noaddr2 inc hl ld ix, CMD_ADDR2 call .readAddr ret nz .noaddr2: ; We expect HL (rest of the cmdline) to be a null char or an accepted ; cmd, otherwise it's garbage ld a, (hl) or a jr z, .nullCmd cp 'p' jr z, .okCmd cp 'd' jr z, .okCmd cp 'a' jr z, .okCmd cp 'i' jr z, .okCmd ; unsupported cmd ret ; Z unset .nullCmd: ld a, 'p' .okCmd: ld (CMD_TYPE), a ret ; Z already set .simpleCmd: ; Z already set ld (CMD_TYPE), a ret ; Parse the string at (HL) and sets its corresponding address in IX, properly ; considering implicit values (current address when nothing is specified). ; advances HL to the char next to the last parsed char. ; It handles "+" and "-" addresses such as "+3", "-2", "+", "-". ; Sets Z on success, unset on error. Line out of bounds isn't an error. Only ; overflows. .readAddr: ld a, (hl) cp '+' jr z, .plusOrMinus cp '-' jr z, .plusOrMinus cp '.' jr z, .dot cp '$' jr z, .eof ; inline parseDecimalDigit add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff sub 0xff-9 ; maps to 0-9 and carries if not a digit jr c, .notHandled ; straight number ld a, ABSOLUTE ld (ix), a call .parseDecimalM ret nz dec de ; from 1-based to 0-base jr .end .dot: inc hl ; advance cmd cursor ; the rest is the same as .notHandled .notHandled: ; something else. It's probably our command. Our addr is therefore "." ld a, RELATIVE ld (ix), a xor a ; sets Z ld (ix+1), a ld (ix+2), a ret .eof: inc hl ; advance cmd cursor ld a, EOF ld (ix), a ret ; Z set during earlier CP .plusOrMinus: push af ; preserve that + or - ld a, RELATIVE ld (ix), a inc hl ; advance cmd cursor ld a, (hl) ld de, 1 ; if .pmNoSuffix ; inline parseDecimalDigit add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff sub 0xff-9 ; maps to 0-9 and carries if not a digit jr c, .pmNoSuffix call .parseDecimalM ; --> DE .pmNoSuffix: pop af ; bring back that +/- cp '-' jr nz, .end ; we had a "-". Negate DE push hl ld hl, 0 sbc hl, de ex de, hl pop hl .end: ; we still have to save DE in memory ld (ix+1), e ld (ix+2), d cp a ; ensure Z ret ; call parseDecimal and set HL to the character following the last digit .parseDecimalM: push bc push ix push hl .loop: inc hl ld a, (hl) ; inline parseDecimalDigit add a, 0xff-'9' ; maps '0'-'9' onto 0xf6-0xff sub 0xff-9 ; maps to 0-9 and carries if not a digit jr nc, .loop ; We're at the first non-digit char. Let's save it because we're going ; to temporarily replace it with a null. ld b, (hl) ; refetch (HL), A has been mucked with in ; parseDecimalDigit xor a ld (hl), a ; Now, let's go back to the beginning of the string and parse it. ; but before we do this, let's save the end of string in DE ex de, hl pop hl call parseDecimal ; Z is set properly at this point. nothing touches Z below. ld a, b ld (de), a ex de, hl ; put end of string back from DE to HL ; Put addr in its final register, DE push ix \ pop de pop ix pop bc ret