diff --git a/compiler/res/prog8lib/conv.p8 b/compiler/res/prog8lib/conv.p8 index ca96968d2..299f116e4 100644 --- a/compiler/res/prog8lib/conv.p8 +++ b/compiler/res/prog8lib/conv.p8 @@ -246,12 +246,12 @@ output .text "0000", $00 ; 0-terminated output buffer (to make printing e ; ---- string conversion to numbers ----- -asmsub any2uword(str string @AY) -> uword @AY { - ; -- returns the number value of the given string - ; the string may be in decimal, hex or binary format +asmsub any2uword(str string @AY) clobbers(Y) -> ubyte @A { + ; -- parses a string into a 16 bit unsigned number. String may be in decimal, hex or binary format. ; (the latter two require a $ or % prefix to be recognised) ; (any non-digit character will terminate the number string that is parsed) - ; result in AY, number of characters processed also remains in cx16.r15 if you want to use it!! (0 = error) + ; returns amount of processed characters in A, and the parsed number will be in cx16.r15. + ; if the string was invalid, 0 will be returned in A. %asm {{ pha sta P8ZP_SCRATCH_W1 @@ -264,11 +264,22 @@ asmsub any2uword(str string @AY) -> uword @AY { cmp #'%' beq _bin pla - jmp str2uword + jsr str2uword + jmp _result _hex pla - jmp hex2uword + jsr hex2uword + jmp _result _bin pla - jmp bin2uword + jsr bin2uword +_result + pha + lda cx16.r15 + sta P8ZP_SCRATCH_B1 ; result value + pla + sta cx16.r15 + sty cx16.r15+1 + lda P8ZP_SCRATCH_B1 + rts }} } diff --git a/examples/cx16/assembler/assem.p8 b/examples/cx16/assembler/assem.p8 index b2afc4c4a..77f0b192e 100644 --- a/examples/cx16/assembler/assem.p8 +++ b/examples/cx16/assembler/assem.p8 @@ -20,8 +20,8 @@ main { } textparse { - str[16] addr_modes = ["Imp", "Acc", "Imm", "Zp", "ZpX", "ZpY", "Rel", "Abs", "AbsX", "AbsY", "Ind", "IzX", "IzY", "Zpr", "Izp", "IaX" ] - ubyte[16] operand_size = [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1] + ; byte counts per address mode id: + ubyte[16] operand_size = [0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1] str input_line = "?" * 40 uword[3] word_addrs @@ -61,12 +61,16 @@ textparse { return } - uword value = conv.any2uword(word_addrs[2]) - if string.compare(word_addrs[0], "*")==0 { - program_counter = value - } else { - set_symbol(word_addrs[0], value) + ubyte nlen = conv.any2uword(word_addrs[2]) + if nlen and @(word_addrs[2]+nlen)==0 { + if string.compare(word_addrs[0], "*")==0 { + program_counter = cx16.r15 + } else { + set_symbol(word_addrs[0], cx16.r15) + } + return } + txt.print("?invalid operand\n") } sub do_label_or_instr() { @@ -124,34 +128,76 @@ textparse { sub assemble_instruction(uword instr_ptr, uword operand_ptr) { uword instruction_info_ptr = instructions.match(instr_ptr) if instruction_info_ptr { - ubyte addr_mode = instructions.determine_addrmode(operand_ptr) - ubyte opcode = instructions.opcode(instruction_info_ptr, addr_mode) - if_cc { - txt.print("?invalid operand\n") - } else { - ubyte num_operand_bytes = operand_size[addr_mode-1] - if not parse_operand_value(operand_ptr, addr_mode) { - txt.print("?invalid operand") - return - } -; txt.print("(debug:) addr.mode: ") -; txt.print_ub(addr_mode) -; txt.nl() - txt.chrout(' ') - txt.print_uwhex(program_counter, 1) - txt.print(" ") - emit(opcode) - if num_operand_bytes==1 { - emit(lsb(cx16.r0)) - } else if num_operand_bytes == 2 { - emit(lsb(cx16.r0)) - emit(msb(cx16.r0)) - } + ; we got a mnemonic match, now process the operand (and its value, if applicable, into cx16.r15) + ubyte addr_mode = parse_operand(operand_ptr) + if addr_mode { + txt.print("operand ok, addr-mode=") + txt.print_ub(addr_mode) txt.nl() + ubyte opcode = instructions.opcode(instruction_info_ptr, addr_mode) + if_cc { + txt.print("?invalid instruction\n") + } else { + ubyte num_operand_bytes = operand_size[addr_mode-1] + txt.chrout(' ') + txt.print_uwhex(program_counter, 1) + txt.print(" ") + emit(opcode) + if num_operand_bytes==1 { + emit(lsb(cx16.r15)) + } else if num_operand_bytes == 2 { + emit(lsb(cx16.r15)) + emit(msb(cx16.r15)) + } + txt.nl() + } + return } - } else { - txt.print("?instruction error\n") + txt.print("?invalid operand\n") + return } + txt.print("?invalid instruction\n") + } + + sub parse_operand(uword operand_ptr) -> ubyte { + ; parses the operand. Returns 2 things: + ; - addressing mode id as result value or 0 when error + ; - operand numeric value in cx16.r15 (if applicable) + ; TODO + + ubyte firstchr = @(operand_ptr) + ubyte parsed_len + when firstchr { + 0 -> return instructions.am_Imp + '#' -> { + ; lda #$99 Immediate + operand_ptr++ + parsed_len = conv.any2uword(operand_ptr) + if parsed_len { + operand_ptr += parsed_len + if @(operand_ptr)==0 + return instructions.am_Imm + } + } + 'a' -> { + ; possibly Accumulator operand + ; TODO parse + return instructions.am_Acc + } + '(' -> { + ; various forms of indirect + ; TODO parse number and other stuff + cx16.r15 = $98ab + return instructions.am_Ind + } + '$', '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { + ; address optionally followed by ,x or ,y + ; TODO Parse + cx16.r0 = $9988 + return instructions.am_Abs + } + } + return 0 } sub emit(ubyte value) { @@ -186,94 +232,6 @@ textparse { return a6 } - sub parse_operand_value(uword operand_ptr, ubyte addr_mode) -> ubyte { - ; -- returns true/false success status, the value is in cx16.r0 if succesful - ; TODO number parsing error detection - ; TODO optimize this (coalesce various parsing options) - - when addr_mode { - instructions.am_Imp, instructions.am_Acc -> { - ; nop / asl a (no operands) - return true - } - instructions.am_Imm -> { - ; lda #$12 - cx16.r0 = conv.any2uword(operand_ptr+1) - debug_print_value(operand_ptr+1) - return true - } - instructions.am_Zp -> { - ; lda $02 - cx16.r0 = conv.any2uword(operand_ptr) - debug_print_value(operand_ptr) - return true - } - instructions.am_Zpr -> { - ; brr0 $12,label - ; TODO parse the label, relative offset - cx16.r0 = conv.any2uword(operand_ptr) - debug_print_value(operand_ptr) - return true - } - instructions.am_ZpX, instructions.am_ZpY -> { - ; lda $02,x / lda $02,y - ; TODO parse the ,x/y - cx16.r0 = conv.any2uword(operand_ptr) - debug_print_value(operand_ptr) - return true - } - instructions.am_Rel -> { - ; bcc $c000 - cx16.r0 = conv.any2uword(operand_ptr) - ; TODO calcualate relative offset to current programcounter - debug_print_value(operand_ptr) - return true - } - instructions.am_Abs -> { - ; jmp $1234 - cx16.r0 = conv.any2uword(operand_ptr) - debug_print_value(operand_ptr) - return true - } - instructions.am_AbsX, instructions.am_AbsY -> { - ; sta $3000,x / sta $3000,y - ; TODO parse the ,x/,y - cx16.r0 = conv.any2uword(operand_ptr) - debug_print_value(operand_ptr) - return true - } - instructions.am_Ind -> { - ; jmp ($fffc) - cx16.r0 = conv.any2uword(operand_ptr+1) - debug_print_value(operand_ptr+1) - return true - } - instructions.am_IzX, instructions.am_IzY, instructions.am_IaX -> { - ; lda ($02,x) / lda ($02),y / jmp ($a000,x) - ; TODO parse the ,x/,y - cx16.r0 = conv.any2uword(operand_ptr+1) - debug_print_value(operand_ptr+1) - return true - } - instructions.am_Izp -> { - ; lda ($02) - cx16.r0 = conv.any2uword(operand_ptr+1) - debug_print_value(operand_ptr+1) - return true - } - } - - return false - - sub debug_print_value(uword optr) { - txt.print("(debug:) operand=") - txt.print(optr) - txt.print(" -> value: ") - txt.print_uwhex(cx16.r0, true) - txt.nl() - } - } - sub split_input() { ; first strip the input string of extra whitespace and comments ubyte copying_word = false @@ -371,56 +329,6 @@ instructions { const ubyte am_Izp = 15 const ubyte am_IaX = 16 - sub determine_addrmode(uword operand_ptr) -> ubyte { - - if not operand_ptr - return am_Imp - - when @(operand_ptr) { - 0 -> return am_Imp - 'a' -> { - if @(operand_ptr+1) == 0 - return am_Acc - ; some expression - ; zp or absolute depends on the value of the symbol referenced - return am_Invalid ; TODO - } - '#' -> { - if @(operand_ptr+1) - return am_Imm - return am_Invalid - } - '(' -> { - ; some indirect TODO - ; can be (zp), (zp,x), (zp),y, (abs), (abs,x) - if @(operand_ptr+1) - return am_Ind - return am_Invalid - } - '$' -> { - ; hex address TODO - ; can be followed by ,x or ,y - if @(operand_ptr+1) - return am_Abs - return am_Invalid - } - '%' -> { - ; bin address TODO - ; can be followed by ,x or ,y - if @(operand_ptr+1) - return am_Abs - return am_Invalid - } - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { - ; absolute or indexed address TODO - ; can be followed by ,x or ,y - return am_Abs - } - } - - return am_Invalid - } - ; TODO: explore (benchmark) hash based matchers asmsub match(uword mnemonic_ptr @AY) -> uword @AY { @@ -468,7 +376,7 @@ instructions { beq _not_found sta P8ZP_SCRATCH_W2 sty P8ZP_SCRATCH_W2+1 - stx cx16.r15 + stx cx16.r5 ; debug result address ;sec @@ -481,7 +389,7 @@ instructions { beq _multi_addrmodes iny lda (P8ZP_SCRATCH_W2),y - cmp cx16.r15 ; check single possible addr.mode + cmp cx16.r5 ; check single possible addr.mode bne _not_found iny lda (P8ZP_SCRATCH_W2),y ; get opcode @@ -493,7 +401,7 @@ _not_found lda #0 rts _multi_addrmodes - ldy cx16.r15 + ldy cx16.r5 lda (P8ZP_SCRATCH_W2),y ; check opcode for addr.mode bne _valid ; opcode $00 usually means 'invalid' but for "brk" it is actually valid so check for "brk" diff --git a/examples/test.p8 b/examples/test.p8 index 13c4278b6..b2773e47d 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,183 +7,70 @@ main { sub start() { - txt.print("yo") + txt.print_ub(conv.any2uword("1")) + txt.chrout(':') + txt.print_uw(cx16.r0) txt.nl() + txt.print_ub(conv.any2uword("11")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("12345")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("65501")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("999999999")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("%10101010")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("$ff")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("$ff99aa")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("%ff")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("abc")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("$zzzz")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword(" 1234")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() + + txt.print_ub(conv.any2uword("")) + txt.chrout(':') + txt.print_uw(cx16.r0) + txt.nl() test_stack.test() - - } - - sub start2 () { - str[] binstrings = [ - "", - "%", - "%0", - "$0", - "%1", - "101", - "%11111111", - "%1111 ", - "% 1111 ", - "%1111%", - "%1111)", - "%1111,", - "%1111.", - "%1111foo", - "%1111000010101010", - "%1111000010101010111" - ] - str[] hexstrings = [ - "", - "$", - "$0", - "%0", - "$1", - "$9", - "9934", - "$91", - "$91 ", - "$ 91 ", - "$12ae$", - "$12ae)", - "$12ae,", - "$12ae.", - "$12aez00", - "$12345" - ] - str[] posdecstrings = [ - "", - "0", - "1", - "9", - "$9", - "10", - "11", - "123", - "255", - "62221", - "42 ", - " 42 ", - "42$", - "42)", - "42,", - "42.", - "42aaaa" - ] - str[] worddecstrings = [ - "", - "0", - "1", - "9", - "$9", - "10", - "11", - "123", - "255", - "62221", - "42 ", - " 42 ", - "42$", - "42)", - "42,", - "42.", - "42aaaa", - "-", - "-0", - "-1", - "-9", - "$9", - "-10", - "-11", - "-123", - "-255", - "-62221", - "-32221", - "-42 ", - "- 42 ", - "-42-", - "-42$", - "-42)", - "-42,", - "-42.", - "-42aaaa" - ] - - uword value - word wvalue - uword strptr - for strptr in binstrings { - value = conv.bin2uword(strptr) - txt.print(strptr) - txt.print(" = ") - txt.print_uw(value) - txt.print(" = ") - txt.print_uwbin(value, true) - txt.print(" #") - txt.print_uw(cx16.r15) ; number of chars processedc - txt.nl() - } - - txt.nl() - for strptr in hexstrings { - value = conv.hex2uword(strptr) - txt.print(strptr) - txt.print(" = ") - txt.print_uw(value) - txt.print(" = ") - txt.print_uwhex(value, true) - txt.print(" #") - txt.print_uw(cx16.r15) ; number of chars processedc - txt.nl() - } - - txt.nl() - for strptr in posdecstrings { - value = conv.str2uword(strptr) - txt.print(strptr) - txt.print(" = ") - txt.print_uw(value) - txt.print(" #") - txt.print_uw(cx16.r15) ; number of chars processedc - txt.nl() - } - - txt.nl() - for strptr in worddecstrings { - wvalue = conv.str2word(strptr) - txt.print(strptr) - txt.print(" = ") - txt.print_w(wvalue) - txt.print(" #") - txt.print_uw(cx16.r15) ; number of chars processedc - txt.nl() - } - - -; found = string.find("irmen de jong", ' ') -; txt.print_uwhex(found, 1) -; txt.nl() -; found = string.find(" irmen-de-jong", ' ') -; txt.print_uwhex(found, 1) -; txt.nl() -; found = string.find("irmen-de-jong ", ' ') -; txt.print_uwhex(found, 1) -; txt.nl() -; found = string.find("irmen-de-jong", ' ') -; txt.print_uwhex(found, 1) -; txt.nl() - -; found = strfinds("irmen de jong", "de") -; txt.print_uwhex(found, 1) -; txt.nl() -; found = strfinds("irmen de jong", "irmen") -; txt.print_uwhex(found, 1) -; txt.nl() -; found = strfinds("irmen de jong", "jong") -; txt.print_uwhex(found, 1) -; txt.nl() -; found = strfinds("irmen de jong", "de456") -; txt.print_uwhex(found, 1) -; txt.nl() } }