From 887802efcdb3b56263069cc6778a8f53ed89d599 Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Mon, 22 Jun 2020 17:56:52 -0400 Subject: Did some more stuff. - Fixed some bugs in the emulator's assembler. - Worked on SuBAsm's lexer some more. - Created a new directory for the SuB suite, and moved all of the SuB suite's files in there. --- asmmon.c | 17 +- disasm.c | 46 +- lexer.c | 4 +- programs/lexer.s | 231 -------- programs/sub-suite/lexer.s | 413 ++++++++++++++ programs/sub-suite/subasm.s | 388 +++++++++++++ programs/sub-suite/subeditor.s | 1234 ++++++++++++++++++++++++++++++++++++++++ programs/sub-suite/utils.s | 394 +++++++++++++ programs/subasm.s | 383 ------------- programs/subeditor.s | 1234 ---------------------------------------- programs/utils.s | 393 ------------- sux.c | 2 +- 12 files changed, 2470 insertions(+), 2269 deletions(-) delete mode 100644 programs/lexer.s create mode 100644 programs/sub-suite/lexer.s create mode 100644 programs/sub-suite/subasm.s create mode 100644 programs/sub-suite/subeditor.s create mode 100644 programs/sub-suite/utils.s delete mode 100644 programs/subasm.s delete mode 100644 programs/subeditor.s delete mode 100644 programs/utils.s diff --git a/asmmon.c b/asmmon.c index 9f1b511..5bc1993 100644 --- a/asmmon.c +++ b/asmmon.c @@ -127,8 +127,7 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u char ch[6]; do { - token *tok = s->tok; - token *t; + token *t = s->tok; uint8_t am = 0xFF; uint8_t rs = 0xFF; if (dbg) { @@ -151,8 +150,7 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u tabs--; } } - for (; tok && tok->id != TOK_COMMENT && tok >= t; tok = tok->next) { - t = tok; + while (t && t->id != TOK_COMMENT) { switch (t->id) { case TOK_DIR : printf(".%s ", dir_t[t->type] ); break; case TOK_OPCODE: @@ -163,8 +161,8 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u j = 0; printf("%s", mne_lower); am = t->type; - t = t->next; - if (t && t->id == TOK_RS) { + if (t->next && t->next->id == TOK_RS) { + t = t->next; rs = t->type; printf("%s", rs_t[t->type]); } @@ -217,8 +215,10 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u default : ch[j++] = t->byte; break; case '\n': ch[j++] = '\\'; ch[j++] = 'n' ; break; case '\r': ch[j++] = '\\'; ch[j++] = 'r' ; break; + case '\t': ch[j++] = '\\'; ch[j++] = 't' ; break; case '\b': ch[j++] = '\\'; ch[j++] = 'b' ; break; case '\\': ch[j++] = '\\'; ch[j++] = '\\'; break; + case '\0': ch[j++] = '\\'; ch[j++] = '0'; break; case '\'': ch[j++] = '\\'; ch[j++] = '\''; break; case '\"': ch[j++] = '\\'; ch[j++] = '\"'; break; } @@ -245,6 +245,7 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u } break; } + t = t->next; } if (am != 0xFF) { if (fall) { @@ -285,8 +286,8 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u tabs--; } } - if (tok && tok->id == TOK_COMMENT) { - printf(";%s", (tok->str) ? tok->str : ""); + if (t && t->id == TOK_COMMENT) { + printf(";%s", (t->str) ? t->str : ""); } puts(""); s = s->next; diff --git a/disasm.c b/disasm.c index db43acf..5ccede4 100644 --- a/disasm.c +++ b/disasm.c @@ -74,7 +74,7 @@ void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, uint8_t iscursor = 0; union reg ptr; uint32_t adr; - wmove(scr, 30, 0); + /*wmove(scr, 30, 0); wclrtoeol(scr); adr = 0x25; ptr.u8[0] = addr[adr+0]; ptr.u8[1] = addr[adr+1]; @@ -99,7 +99,7 @@ void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, ptr.u8[2] = addr[adr+2]; ptr.u8[3] = addr[adr+3]; ptr.u8[4] = addr[adr+4]; ptr.u8[5] = addr[adr+5]; ptr.u8[6] = addr[adr+6]; ptr.u8[7] = addr[adr+7]; - wprintw(scr, ", idx0: $%04"PRIX64, ptr.u64); + wprintw(scr, ", idx0: $%04"PRIX64, ptr.u64);*/ if (address == CTRL_ADDR || addr[STEP_ADDR]) { mvwprintw(scr, 29, 0, "address: $%04"PRIX64", scr_row: %02u, scr_col: %02u, scr_str: %02u, scr_end: %02u\r", address, addr[0], addr[1], addr[0x22], addr[0x23]); adr = 0x30000; @@ -108,13 +108,15 @@ void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, for (uint8_t i = 0; i < 16; i++) { wprintw(scr, "%02X", addr[adr+i]); } - mvwprintw(scr, ln++, 0, "buffer:\r"); + mvwprintw(scr, ln++, 0, "buffer: "); wmove(scr, ln++, 0); - for (uint8_t i = 0; i < 10; i++) { - line_idx = (i << 6) + (i << 4); + uint8_t maxrow = 10; + int line_offset = (addr[0]-(maxrow-1) >= 0) ? addr[0]-(maxrow-1) : 0; + for (uint8_t i = 0; i < maxrow; i++) { + line_idx = (i+addr[0x22]+line_offset << 6) + (i+addr[0x22]+line_offset << 4); for (uint8_t j = 0; j < 0x50; j++) { wprintw(scr, "%02X", addr[tmpad+j+line_idx]); - if ((addr[0]+addr[0x22]) == i && addr[1] == j) { + if ((addr[0] == i+line_offset) && addr[1] == j) { iscursor=1; getyx(scr,row, col); wmove(scr, ln++, 0); @@ -133,19 +135,27 @@ void disasm(struct sux *cpu, uint64_t *operands, uint8_t lines, uint8_t opcode, wmove(scr, ln++, 0); } } - /*if (address == 0x4000 || tmpaddr == 0x4000 || addr[STEP_ADDR]) { - ln = 46; - tmpad = 0x4000; - line_idx = 0; - mvwprintw(scr, ln++, 0, "cmd_buf:"); - for (uint8_t i = 0; i < 5; i++) { - wmove(scr, ln++, 0); - line_idx = (i << 4)+(i << 6); - for (uint8_t j = 0; j < 0x50; j++) { - wprintw(scr, "%02X", addr[tmpad+j+line_idx]); - } - wprintw(scr, ", i: %02X", i); + /* + wmove(scr, 47, 0); + wclrtoeol(scr); + wprintw(scr, "a: $%02X,", addr[0x0A]); + wprintw(scr, " b: $%02X,", addr[0x0B]); + wprintw(scr, " c: $%02X,", addr[0x0C]); + wprintw(scr, " d: $%02X,", addr[0x0D]); + wprintw(scr, " e: $%02X,", addr[0x0E]); + wprintw(scr, " f: $%02X", addr[0x0F]); + tmpad = 0x33000; + line_idx = 0; + wprintw(scr, "cmd_buf:"); + for (uint8_t i = 0; i < 1; i++) { + wmove(scr, ln++, 0); + wclrtoeol(scr); + line_idx = (i << 4)+(i << 6); + for (uint8_t j = 0; j < 0x50; j++) { + wprintw(scr, "%02X", addr[tmpad+j+line_idx]); } + wprintw(scr, ", i: %02X", i); }*/ + } } diff --git a/lexer.c b/lexer.c index 78d6044..55eb576 100644 --- a/lexer.c +++ b/lexer.c @@ -361,7 +361,8 @@ uint64_t lex(char *str, uint64_t address, uint8_t dbg) { break; case PTOK_SQUOTE: i++; - k = j; + k = 0; + j = 0; while (isdelm(str[i], dbg) != 8 || isesc) { isesc = (str[i] == '\\' && str[i-1] != '\\'); lexeme[j++] = str[i++]; @@ -373,6 +374,7 @@ uint64_t lex(char *str, uint64_t address, uint8_t dbg) { switch (lexeme[++k]) { case 'n' : ch = '\n'; break; case 'r' : ch = '\r'; break; + case 't' : ch = '\t'; break; case 'b' : ch = '\b'; break; case '\'': ch = '\''; break; case '\"': ch = '\"'; break; diff --git a/programs/lexer.s b/programs/lexer.s deleted file mode 100644 index cd5bb54..0000000 --- a/programs/lexer.s +++ /dev/null @@ -1,231 +0,0 @@ -; Lexer, and supporting routines for SuBAsm. - -; Enums. - -; Directives. -DIR_ORG = 0 ; Origin. -DIR_BYTE = 1 ; Byte = 8 bits. -DIR_WORD = 2 ; Word = 16 bits. -DIR_DWORD = 3 ; Dword = 32 bits. -DIR_QWORD = 4 ; Qword = 64 bits. -DIR_INCL = 5 ; Include. - -; Tokens. -TOK_DIR = 0 ; Directive. -TOK_LOCAL = 1 ; Local syobol. -TOK_LABEL = 2 ; Label. -TOK_SYM = 3 ; Symbol. -TOK_EXPR = 4 ; Expression. -TOK_CSV = 5 ; Comma separated value. -TOK_STR = 6 ; String. -TOK_CHAR = 7 ; Character. -TOK_IND = 8 ; Indirect addressing. -TOK_IMM = 9 ; Immediate data. -TOK_MNE = 10 ; Opcode/Mnemonic. -TOK_RS = 11 ; Register size prefix. -TOK_COMM = 12 ; Comment. -TOK_HEX = 13 ; Hex value. -TOK_DEC = 14 ; Decimal value. -TOK_BIN = 15 ; Binary value. -TOK_INCL = 16 ; Include file. - -; Pre-Tokens. -PTOK_DOT = 0 ; . -PTOK_AT = 1 ; @ -PTOK_COLON = 2 ; : -PTOK_EQU = 3 ; = -PTOK_PLUS = 4 ; + -PTOK_MINUS = 5 ; - -PTOK_GT = 6 ; > -PTOK_LT = 7 ; < -PTOK_LBRAK = 8 ; ( -PTOK_RBRAK = 9 ; ) -PTOK_COMMA = 10 ; , -PTOK_X = 11 ; x -PTOK_Y = 12 ; y -PTOK_DQUOT = 13 ; " -PTOK_SQUOT = 14 ; ' -PTOK_HASH = 15 ; # -PTOK_SCOLN = 16 ; ; -PTOK_DOLR = 17 ; $ -PTOK_PRCNT = 18 ; % -PTOK_NUM = 19 ; 0-9 -PTOK_ALPH = 20 ; a-z A-Z -PTOK_OTHR = 21 ; Everything else. - -; Expressions. -EXPR_PLUS = 0 ; Plus. -EXPR_MINUS = 1 ; Minus. -EXPR_LOW = 2 ; Lower half of address. -EXPR_HIGH = 3 ; Upper half of address. -EXPR_NONE = 4 ; No expression. - - -; Data. -.org lexer_data -; Jump table for parsing pre-tokens. -swtab: - .word ptok_dot ; PTOK_DOT - .word ptok_at ; PTOK_AT - .word ptok_col ; PTOK_COLON - .word ptok_equ ; PTOK_EQU - .word ptok_plus ; PTOK_PLUS - .word ptok_min ; PTOK_MINUS - .word ptok_gt ; PTOK_GT - .word ptok_lt ; PTOK_LT - .word ptok_lbrk ; PTOK_LBRAK - .word ptok_rbrk ; PTOK_RBRAK - .word ptok_com ; PTOK_COMMA - .word ptok_xr ; PTOK_X - .word ptok_yr ; PTOK_Y - .word ptok_dqu ; PTOK_DQUOT - .word ptok_squ ; PTOK_SQUOT - .word ptok_hash ; PTOK_HASH - .word ptok_scol ; PTOK_SCOLN - .word ptok_dolr ; PTOK_DOLR - .word ptok_prcn ; PTOK_PRCNT - .word ptok_num ; PTOK_NUM - .word ptok_alph ; PTOK_ALPH - .word ptok_othr ; PTOK_OTHR - -; Data entry point for utility subroutines. -util_data: - - -; Program code. -.org lexer -lex: - ldx #0 ; Reset X. - txa ; Reset A. - phy #2 ; Preserve the screen buffer index. - txy ; Reset Y. - sty.q idx0 ; Clear the first index. - sty.q idx1 ; Clear the second index. - sty.q idx2 ; Clear the third index. -; lda (ptr), y ; Get a character from the line. -; pha #1 ; Preserve the character. -; jsr isdigit ; Is this character a digit? -; pla #1 ; Get the character back. -@getline: - lda #2 ; Get the third byte, of the line table address. - lsl #$10 ; Shift it by 2 bytes. - ldb #1 ; Set the second pointer - lda.w ltok ; to the last line. - jsr set_ptr ; - lda.w (ptr2) ; Get the next line. - jsr set_ptr ; Set the second pointer to the next line. - sta.w ctok ; Make it the current line. - and #0 ; Reset A. -@loop: - ldy.w idx0 ; Get the string index. - lda (ptr), y ; Get a character from the line. - jsr isdelm ; Get the delimiter. - cmp #1 ; Are we at the end of the line? - beq @end ; Yes, so we're done. -@spaces: - ldy.w idx0 ; Get the string index. - inc.w idx0 ; Increment the string index. - lda (ptr), y ; Get a character from the line. - pha #1 ; Preserve the character. - jsr isdelm ; Get the delimiter. - and #$10 ; Is this character, a space, or tab? - pla #1 ; Get the character back. - beq @isstart ; No, so check for the start of the line. - cmp #' ' ; Is this character, a space? - beq @incs ; Yes, so increment the starting space count. - cmp #'\t' ; No, but is it a tab? - beq @inct ; Yes, so increment the starting tab count. - jmp @spaces ; No, so keep looping. -@incs: - inc idx1 ; Increment the space count. - jmp @spaces ; Keep looping. -@inct: - inc idx1+1 ; Increment the tab count. - jmp @spaces ; Keep looping. -@isstart: - pha #2 ; Preserve the character. - lda.w idx1 ; Was there any whitespace? - pla #2 ; Get the character back. - beq @switch ; No, so start lexing. - cpb #1 ; Yes, and are we at the start of the line? - bne @switch ; No, so start lexing. -@whtspace: - ldy #2 ; Yes, so set the line index to the starting whitespace counters. - lda.w idx1 ; Get both indecies. - sta.w (ptr2), y ; Save them in the line. - and #0 ; Reset A. - sta.w idx1 ; Reset the second index. - deb ; Set the isstart flag to false. -@switch: - jsr get_ptok ; Get the pre-token. - jsr parse_ptok ; Parse the pre-token. - beq @end ; We got to the end of the string. - jmp @loop ; Keep looping. -@end: - ply #2 ; Get the screen buffer index back. - rts ; End of lex. - -parse_ptok: - pha #1 ; Preserve the pre-token. - ldb #2 ; Set the third pointer - lda.w #swtab ; to the start of the jump table. - jsr set_ptr ; - and #0 ; Reset A. - pla #1 ; Get the pre-token back. - phy #2 ; Preserve Y. - lsl #1 ; Multiply the pre-token by two, to get the jump index. - tay ; Get the index of the jump table. - lda.w (ptr3), y ; Get the address to jump to. - jsr set_ptr ; Set the third pointer to the case address. - and #0 ; Reset A. - tab ; Reset B. - ply #2 ; Get Y back. - jmp (ptr3) ; Jump to the case label. -ptok_dot: - rts ; End of parse_ptok. -ptok_at: - rts ; End of parse_ptok. -ptok_col: - rts ; End of parse_ptok. -ptok_equ: - rts ; End of parse_ptok. -ptok_plus: - rts ; End of parse_ptok. -ptok_min: - rts ; End of parse_ptok. -ptok_gt: - rts ; End of parse_ptok. -ptok_lt: - rts ; End of parse_ptok. -ptok_lbrk: - rts ; End of parse_ptok. -ptok_rbrk: - rts ; End of parse_ptok. -ptok_com: - rts ; End of parse_ptok. -ptok_xr: - rts ; End of parse_ptok. -ptok_yr: - rts ; End of parse_ptok. -ptok_dqu: - rts ; End of parse_ptok. -ptok_squ: - rts ; End of parse_ptok. -ptok_hash: - rts ; End of parse_ptok. -ptok_scol: - rts ; End of parse_ptok. -ptok_dolr: - rts ; End of parse_ptok. -ptok_prcn: - rts ; End of parse_ptok. -ptok_num: - rts ; End of parse_ptok. -ptok_alph: - rts ; End of parse_ptok. -ptok_othr: - rts ; End of parse_ptok. - - -; Entry point for utility subroutines. -utils: diff --git a/programs/sub-suite/lexer.s b/programs/sub-suite/lexer.s new file mode 100644 index 0000000..315bee4 --- /dev/null +++ b/programs/sub-suite/lexer.s @@ -0,0 +1,413 @@ +; Lexer, and supporting routines for SuBAsm. + +; Enums. + +; Directives. +DIR_ORG = 0 ; Origin. +DIR_BYTE = 1 ; Byte = 8 bits. +DIR_WORD = 2 ; Word = 16 bits. +DIR_DWORD = 3 ; Dword = 32 bits. +DIR_QWORD = 4 ; Qword = 64 bits. +DIR_INCL = 5 ; Include. + +; Tokens. +TOK_DIR = 0 ; Directive. +TOK_LOCAL = 1 ; Local syobol. +TOK_LABEL = 2 ; Label. +TOK_SYM = 3 ; Symbol. +TOK_EXPR = 4 ; Expression. +TOK_CSV = 5 ; Comma separated value. +TOK_STR = 6 ; String. +TOK_CHAR = 7 ; Character. +TOK_IND = 8 ; Indirect addressing. +TOK_IMM = 9 ; Immediate data. +TOK_MNE = 10 ; Opcode/Mnemonic. +TOK_RS = 11 ; Register size prefix. +TOK_COMM = 12 ; Comment. +TOK_HEX = 13 ; Hex value. +TOK_DEC = 14 ; Decimal value. +TOK_BIN = 15 ; Binary value. +TOK_INCL = 16 ; Include file. + +; Pre-Tokens. +PTOK_DOT = 0 ; . +PTOK_AT = 1 ; @ +PTOK_COLON = 2 ; : +PTOK_EQU = 3 ; = +PTOK_PLUS = 4 ; + +PTOK_MINUS = 5 ; - +PTOK_GT = 6 ; > +PTOK_LT = 7 ; < +PTOK_LBRAK = 8 ; ( +PTOK_RBRAK = 9 ; ) +PTOK_COMMA = 10 ; , +PTOK_X = 11 ; x +PTOK_Y = 12 ; y +PTOK_DQUOT = 13 ; " +PTOK_SQUOT = 14 ; ' +PTOK_HASH = 15 ; # +PTOK_SCOLN = 16 ; ; +PTOK_DOLR = 17 ; $ +PTOK_PRCNT = 18 ; % +PTOK_NUM = 19 ; 0-9 +PTOK_ALPH = 20 ; a-z A-Z +PTOK_OTHR = 21 ; Everything else. + +; Expressions. +EXPR_PLUS = 0 ; Plus. +EXPR_MINUS = 1 ; Minus. +EXPR_LOW = 2 ; Lower half of address. +EXPR_HIGH = 3 ; Upper half of address. +EXPR_NONE = 4 ; No expression. + + +; Data. +.org lexer_data +; Jump table for parsing pre-tokens. +swtab: + .word ptok_dot ; PTOK_DOT + .word ptok_at ; PTOK_AT + .word ptok_col ; PTOK_COLON + .word ptok_equ ; PTOK_EQU + .word ptok_plus ; PTOK_PLUS + .word ptok_min ; PTOK_MINUS + .word ptok_gt ; PTOK_GT + .word ptok_lt ; PTOK_LT + .word ptok_lbrk ; PTOK_LBRAK + .word ptok_rbrk ; PTOK_RBRAK + .word ptok_com ; PTOK_COMMA + .word ptok_xr ; PTOK_X + .word ptok_yr ; PTOK_Y + .word ptok_dqu ; PTOK_DQUOT + .word ptok_squ ; PTOK_SQUOT + .word ptok_hash ; PTOK_HASH + .word ptok_scol ; PTOK_SCOLN + .word ptok_dolr ; PTOK_DOLR + .word ptok_prcn ; PTOK_PRCNT + .word ptok_num ; PTOK_NUM + .word ptok_alph ; PTOK_ALPH + .word ptok_othr ; PTOK_OTHR + +; Data entry point for utility subroutines. +util_data: + + +; Program code. +.org lexer +lex: + ldx #0 ; Reset X. + txa ; Reset A. + phy #2 ; Preserve the screen buffer index. + txy ; Reset Y. + sty.q idx0 ; Clear the first index. + sty.q idx1 ; Clear the second index. + sty.q idx2 ; Clear the third index. + sty b ; Clear the isop flag. +; lda (ptr), y ; Get a character from the line. +; pha #1 ; Preserve the character. +; jsr isdigit ; Is this character a digit? +; pla #1 ; Get the character back. +@getline: + lda #2 ; Get the third byte, of the line table address. + lsl #$10 ; Shift it by 2 bytes. + ldb #1 ; Set the second pointer + lda.w ltok ; to the last line. + jsr set_ptr ; + lda.w (ptr2) ; Get the next line. + jsr set_ptr ; Set the second pointer to the next line. + sta.w ctok ; Make it the current line. + and #0 ; Reset A. +@loop: + ldy.w idx0 ; Get the string index. + lda (ptr), y ; Get a character from the line. + jsr isdelm ; Get the delimiter. + cmp #1 ; Are we at the end of the line? + beq @end ; Yes, so we're done. +@spaces: + ldy.w idx0 ; Get the string index. + lda (ptr), y ; Get a character from the line. + pha #1 ; Preserve the character. + jsr isdelm ; Get the delimiter. + and #$10 ; Is this character, a space, or tab? + pla #1 ; Get the character back. + beq @isstart ; No, so check for the start of the line. + inc.w idx0 ; Yes, so increment the string index. + cmp #' ' ; Is this character, a space? + beq @incs ; Yes, so increment the starting space count. + cmp #'\t' ; No, but is it a tab? + beq @inct ; Yes, so increment the starting tab count. + jmp @spaces ; No, so Keep looping. +@incs: + inc idx1 ; Increment the space count. + jmp @spaces ; Keep looping. +@inct: + inc idx1+1 ; Increment the tab count. + jmp @spaces ; Keep looping. +@isstart: + pha #2 ; Preserve the character. + lda.w idx1 ; Was there any whitespace? + pla #2 ; Get the character back. + beq @switch ; No, so start lexing. + cpb #1 ; Yes, and are we at the start of the line? + bne @switch ; No, so start lexing. +@whtspace: + ldy #2 ; Yes, so set the line index to the starting whitespace counters. + lda.w idx1 ; Get both indecies. + sta.w (ptr2), y ; Save them in the line. + and #0 ; Reset A. + sta.w idx1 ; Reset the second index. + deb ; Set the isstart flag to false. +@switch: + ldy.w idx0 ; Get the string index. + lda (ptr), y ; Get the character. + jsr get_ptok ; Get the pre-token. + jsr parse_ptok ; Parse the pre-token. +; beq @end ; We got to the end of the string. + jmp @loop ; Keep looping. +@end: + ply #2 ; Get the screen buffer index back. + rts ; End of lex. + + +parse_ptok: + pha #1 ; Preserve the pre-token. + ldb #2 ; Set the third pointer + lda.w #swtab ; to the start of the jump table. + jsr set_ptr ; + and #0 ; Reset A. + pla #1 ; Get the pre-token back. + phy #2 ; Preserve Y. + lsl #1 ; Multiply the pre-token by two, to get the jump index. + tay ; Get the index of the jump table. + lda.w (ptr3), y ; Get the address to jump to. + jsr set_ptr ; Set the third pointer to the case address. + and #0 ; Reset A. + tab ; Reset B. + ply #2 ; Get Y back. + jmp (ptr3) ; Jump to the case label. +ptok_dot: + ldb #1 ; Make init_lex increment the string index. + jsr init_lex ; Initialize the lexeme buffer for copying. + ldb #$11 ; Set the delimiter comparison value to whitespace. + jsr delmcpy ; Copy the string, to the lexeme buffer, until delimiter. +@isop: + lda b ; Has the isop flag been set? + beq @dir ; No, so check for a directive. +@rs: + lda #TOK_RS ; Yes, so set the lexeme type to TOK_RS. + sta lex_type ; + ldy.w idx1 ; Get the lexeme index. + dey ; Decrement the lexeme index. + lda (ptr3), y ; Get the suffix character. + jsr get_rs ; Get the register size. + jmp @end ; We are done. +@dir: + lda #TOK_DIR ; Set the lexeme type to TOK_DIR. + sta lex_type ; + ldb #0 ; Make the lexeme buffer, the first pointer. + stb.q idx1 ; Reset the first index. + jsr set_lexptr ; Set up the lexeme buffer. +@dir_loop: + lda.w #dir ; Get pointer to the start of the directive table. + clc ; Prepare for a non carrying add. + adc.w idx2 ; Offset the pointer, by the length of the previous string. + pha #8 ; Preserve the directive string pointer. + jsr strcasecmp ; Is the lexeme buffer, the same as the directive string? + pla #8 ; Get the directive string pointer back. + beq @found ; Yes, so create a new token. + ldb idx1 ; No, so Get the directive ID. + cpb #6 ; Have we reached the end of the directive table? + beq @end ; Yes, so we're done. + inc idx1 ; No, so increment the directive ID. +@getlen: + jsr strlen ; Get the string's length. + inx ; Add one to the length. + txa ; Place it in the accumulator. + clc ; Prepare for a non carrying add. + adc.w idx2 ; Add the string offset to the current length + sta.w idx2 ; Save the offset in the third index. + jmp @dir_loop ; Keep looping. +@found: + nop ; +@end: + jsr make_tok ; Create the token. + jsr set_cmdbuf ; Set the first pointer to the command buffer. + rts ; End of parse_ptok. +ptok_at: + rts ; End of parse_ptok. +ptok_col: + rts ; End of parse_ptok. +ptok_equ: + rts ; End of parse_ptok. +ptok_plus: + rts ; End of parse_ptok. +ptok_min: + rts ; End of parse_ptok. +ptok_gt: + rts ; End of parse_ptok. +ptok_lt: + rts ; End of parse_ptok. +ptok_lbrk: + rts ; End of parse_ptok. +ptok_rbrk: + rts ; End of parse_ptok. +ptok_com: + rts ; End of parse_ptok. +ptok_xr: + rts ; End of parse_ptok. +ptok_yr: + rts ; End of parse_ptok. +ptok_dqu: + ldb #1 ; Make init_lex increment the string index. + jsr init_lex ; Initialize the lexeme buffer for copying. + ldb #4 ; Set the delimiter comparison value to a double quote. + jsr delmcpy ; Copy the string, to the lexeme buffer, until delimiter. +@term: + rts ; End of parse_ptok. +ptok_squ: + rts ; End of parse_ptok. +ptok_hash: + rts ; End of parse_ptok. +ptok_scol: + rts ; End of parse_ptok. +ptok_dolr: + rts ; End of parse_ptok. +ptok_prcn: + rts ; End of parse_ptok. +ptok_num: + rts ; End of parse_ptok. +ptok_alph: + ldb #0 ; Do not let init_lex increment the string index. + jsr init_lex ; Initialize the lexeme buffer for copying. + ldb #1 ; Stop at any possible delimiter, except whitespace. + tba ; Use isdelm2 for the comparison. + jsr delmcpy ; Copy the string, to the lexeme buffer, until delimiter. + lda #0 ; Reset A. + sta b ; Clear the isop flag. +@isop: + ldb #0 ; Make the lexeme buffer, the first pointer. + stb.q idx1 ; Reset the first index. + jsr set_lexptr ; Set up the lexeme buffer. +@isop_loop: + lda.w #mne ; Get pointer to the start of the instruction table. + clc ; Prepare for a non carrying add. + adc.w idx2 ; Offset the pointer, by the length of the previous string. + jsr strcasecmp ; Is the lexeme buffer, the same as the mnemonic string? + beq @found ; Yes, so create a new token. + ldb idx1 ; No, so Get the instruction ID. + cpb #OPNUM-1 ; Have we reached the end of the instruction table? + beq @end ; Yes, so we're done. + inc idx1 ; No, so increment the instruction ID. +@offset: + lda #13 ; Get the base size of the instruction table. + clc ; Prepare for a non carrying multiply. + mul idx1 ; Multiply the base offset, by the instruction ID. + sta.w idx2 ; Save the offset in the third index. + jmp @isop_loop ; Keep looping. +@found: + lda #TOK_MNE ; Set the lexeme type to TOK_MNE. + sta lex_type ; + inc b ; Set the isop flag. +@end: + jsr make_tok ; Create the token. + jsr set_cmdbuf ; Set the first pointer to the command buffer. + rts ; End of parse_ptok. +ptok_othr: + rts ; End of parse_ptok. + + +set_lexptr: + lda.d #lexeme ; Set the pointer to the lexeme buffer. + jsr set_ptr ; + and #0 ; Reset A. + tab ; Reset B. + sta.q idx1 ; Reset the second index. + rts ; End of set_lexptr. + + +set_cmdbuf: + ldb #0 ; Set the first pointer + lda.d #cmd_buf ; to the command buffer. + jsr set_ptr ; + and #0 ; Reset A. + tab ; Reset B. + rts ; End of set_cmdbuf. + + +init_lex: + cpb #0 ; Do we need to increment the string index? + beq @init ; No, so skip that step. +@inc_str: + inc.w idx0 ; Yes, so increment the string index. +@init: + lda #0 ; Reset A. + sta.q idx1 ; Reset the second index + sta.q idx2 ; Reset the third index + ldb #2 ; Make the lexeme buffer, the third pointer. + jsr set_lexptr ; Set up the lexeme buffer. + rts ; End of init_lex. + + +delmcpy: + sta a ; Save the delimiter check flag. + stb c ; Save the delimiter comparison value. +@loop: + ldy.w idx0 ; Get the string index. + lda (ptr), y ; Get a character from the line. + pha #1 ; Preserve the character. + lda a ; Are we calling isdelm2? + pla #1 ; Get the character back. + bne @isdelm2 ; Yes, so use isdelm2. + jsr isdelm ; No, so get the delimiter value from isdelm. + and c ; Are both delimiter values, the same? + bne @end ; Yes, so we're done. + jmp @copy ; No, so start copying the character. +@isdelm2: + jsr isdelm2 ; Get the delimiter value from isdelm2. + cmp c ; Are both delimiter values, the same? + beq @end ; Yes, so we're done. +@copy: + lda (ptr), y ; Get a character from the line. + ldy.w idx1 ; Get the lexeme index. + sta (ptr3), y ; Copy the character to the lexeme buffer. + inc.w idx0 ; Increment the string index. + inc.w idx1 ; Increment the lexeme index. + jmp @loop ; Keep looping. +@end: + lda #0 ; Terminate the lexeme buffer. + sta (ptr3), y ; + rts ; End of delmcpy. + + +get_rs: + phb #1 ; Preserve B. + ldb #0 ; Set the isop flag to false. + plb #1 ; Get B back. + jsr tolower ; Convert the character to lowercase. + cmp #'w' ; Is it .w? + beq @r1 ; Yes, so return 1. + cmp #'d' ; No, but was it .d? + beq @r2 ; Yes, so return 2. + cmp #'q' ; No, but was it .d? + beq @r3 ; Yes, so return 3. +@r0: + lda #0 ; Return 0. + rts ; End of get_rs. +@r1: + lda #1 ; Return 1. + rts ; End of get_rs. +@r2: + lda #2 ; Return 2. + rts ; End of get_rs. +@r3: + lda #3 ; Return 3. + rts ; End of get_rs. + + +make_tok: + nop ; +@end: + rts ; End of make_tok. + +; Entry point for utility subroutines. +utils: diff --git a/programs/sub-suite/subasm.s b/programs/sub-suite/subasm.s new file mode 100644 index 0000000..9c6c3f0 --- /dev/null +++ b/programs/sub-suite/subasm.s @@ -0,0 +1,388 @@ +; SuBAsm +; The Sux Bootstrapped Assembler. +; +; by mr b0nk 500 + +MAX_SYM = $800 ; Max symbol size. +OPNUM = 88 ; Instruction count. + +.include "lexer.s" +.include "utils.s" + +.org incl +; String Constants. +asm_name: + .byte "SuBAsm" +asm_ver: + .byte "0.1" + +; Directives. +dir: + .byte "org" + .byte "byte" + .byte "word" + .byte "dword" + .byte "qword" + .byte "include" + +; Short form Commands. +sh_cmds: + .byte "vlahirs" + +; Commands. +cmds: + .byte "viewmem" + .byte "list" + .byte "asm" + .byte "help" + .byte "inst" + .byte "run" + .byte "set" + +; Instruction mnemonics, and opcodes. + +; Legend. +; mne = Mnemonic. +; imm = Immediate data. +; zm = Zero Matrix. +; zmx = Zero Matrix, indexed with X. +; zmy = Zero Matrix, indexed with Y. +; ind = Indirect. +; idx = Indexed Indirect. +; idy = Indirect Indexed. +; abs = Absolute. +; imp = Implied. + +mne: +; mne imm, zm, zmx, zmy, ind, idx, idy, abs, imp + .byte "CPS", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 + .byte "ADC", $01, $06, $FF, $FF, $FF, $FF, $FF, $04, $FF + .byte "AAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $02 + .byte "PHP", $08, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "CPB", $09, $2D, $FF, $FF, $55, $AD, $AC, $2C, $FF + .byte "PHB", $0A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "DEC", $FF, $0D, $FF, $FF, $FF, $FF, $FF, $0C, $E5 + .byte "JMP", $FF, $0E, $FF, $FF, $CE, $FF, $FF, $10, $FF + .byte "SBC", $11, $16, $FF, $FF, $FF, $FF, $FF, $14, $FF + .byte "SAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $12 + .byte "ENT", $18, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "CPY", $19, $3D, $FF, $FF, $85, $FF, $FF, $4C, $FF + .byte "PLB", $1A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "INC", $FF, $1D, $FF, $FF, $FF, $FF, $FF, $1C, $F5 + .byte "JSR", $FF, $1E, $FF, $FF, $BE, $FF, $FF, $20, $FF + .byte "AND", $21, $26, $FF, $FF, $FF, $FF, $FF, $24, $FF + .byte "ABA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $22 + .byte "PLP", $28, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "CPX", $29, $4D, $FF, $FF, $B5, $FF, $FF, $3C, $FF + .byte "PHY", $2A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "BPO", $FF, $2E, $FF, $FF, $FF, $FF, $FF, $30, $FF + .byte "ORA", $31, $36, $FF, $FF, $FF, $FF, $FF, $34, $FF + .byte "OAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $32 + .byte "STT", $38, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "PLY", $3A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "BNG", $FF, $3E, $FF, $FF, $FF, $FF, $FF, $40, $FF + .byte "XOR", $41, $46, $FF, $FF, $FF, $FF, $FF, $44, $FF + .byte "XAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $42 + .byte "PHA", $48, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "PHX", $4A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "BCS", $FF, $4E, $FF, $FF, $FF, $FF, $FF, $50, $FF + .byte "LSL", $51, $56, $FF, $FF, $FF, $FF, $FF, $54, $FF + .byte "LLB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $52 + .byte "CLC", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $58 + .byte "PLX", $5A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "BCC", $FF, $5E, $FF, $FF, $FF, $FF, $FF, $60, $FF + .byte "LSR", $61, $66, $FF, $FF, $FF, $FF, $FF, $64, $FF + .byte "LRB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $62 + .byte "PLA", $68, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "TAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $6A + .byte "BEQ", $FF, $6E, $FF, $FF, $FF, $FF, $FF, $70, $FF + .byte "ROL", $71, $76, $FF, $FF, $FF, $FF, $FF, $74, $FF + .byte "RLB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $72 + .byte "SEC", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $78 + .byte "TBA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $7A + .byte "BNE", $FF, $7E, $FF, $FF, $FF, $FF, $FF, $80, $FF + .byte "ROR", $81, $86, $FF, $FF, $FF, $FF, $FF, $84, $FF + .byte "RRB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $82 + .byte "DEY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $88 + .byte "TAY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $8A + .byte "BVS", $FF, $8E, $FF, $FF, $FF, $FF, $FF, $90, $FF + .byte "MUL", $91, $96, $FF, $FF, $FF, $FF, $FF, $94, $FF + .byte "MAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $92 + .byte "CLI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $98 + .byte "TYA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $9A + .byte "BVC", $FF, $9E, $FF, $FF, $FF, $FF, $FF, $A0, $FF + .byte "DIV", $A1, $A6, $FF, $FF, $FF, $FF, $FF, $A4, $FF + .byte "DAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $A2 + .byte "INY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $A8 + .byte "TAX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $AA + .byte "RTS", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $AE + .byte "CMP", $B1, $B6, $FF, $FF, $25, $7D, $7C, $B4, $FF + .byte "CAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $B2 + .byte "SEI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $B8 + .byte "LDX", $B9, $BD, $FF, $C9, $95, $FF, $FF, $BC, $FF + .byte "TXA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $BA + .byte "RTI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C0 + .byte "LDA", $C1, $C6, $79, $39, $05, $5D, $5C, $C4, $FF + .byte "DEX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C5 + .byte "CLV", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C8 + .byte "TYX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $CA + .byte "STA", $FF, $CD, $89, $49, $15, $6D, $6C, $CC, $FF + .byte "TSX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D0 + .byte "LDB", $D1, $D6, $99, $59, $35, $8D, $8C, $D4, $FF + .byte "INX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D5 + .byte "WAI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D8 + .byte "TXY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $DA + .byte "STB", $FF, $DD, $A9, $69, $45, $9D, $9C, $DC, $FF + .byte "TXS", $E0, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + .byte "LDY", $E1, $E6, $E9, $FF, $65, $FF, $FF, $E4, $FF + .byte "BRK", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $E8 + .byte "NOP", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $EA + .byte "STY", $FF, $ED, $F9, $FF, $75, $FF, $FF, $EC, $FF + .byte "DEB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $EE + .byte "ASR", $F1, $F6, $FF, $FF, $FF, $FF, $FF, $F4, $FF + .byte "ARB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $F2 + .byte "STX", $FF, $FD, $FF, $D9, $A5, $FF, $FF, $FC, $FF + .byte "INB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FE + +; Command subroutine table. +cmd_srt: + .word viewmem + .word list + .word asm + .word help + .word inst + .word run + .word set + +; Data entry point for the lexer. +lexer_data: + + +; Token table. +.org $20000 +tokline: + +.org cmd_buf+$400 +; Program Counter. +prg_cnt: + .qword 0 +; Hex digit string buffer. +hex_str: + .qword 0, 0 +; String buffer. +strbuf: + +.org strbuf+$80 +; Subroutine pointer. +sub_ptr: + .word 0 + +; Indecies. +idx0: + .qword 0 +idx1: + .qword 0 +idx2: + .qword 0 +idx3: + .qword 0 + +; Current token line. +ctok: + .word 0 + +; Last token line. +ltok: + .word 0 + +; Lexeme type. +lex_type: + .byte 0 + +; Lexeme string. +lexeme: + +; Symbol table. +.org lexeme+$100 +sym: + +; Fixup table. +; Fixups are unresolved symbols. +.org sym+$8000 +fix: + + +; Start of program code. +.org parser +subasm: + ldb #0 ; Set the first pointer + lda.d #cmd_buf ; to the command buffer. + jsr set_ptr ; + tba ; Reset A. + tax ; Reset X. + jsr chk_shcmd ; Did we get a shortend command? + bne @cmd ; Yes, so skip everything else. + jsr chk_cmd ; No, but did we get a full command? + bne @cmd ; Yes, so skip everything else. + jsr lex ; No, so start lexing this line. + jmp @end ; We are done. +@cmd: + ldb #1 ; Set the second pointer + lda.d #cmd_srt ; to the command subroutine table. + jsr set_ptr ; + deb ; Reset B. + tba ; Reset A. + lda f ; Get the command ID. + cmp #8 ; Is the command ID greater than the command count? + bcs @end ; Yes, so we're done. + lsl #1 ; No, so multiply the command ID by two. + phy #2 ; Preserve the screen buffer position. + tay ; Set the index to the offset that we just calculated. + lda.w (ptr2), y ; Get the command subroutine, from the command subroutine table. + ply #2 ; Get back the screen buffer position. + ldb #2 ; Save it in the third pointer. + jsr set_ptr ; + ldb #0 ; Reset B. + jsr (ptr3) ; Run the command's subroutine. +@end: + rts ; End of subasm. + +chk_shcmd: + tba ; Reset A. + inb ; Set the second pointer + lda.w #sh_cmds ; to the shortend command table. + jsr set_ptr ; + deb ; Reset B. + tba ; Reset A. + phy #2 ; Preserve the screen buffer position. + txy ; Set our index to zero. + lda (ptr), y ; Is there nothing in the command buffer? + beq @false ; Yes, so return that we failed. + cmp #' ' ; No, but is this character, a space? + beq @false ; Yes, so return that we failed. + jsr tolower ; No, so convert it to lowercase. +@loop: + ldb (ptr2), y ; Are we at the end of the table? + beq @false ; Yes, so return that we failed. + cab ; No, so did the character match? + beq @found ; Yes, so check if there are any arguments. + iny ; No, so check the next command. + jmp @loop ; Keep looping. +@found: + sty f ; Save the command ID. + ldy #1 ; Check the next character in the command buffer. + lda (ptr), y ; Is this the end of the buffer? + beq @true ; Yes, so return that we succeded. + cmp #' ' ; No, but is this a space? + beq @true ; Yes, so return that we succeded. + jmp @false ; No, so return that we failed. +@true: + lda #1 ; Return true. + jmp @end ; We are done. +@false: + ldb #0 ; Reset B. + tba ; Return false. + tax ; Reset X. +@end: + ply #2 ; Get back the screen buffer position. + rts ; End of chk_shcmd. + + +chk_cmd: + tba ; Reset A. + tax ; Reset X. + sta.q idx0 ; Reset the first index. + sta.q idx1 ; Reset the second index. +@loop: + lda.w #cmds ; Get pointer to the start of the command table. + clc ; Prepare for a non carrying add. + adc.w idx0 ; Offset the pointer, by the length of the previous string. + pha #8 ; Preserve the command string pointer. + jsr strcasecmp ; Is the command buffer, the same as the command string? + pla #8 ; Get the command string pointer back. + beq @true ; Yes, so return true. + ldb idx1 ; No, so Get the command ID. + cpb #7 ; Have we reached the end of the command table? + beq @false ; Yes, so return false. + inc idx1 ; No, so increment the command ID. +@getlen: + jsr strlen ; Get the string's length. + inx ; Add one to the length. + txa ; Place it in the accumulator. + clc ; Prepare for a non carrying add. + adc.w idx0 ; Add the string offset to the current length + sta.w idx0 ; Save the offset in the first index. + jmp @loop ; Keep looping. +@true: + ldb idx1 ; Get the command ID. + stb f ; Return the command ID. + ldb #1 ; Return true. + jmp @end ; We are done. +@false: + ldb #0 ; Return false. +@end: + rts ; End of chk_cmd. + +viewmem: + lda.q prg_cnt ; Get the program counter. + sta.q idx0 ; Save the address in the first index. + and #$F0 ; Clear the first four bits of the address. + sta idx0 ; Overwrite the first byte, with the masked byte. + lda #19 ; Move the cursor to the right, by 19 columns. + sta scr_col ; + jsr update_pos ; + jsr print_lo ; Print the low nibble offsets. + ldx #0 ; Reset X. + ldb #0 ; Reset B. + stb idx1 ; Reset the byte count. +@loop: + lda #'\n' ; Print a newline. + jsr print_char ; + jsr print_hi ; Place the address in the string buffer. + jsr print_chunk ; Place the next 16 bytes in the string buffer. + lda.d #strbuf ; Print the string buffer. + jsr print_str ; + inc idx1 ; Increment the chunk count. + ldb idx1 ; Get the chunk count. + cpb #$10 ; Did we print 16 chunks? + beq @end ; Yes, so we're done. + lda.q idx0 ; No, so get the address index. + clc ; Prepare for a non carrying add. + adc #$10 ; Add 16 to the address. + sta.q idx0 ; Put it back into the address. + and #0 ; Reset A. + jmp @loop ; Keep looping. +@end: + lda #'\n' ; Print a newline. + jsr print_char ; + and #0 ; Reset A. + rts ; End of viewmem. + + +list: + nop ; +@end: + rts ; End of list. +asm: + nop ; +@end: + rts ; End of asm. +help: + nop ; +@end: + rts ; End of help. +inst: + nop ; +@end: + rts ; End of inst. +run: + nop ; +@end: + rts ; End of run. +set: + nop ; +@end: + rts ; End of set. + +; Entry point for utility subroutines. +lexer: diff --git a/programs/sub-suite/subeditor.s b/programs/sub-suite/subeditor.s new file mode 100644 index 0000000..1768d62 --- /dev/null +++ b/programs/sub-suite/subeditor.s @@ -0,0 +1,1234 @@ +; SuBEditor. +; +; Writen in Sux assembly by +; mr b0nk 500 + +; I/O constants. +status = $100 ; Keyboard status. +scr = $101 ; Character that is to be printed. +kbd = $102 ; Character from the Keyboard. +step = $110 ; Enables clock stepping, when set. + +; Screen constants. +maxrow = 23 ; Screen's row count. +maxcol = 79 ; Screen's column count. + +; Include SuBAsm. +.include "subasm.s" + +.org $A000 +; String Literals/Constants. +tok: + .byte "dab" +msg: + .byte "oof, you divided a, and b on me.\n" + +ed_name: + .byte "SuBEditor" +ed_ver: + .byte "1" +ed_sver: + .byte ".0.0" + +ver_str: + .byte ", version " +made: + .byte "Created by, " + +author: + .byte "mr b0nk 500" + +string2: + .byte "You typed, " + +; Linewrap bitmask table. +bits: + .byte $80, $40, $20, $10, $08, $04, $02, $01 + +; This label is for any included files. +incl: + +; Linewrap table. +.org $30000 +bitabl: + .qword 0 + .qword 0 + +; SCreen buffer. +.org bitabl+$1000 +buffer: + +; Command buffer. +.org buffer+$2000 +cmd_buf: + + +; Screen variables. +.org 0 +scr_row: + .byte 0 +scr_col: + .byte 0 +scr_trow: + .byte 0 +scr_tcol: + .byte 0 +scr_ptr: + .word 0 +scr_ptr2: + .word 0 +scr_ptr3: + .word 0 + +; Pseudo registers. +a: + .byte 0 +b: + .byte 0 +c: + .byte 0 +d: + .byte 0 +e: + .byte 0 +f: + .byte 0 +g: + .byte 0 +; This pseudo register is always zero. +zero: + .qword 0 +; End of pseudo registers. + +end: + .qword 0 +bitmask: + .byte 0 +scr_str: + .byte 0 +scr_end: + .byte 0 +wrapped: + .byte 0 + +; Pointers +ptr: + .qword 0 +ptr2: + .qword 0 +ptr3: + .qword 0 + +; Main program +.org $8000 +reset: + cps ; Reset the processor status register. + ldx.w #$FFFF ; Reset the stack pointer. + txs ; + ldy #0 ; Reset the Y register. + sty end ; + tyx ; Reset the X register. + lda #maxrow ; Set the end of the screen to the screen's max row count. + sta scr_end ; + tya ; Reset the Accumulator. + sta scr_str ; Set the start of the screen back to zero. + sta.q bitabl ; Reset the first half of the linewrap table. + sta.q bitabl+8 ; Reset the second half of the linewrap table. + inc end ; + lda.w #$1FFF ; Set the clear count to $1FFF. + sta.w scr_ptr ; + lda.d #buffer ; Set the array to be cleared to the screen buffer. + jsr clr_arr ; Clear the screen buffer. + jsr pnt_strt ; Print the starting message. + jmp start ; Goto the start of the main program. + +clr_arr: + phb #1 ; Preserve whatever was in B. + ldb #0 ; Clear B. + jsr set_ptr ; Set the first pointer to the parameter. + adc #8 ; Set the second pointer to the parameter, plus eight. + inb ; Tell set_ptr to set the second pointer. + jsr set_ptr ; + deb ; Set B back to zero. + tba ; +@loop: + cpy.w scr_ptr ; Did we clear all of the array? + bcs @end ; Yes, so we're done. + sta.q (ptr), y ; No, so clear eight bytes. + sta.q (ptr2), y ; Clear eight more bytes. + tya ; Copy the array index. + adc #$10 ; Increment the index by 16. + tay ; Update the index. + tba ; Reset the Accumulator. + sta.q (ptr), y ; Do this one more time, to clear 32 bytes. + sta.q (ptr2), y ; + tya ; + adc #$10 ; + tay ; + tba ; + jmp @loop ; Keep looping. +@end: + ldy.w zero ; Set the index back to zero. + plb #1 ; Get whatever was in the B register, back. + rts ; End of clr_arr. + +pnt_strt: + lda.w #ed_name ; Print the name of the editor. + jsr print_str ; + lda.w #ver_str ; Print the version text. + jsr print_str ; + lda.w #ed_ver ; Print the version number. + jsr print_str ; + lda.w #ed_sver ; Print the sub version number. + jsr print_str ; + lda #'\n' ; Print a newline. + jsr print_char ; + lda.w #made ; Print the "Created by" text. + jsr print_str ; + lda.w #author ; Print the name of the author. + jsr print_str ; + lda #'\n' ; Print a newline. + jsr print_char ; + rts ; End of pnt_strt. + +start: + lda #0 ; TODO: Update this for the Super VIA. + sta status ; Clear the control register of the I/O adapter. + tax ; Reset X. + phy #2 ; Save the cursor index for later. + tay ; Reset the cursor index. + lda.w #$3FF ; Set the clear count to $3FF. + sta.w scr_ptr ; + lda.d #cmd_buf ; Set the array to be cleared to the command buffer. + jsr clr_arr ; Clear the command buffer. + ply #2 ; Get back the cursor index. + and #0 ; Reset the Accumulator. + sta end ; + jmp read ; Start reading the keyboard. + +read: + lda #0 ; Reset the Accumulator. + sta end ; Disable the dummy flag. + inc end ; Enable the dummy flag. + lda status ; Did we get a key? + beq read ; No, so try again. + jsr getchar ; Yes, and was it a newline? + beq parse ; Yes, so start parsing the line. + jmp read ; No, so keep looping. + +print_str: + ldx #0 ; Reset X. + sta.q end ; Save the parameter. +@reset: + lda.q end ; Get the parameter. + ldb #0 ; Clear the B register. + jsr set_ptr ; Set the first pointer to the parameter. + tba ; Clear the Accumulator. +@loop: + ldb #1 ; Enable replace mode. + stb b ; + lda.q ptr ; Get the first pointer. + cmp.q end ; Did the pointer change? + bne @reset ; Yes, so set it back. + and #0 ; No, reset the accumulator. + phy #2 ; Save the cursor index. + txy ; Copy the string index into Y. + lda (ptr), y ; Are we at the end of the string? + ply #2 ; Get the cursor index back. + beq @end ; Yes, so we're done. + inx ; No, so increment the string index. + jsr print_char ; Print the character. + jmp @loop ; Keep looping. +@end: + ldb #0 ; Enable insert mode. + stb b ; + rts ; End of print_str. + +getbit: + clc ; Clear the carry flag. + lda scr_str ; Has the screen been scrolled? + bne getbt0 ; Yes, so add the screen offset to the current line number. + ldx scr_row ; No, so just use the current line number. + jmp getbt1 ; Start getting the bit. +getbt0: + lda scr_row ; Get the current line number. + adc scr_str ; Add the screen offset to it. + tax ; Use it as the wrap index. +getbt1: + pha #1 ; Save the parameter. + ldb #1 ; Make sure that set_ptr sets the second pointer. + lda.d #bitabl ; Set the second pointer to the linewrap table. + jsr set_ptr ; + lsr #$10 ; Clear the Accumulator. + pla #1 ; Get the return byte back. + jsr bitpos ; Get the bit, and byte position. + phy #2 ; Save the screen index. + txy ; Get the byte position. + ldb (ptr2), y ; Get one byte of the wrap table. + ply #2 ; Get the screen index back. + aba ; Mask out the bit of the current line number. + cmp #1 ; Set the carry flag, if true. + jmp bitout ; We are done. + +clrbit: + pha #1 ; Save the parameter. + ldb #1 ; Make sure that set_ptr sets the second pointer. + lda.d #bitabl ; Set the second pointer to the linewrap table. + jsr set_ptr ; + and #0 ; Clear the Accumulator. + pla #1 ; Get the return byte back. + jsr bitpos ; Get the bit, and byte position. + xor #$FF ; Invert the bitmask. + phy #2 ; Save the screen index. + txy ; Get the byte position. + ldb (ptr2), y ; Get one byte of the wrap table. + aba ; Clear the bit of the current line number. +bitsav: + sta (ptr2), y ; Update the wrap table. + ply #2 ; Get the screen index back. +bitout: + ldx bitmask ; Return the bitmask. + rts ; We are done. + +setbit: + pha #1 ; Save the parameter. + ldb #1 ; Make sure that set_ptr sets the second pointer. + lda.d #bitabl ; Set the second pointer to the linewrap table. + jsr set_ptr ; + and #0 ; Clear the Accumulator. + pla #1 ; Get the return byte back. + jsr bitpos ; Get the bit, and byte position. + phy #2 ; Save the screen index. + txy ; Get the byte position. + ldb (ptr2), y ; Get one byte of the wrap table. + oab ; Set the bit of the current line number. + jmp bitsav ; Save the bit. + +bitpos: + pha #1 ; Save the parameter. + ldb #0 ; Make sure that set_ptr sets the first pointer. + lda.w #bits ; Set the first pointer to the bitmask table. + jsr set_ptr ; + and #0 ; Clear the Accumulator. + pla #1 ; Get the parameter back. + stx bitmask ; Make the line number the bitmask. + txa ; Copy it to the Accumulator. + and #7 ; Get the bit position. + phy #2 ; Save the cursor index. + tay ; Use the bit position as the index. + tax ; Copy it into X. + lda (ptr), y ; Get the bitmask. + ply #2 ; Get back the cursor index. + pha #1 ; Save the bitmask. + lda bitmask ; Get the line number. + lsr #3 ; Get the byte position. + tax ; Copy it into X. + pla #1 ; Get back the bitmask. + rts ; End of bitpos. + +getchar: + lda kbd ; Get the character that was typed from the keyboard. + ldb #0 ; Reset the B register. + stb e ; Set the temporary row position to zero, in case we get a newline. + stb b ; Enable insert mode. + pha #1 ; Save the character. + phy #2 ; Save the cursor index. + cmp #'\n' ; Was the character that was typed, a newline? + bne @print ; No, so just print the character. + jsr cmd_cpy ; Yes, so start copying the line to the command buffer. +@print: + ply #2 ; Get back the cursor index. + pla #1 ; Get back the character. + ldb e ; Is the temporary row position non zero? + bne @row ; Yes, so reset the row positon. +@print1: + jsr print_char ; No, so print the character. + lda a ; Get the return value. + cmp #'\n' ; Is the return value, a newline? + beq @true ; Yes, so return true. + jmp @false ; No, so return false. +@row: + ldb e ; Get the temporary row position. + cpb #maxrow ; Is temporary row position, at, or above the bottom of the screen? + beq @row2 ; Yes, so leave it as is. + bcs @row1 ; No, so set it to the bottom of the screen. + jmp @row2 ; Yes, so leave it as is. +@row1: + ldb #maxrow ; Set the row position to the bottom of the screen. +@row2: + stb scr_row ; Set the row position. + jmp @print1 ; Print the character. +@true: + lda #0 ; Return true. + jmp @end ; We are done. +@false: + lda #1 ; Return false. +@end: + rts ; End of getchar. + + +cmd_cpy: + lda scr_row ; Get the row position. + sta scr_trow ; Save it for later. + jsr findend ; Find the end of the line. + ldb scr_str ; Has the screen been scrolled? + beq @start ; No, so don't subtract the screen's starting point from the line number. +@offset: + sec ; Yes, so make sure that we don't subtract by the starting point, plus one. + sbc scr_str ; Offset the row position, back by the screen's starting point. + clc ; Clear the carry flag, so that nothing odd occurs. +@start: + sta scr_row ; Set the row position to the end of the line. + sta e ; Save it into the temporary row posiition. + jsr findst ; Find the start of the line. + clc ; Clear the carry flag. + lda scr_row ; Get the row position. + adc scr_str ; Add it with the screen's starting row. + mul #maxcol+1 ; Multiply it with the width of the screen, plus one. + tay ; Place it into the index. + ldx.w #0 ; Reset the X register. + ldb #0 ; Make sure that set_ptr sets the first pointer. + lda.d #buffer ; Set the first pointer to the start of the screen buffer. + jsr set_ptr ; + inb ; Make sure that set_ptr sets the second pointer. + lda.d #cmd_buf ; Set the second pointer to the start of the command buffer. + jsr set_ptr ; + deb ; Set B back to zero. + tba ; Set the accumulator to zero. +@loop: + ldb #0 ; Reset the B register. + lda.q (ptr), y ; Get eight bytes from the current line. +@loop1: + phy #2 ; Save the screen index. + txy ; Get the command buffer index. + sta (ptr2), y ; Copy one byte from the screen buffer, to the command buffer. + inx ; Increment the command buffer index. + ply #2 ; Get back the screen index. + cpx.w #$3FF ; Are we at the end of the command buffer? + bcs @end ; Yes, so we're done. + iny ; No, so increment the screen index. + inb ; Increment the byte count. + lsr #8 ; Shift in the next byte. + stb g ; Save the byte count. + tab ; Save the string buffer. + and #$FF ; Is this byte of the buffer, a null terminator? + beq @end1 ; Yes, so we're done. + tba ; No so get back the string buffer. + ldb g ; Get back the byte count. + cpb #7 ; Did we shift in eight bytes? + beq @loop ; Yes, so get eight more bytes. + jmp @loop1 ; No, so keep shifting in more bytes. +@end: + ldb #0 ; Reset B. + phy #2 ; Save the screen index. + txy ; Get the command buffer index. + stb (ptr2), y ; Terminate the command buffer. + ply #2 ; Get back the screen index. +@end1: + tab ; The B register is zero, so clear the Accumulator. + rts ; End of cmd_cpy. + + +findst: + lda #0 ; Reset A. +@loop: + pha #1 ; Save the current line number. + jsr getbit ; Is this the start of the line? + pla #1 ; Get the current line number back. + bcc @end ; Yes, so we're done. + inc ; No, so check the next physical line. + dec scr_row ; Are we at the top of the screen? + bpo @loop ; No, so keep looping. + dec ; Yes, so move back one line. + inc scr_row ; Put the row postiion back to zero. +@end: + cmp #0 ; Update all the flags. + rts ; End of findst. + + +fndend: + phb #1 ; Save the contents of the B register. + ldb #0 ; Make sure that set_ptr sets the first pointer. + lda.d #buffer ; Set the first pointer to the start of the screen buffer. + jsr set_ptr ; + tba ; Set the Accumulator to zero. + plb #1 ; Restore the contents of the B register. + phy #2 ; +@loop: + lda (ptr), y ; Are we at the end of the string? + beq @end ; Yes, so we're done. + iny ; No, so increment the cursor index. + jmp @loop ; Keep looping. +@end: + sty.w scr_ptr3 ; + ply #2 ; + rts ; End of fndend. + +findend: + jsr fndend ; + lda.w scr_ptr3 ; + div #maxcol+1 ; + rts ; + +parse: + lda #0 ; + tax ; + jsr subasm ; + jmp start ; + +print_char: + sta a ; Save the typed character for now. + ldb #2 ; Make sure that set_ptr sets the third pointer. + lda.d #buffer ; Set the third pointer to the start of the screen buffer. + jsr set_ptr ; + ldb #0 ; Set B to zero. + tba ; Set the Accumulator to zero. + lda a ; Get back the character. + cmp #$1B ; Did the user type an escape character? + beq esc ; Yes, so go check the escape code. + cmp #'\n' ; No, but did the user type a newline? + beq nl ; Yes, so handle the newline. + cmp #$C ; No, but did the user type Ctrl+L? + beq clr_scr ; Yes, so clear the screen. + cmp #19 ; No, but did the user type Ctrl+S? + beq en_step ; Yes, so enable clock/instruction stepping. + cmp #18 ; No, but did the user type Ctrl+R? + beq dis_step ; Yes, so disable clock/instruction stepping. + cmp #'\b' ; No, but did the user type a backspace? + beq bs ; Yes, so handle the backspace. + cmp #$7F ; No, but did they type Delete? + beq bs ; Yes, so treat it as a backspace. +printc: + lda #0 ; No, so start trying to print a character. + sta d ; + lda (ptr3), y ; Are we at the end of the string? + beq @save ; Yes, so just print the character. + lda b ; No, but was the flag set? + bne @save ; Yes, so don't shift the line. + sty.w scr_ptr ; No, so save the cursor index for later. + jsr fndend ; Find the end of the line. + jmp @shift ; Start shifting the line right. +@update: + lda scr_col ; Save the current column position for later. + sta scr_tcol ; +@update1: + jsr findend ; Find the end of the line. + sta e ; Use it for redrawing the line. + sta scr_row ; Set the row position to to the end of the line. + jsr findst ; Find the start of the line. + lda scr_row ; Get the start of the line. +@update2: + sta f ; Set the starting line, to the start of the line. + jsr rdrw_ln ; Redraw the line. + lda scr_trow ; Get the real row position back. + sta scr_row ; + lda scr_tcol ; Get the real column position back. + sta scr_col ; + jsr update_pos ; Update the cursor's position. + dec d ; + jmp @save1 ; +@shift: + ldy.w scr_ptr3 ; + inc scr_ptr3 ; + tyx ; + dey ; + ldb #1 ; + stb d ; + jsr shftln ; + ldb #1 ; + stb d ; + lda a ; + sta (ptr3), y ; store typed character into the input buffer. + lda scr_row ; + sta scr_trow ; + jmp @update ; +@save: + ldb d ; + bne @update ; +@save1: + lda a ; + sta (ptr3), y ; store typed character into the input buffer. +@incr: + inc scr_col ; Increment the cursor's x coordinate. + iny ; +@wrapped: + ldb #1 ; + stb f ; + ldb scr_col ; + cpb #maxcol+1 ; + bcs @scrolled ; +@print: + sta scr ; Echo typed character. + ldb f ; + beq @wrap ; + jmp printc_end ; +@scrolled: + ldb scr_row ; + cpb #maxrow ; + bcs @scroll ; +@wrapped2: + ldb #0 ; + stb f ; + jmp @print ; +@scroll: + sta scr ; Echo typed character. + clc ; + lda #1 ; + sta wrapped ; + jsr scrl_down ; +@wrap: + ldb #0 + stb scr_col ; + ldb scr_row ; + cpb #maxrow ; + bcs @wrap2 ; +@wrap1: + inc scr_row ; +@wrap2: + phx #2 ; + clc ; + lda scr_row ; + adc scr_str ; + tax ; + jsr setbit ; + plx #2 ; + jsr update_pos ; +printc_end: + rts ; + +nl: + lda #0 ; Reset A. + ldb (ptr3), y ; Is this character not a null terminator? + bne @scroll ; Yes, so don't overwrite it. + sta (ptr3), y ; No, so overwrite it. +@scroll: + sta scr_col ; Move the cursor to the start of the next line. + lda scr_row ; Get the row position. + cmp #maxrow ; Are we at the bottom of the screen? + bcc @incr ; No, so move down one line. + jsr scrl_down ; Yes, so scroll down one line. + jmp @end ; We are done. +@incr: + inc scr_row ; Move the cursor down by one line. + jsr update_pos ; Update the cursor's position. +@end: + lda #'\n' ; Print the newline. + sta a ; + jmp printc_end ; + +clr_scr: + lda #maxrow ; + sta scr_end ; + lda #0 ; + sta scr_str ; + sta.q bitabl ; + sta.q bitabl+8 ; + tay ; + lda.w #$1FFF ; Set the clear count to $1FFF. + sta.w scr_ptr ; + lda.d #buffer ; Set the array to be cleared to the screen buffer. + jsr clr_arr ; Clear the screen buffer. + tay ; + lda.w #$3FF ; Set the clear count to $3FF. + sta.w scr_ptr ; + lda.d #cmd_buf ; Set the array to be cleared to the command buffer. + jsr clr_arr ; Clear the screen buffer. + sta scr_col ; + sta scr_row ; + jsr update_pos ; + lda #$C ; + sta scr ; + jmp printc_end ; + +en_step: + lda step ; + beq step_en ; + jmp printc_end ; +step_en: + lda #1 ; + sta step ; + jmp printc_end ; + +dis_step: + lda step ; + bne step_dis ; + jmp printc_end ; +step_dis: + lda #0 ; + sta step ; + jmp printc_end ; + +back: + ldb #0 ; Reset B, and some flags. + stb e ; + stb f ; + lda scr_row ; Save the current row position for later. + sta scr_trow ; + jsr findend ; Find the end of the line. + sta scr_row ; Set our row position to the end of the line. +@find_st: + jsr findst ; Does this line take up more than one real line? + beq @shift ; No, so skip updating any other lines. + bcs @update ; Yes, so update the other lines. + lda scr_trow ; Get the real row position back. + sta scr_row ; +@shift: + dey ; Decrement the buffer's offset. + lda #0 ; Place a null terminator + sta (ptr3), y ; into the buffer. + tyx ; Copy the current cursor index to X. + iny ; Increment cursor index. + ldb #0 ; Set shifting direction to left. + stb d ; + jsr shftln ; Shift line back by one character. + lda #$7F ; Print a backspace to the screen. + sta scr ; + lda e ; Are we updating more than one line? + beq @load ; No, so skip to the next step. +@find_end: + jsr findend ; Yes, so find the end of the line. + sta e ; Set the end parameter to it. + lda scr_col ; Save the current column position for now. + sta scr_tcol ; + jsr rdrw_ln ; Start redrawing the line. + lda scr_tcol ; Get the real column position back. + sta scr_col ; +@load: + lda scr_trow ; Get the real row position back. + sta scr_row ; + dec scr_col ; Move the cursor back by one column, + jsr update_pos ; and update it's position. + jmp printc_end ; We are done. +@update: + lda scr_row ; Set the line to start redrawing, to the start of the line. + sta f ; + inc e ; Set the redraw flag to true. + jmp @shift ; Start shifting the line back. + +bs: + lda scr_col ; Are we at the far left of the screen? + beq @wrap ; Yes, so check for a wrapped line. + jmp back ; No, so add the backspace to the buffer. +@wrap: + jsr getbit ; Is this line, a wrapped line? + bcs @wrap1 ; Yes, so check if the cursor is at the top. + jmp printc_end ; No, so we're done. +@wrap1: + lda scr_row ; Are we at the top of the screen? + beq @wrap2 ; Yes, so check if the screen is at the top of the buffer. + jmp @wrap3 ; No, so start clearing the wrap bit. +@wrap2: + lda scr_str ; Are we at the top of the buffer? + bne @scroll ; Yes, so scroll up. + jmp printc_end ; No, so we're done. +@scroll: + clc ; Clear the carry flag, so that we don't get odd behaviour. + jsr scrl_up ; Scroll up. + inc scr_row ; Move down by one row. +@wrap3: + clc ; Clear the carry flag. + lda scr_row ; Add the cursor's row position, + adc scr_str ; and the screen's starting row. + tax ; Transfer that into X. +@wrap4: + dec scr_row ; Move up by one row. + ldb #maxcol+1 ; Move the cursor to the absolute right of the screen. + stb scr_col ; + jsr update_pos ; Update the cursor's position. + jmp back ; Delete the previous character. + +shftln: + ldb d ; Is the flag not set? + beq @dec_loop ; Yes, so shift, and decrement. + ldb #0 ; Clear the B register. + jmp @inc_loop ; No, so shift, and increment. +@neg: + ldy.w zero ; Set the source poition to 0. + stb (ptr3), y ; Clear the character that is in the source. + jmp @end ; We are done. +@inc_loop: + sty.w scr_ptr2 ; Save the source position for later. + ldy.w scr_ptr ; Get the previous cursor index. + cpy.w scr_ptr2 ; Is the source position, at, or below the cursor index? + beq @inc_loop1 ; Yes, so keep looping. + bcs @end ; No, so we're done. +@inc_loop1: + ldy.w scr_ptr2 ; Get the source position. + lda (ptr3), y ; Get the character from the source position. + phy #2 ; Save the source position for later. + txy ; Set our position to the destination. + sta (ptr3), y ; Place the character from the source position, to the destination position. + ply #2 ; Set our position back to the source. + stb (ptr3), y ; Clear the character that is in the source. + bng @neg ; The source underflowed, so set it back to zero, + dey ; Decrement the source position. + dex ; Decrement the destination position. + jmp @inc_loop ; Keep looping. +@dec_loop: + stx.w scr_ptr2 ; Save the destination position for later. + lda (ptr3), y ; Is the character at the source position, a null terminator? + beq @end3 ; Yes, so we're done. + phy #2 ; No, so save the source position for later. + txy ; Set our position to the destination. + sta (ptr3), y ; Place the character from the source position, to the destination position. + inx ; Increment the destination position. + ply #2 ; Set our position back to the source. + stb (ptr3), y ; Clear the character that is in the source. + iny ; Increment the source position. + jmp @dec_loop ; Keep looping. +@wrap: + tax ; Use the ending line as a parameter for setbit. + jsr setbit ; Set the wrap bit of the ending line. + jmp @end5 ; We are done. +@wrap1: + tax ; Use the ending line as a parameter for clrbit. + jsr clrbit ; Clear the wrap bit of the ending line. + jmp @end5 ; We are done. +@end: + lda (ptr3), y ; Is this character a null terminator? + bne @end1 ; No, so just find the end of the line. + lda #$20 ; Yes, so convert it to a space for now. + sta (ptr3), y ; +@end1: + jsr findend ; Find the ending line. + sta d ; Save ending line for later. + lda (ptr3), y ; Is this character a space? + cmp #$20 ; + bne @end5 ; No, so skip the conversion. + lda #0 ; Yes, so convert it back to zero. + sta (ptr3), y ; +@end2: + lda d ; Get the ending line. + cmp scr_row ; Is the ending line greater than the starting line? + beq @end5 ; No, so we're done. + bcs @wrap ; Yes, so set the wrap bit. + jmp @end5 ; No, so we're done. +@end3: + jsr findend ; Find the ending line. + cpb #0 ; Is the remainder zero? + beq @end4 ; Yes, so check if the ending line is greater than the starting line. + jmp @end5 ; No, so we're done. +@end4: + cmp scr_row ; Is the ending line greater than the starting line? + beq @end5 ; No, so we're done. + bcs @wrap1 ; Yes, so clear the wrap bit. +@end5: + rts ; End of shftln. + +esc: + lda status ; Get the next character. + lda kbd ; + cmp #$1B ; Is this character an escape character? + beq shftesc ; Yes, so check the other set of escape routines. + lda status ; No, so wait for the next character. + beq printc_end ; We have an error, so discard it, and go back to getting user input. + lda kbd ; Get the escape code. + sta c ; Store the escape code, until we need it. + lda #0 ; Set the D pseudo register to zero. + sta d ; + jsr isup ; Check if the user pressed up. + lda d ; Did the user press up? + bne esc_end ; Yes, so we're done. + jsr isdown ; No, so check if the user pressed down. + lda d ; Did the user press down? + bne esc_end ; Yes, so we're done. + lda #0 ; No, so check if the user pressed left. + jsr isleft ; + lda d ; Did the user press left? + bne esc_end ; Yes, so we're done. + jsr isright ; No, so check if the user pressed right. +esc_end: + lda #0 ; Clear the D pseudo register. + sta d ; + jmp printc_end ; We are done. + +shftesc: + lda status ; Skip the '['. + lda kbd ; + lda status ; Wait for the next character. + beq printc_end ; We have an error, so discard it, and go back to getting user input. + lda kbd ; Get the escape code. + sta c ; Store the escape code, until we need it. + lda #0 ; Use the D pseudo register as a skip flag. + sta d ; + jsr isshftup ; Check if the user pressed shift+up. + lda d ; Was it successful? + bne shftesc_end ; Yes, so we're done. + jsr isshftdown ; No, so check if the user pressed shift+down. +shftesc_end: + lda #0 ; Clear the D pseudo register. + sta d ; + jmp printc_end ; We are done. + +isup: + lda c ; Load the escape code into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + bne @end ; No, so we're done. + lda scr_row ; Yes, but is the cursor at the top of the screen? + beq @scroll ; Yes, so check if we need to scroll. +@check2: + lda c ; No, so load the escape code back into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + beq up ; Yes, so move the cursor up. + jmp @end ; No, so we're done. +@scroll: + lda scr_str ; Are we at the top of the screen buffer? + beq @end ; Yes, so we're done. + jsr scrl_up ; No, so scroll up. + lda #1 ; Tell the escape routine that we were successful. + sta d ; +@end: +isup_done: + rts ; End of isup. + +isdown: + lda c ; Load the escape code into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + bne @end ; No, so we're done. + lda scr_row ; Yes, so start checking the y coordinate of the cursor. + cmp #maxrow ; Is the cursor at the bottom of the screen? + beq @scroll ; Yes, so scroll down. + lda c ; No, so load the escape code back into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + beq down ; Yes, so move the cursor down. + jmp @end ; No, so we're done. +@scroll: + lda scr_row ; Save the cursor's row number. + sta scr_trow ; + lda scr_col ; Save the cursor's column number. + sta scr_tcol ; + jsr scrl_down ; Scroll down. + lda scr_trow ; Load the cursor's row number. + sta scr_row ; + lda scr_tcol ; Load the cursor's column number. + sta scr_col ; + lda #1 ; Tell the escape routine that we were successful. + sta d ; +@end: +isdown_done: + rts ; End of isdown. + +isright: + lda c ; Load the escape code into the accumulator. + cmp #'C' ; Did the user press the right arrow key? + bne @end2 ; No, so we're done. + lda scr_col ; Yes, so start checking the x coordinate of the cursor. + cmp #maxcol ; Is the cursor at the far right of the screen? + beq @wrap ; Yes, so check if this is a wrapped line. + jmp right ; No, so move the cursor right, like normal. +@wrap: + inc scr_row ; Move down a row. + jsr getbit ; Is the current line, a wrapped line? + bcs @incr ; Yes, so leave the cursor where it is. + dec scr_row ; No, so move the cursor back up a row. + jmp @end2 ; We are done. +@scroll: + lda scr_str ; Are we at the top of the screen buffer? + beq @end ; Yes, so we're done. + lda #1 ; No, so scroll down. + sta wrapped ; Set the wrapped flag. + jsr scrl_down ; Scroll down. + jmp @end ; We are done. +@incr: + lda #0 ; Set the cursor to the far left of the screen. + sta scr_col ; + lda scr_row ; Get the current row number. + cmp #maxrow ; Are we at the bottom of the screen? + beq @end1 ; No, so we're done. + bcs @scroll ; Yes, so check if we are scrolling down. + jmp @end1 ; No, so we're done. +@end: + dec scr_row ; Move back up a row. +@end1: + jsr update_pos ; Update the cursor position. +@end2: +isright_dne: + lda #0 ; Unset the wrapped flag. + sta wrapped ; + rts ; End of isright. + +isleft: + lda c ; Load the escape code into the accumulator. + cmp #'C' ; Did the user press right? + beq @end1 ; Yes, so we're done + lda scr_col ; No, but is the cursor at the far left of the screen? + beq @wrap ; Yes, so start checking if this is a wrapped line. + lda c ; No, so load the escape code back into the accumulator. + cmp #'D' ; Did the user press the left arrow key? + beq left ; Yes, so move the cursor left. + jmp @end1 ; No, so we're done. +@wrap: + jsr getbit ; Is the current line, a wrapped line? + bcs @decr ; Yes, so wrap back up a line. + jmp @end1 ; No, so we're done. +@decr: + lda scr_row ; Is the cursor at the top of the screen? + beq @decr1 ; Yes, so don't move up a line. + lda #1 ; No, so set the wrapped flag. + sta wrapped ; + dec scr_row ; Move the cursor up one line. +@decr1: + lda #maxcol ; Move the Cursor to the far right of the screen. + sta scr_col ; + lda #1 ; Tell the escape routine that we were successful. + sta d ; + lda scr_row ; Are we at the top of the screen? + beq @scroll ; Yes, so check if we need to scroll. + jmp @end ; No, so we're done. +@scroll: + lda wrapped ; Was the wrapped flag set somewhere else? + bne @end ; Yes so we're done. + lda scr_str ; No, but are we actually at the top of the screen buffer? + beq @end1 ; Yes, so we're done. + jsr scrl_up ; No, so scroll up. + jmp @end1 ; We are done. +@end: + jsr update_pos ; Update the cursor position. +@end1: +isleft_done: + lda #0 ; Unset the wrapped flag. + sta wrapped ; + rts ; End of isleft. + +up: + dec scr_row ; Move the cursor up a line. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + jmp isup_done ; We are done. +down: + inc scr_row ; Move the cursor down a line. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + jmp isdown_done ; We are done. +right: + inc scr_col ; Move the cursor right by one character. + jsr update_pos ; Update it's position. + jmp isright_dne ; We are done. +left: + dec scr_col ; Move the cursor left a character. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + jmp isleft_done ; We are done + +isshftup: + lda c ; Load the escape code back into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + bne shftup_done ; + lda #1 ; + sta d ; + lda scr_str ; + beq shftup_done ; + jmp shftup ; +shftup_done: + rts ; + +isshftdown: + lda c ; Load the escape code back into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + bne shftdn_done ; + lda #1 ; + sta d ; + lda scr_end ; + cmp #71 ; + bcs shftdn_done ; + jmp shftdown ; +shftdn_done: + rts ; + +shftup: + jsr scrl_up ; + lda #1 ; + sta d ; + jmp shftup_done ; + +shftdown: + jsr scrl_down ; + lda #1 ; + sta d ; + jmp shftdn_done ; + +update_pos: + ldb #1 ; Set the F pseudo register to one, to fix some bugs. + stb f ; + clc ; Clear the carry flag. + lda scr_row ; Add the cursor's line number, + adc scr_str ; with the starting line number to get the absolute line number. + tay ; Place it in the Y regster for now. + mul #maxcol+1 ; Multiply the line number by the screen's max column count, plus 1. + clc ; Clear the carry flag. + adc scr_col ; Add the cursor's column number to get the screen index. + tay ; Place the index into the Y register. + tba ; Reset A. + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + jsr getrow ; Start printing the row number to the screen. + jsr getcol ; Start printing the column number to the screen. + lda #'H' ; Print 'H' + sta scr ; to the screen. + rts ; End of update_pos. + +getrow: + lda scr_row ; Get the cursor's y coordinate. + jmp bcd ; Convert it to BCD. +getcol: + lda #';' ; Print ';' + sta scr ; to the screen. + lda scr_col ; Get the cursor's x coordinate. +bcd: + div #10 ; Divide A by 10. + ora #'0' ; Convert it to ascii, and + sta scr ; print to the screen. + tba ; Get the remainder. + ora #'0' ; Convert it to ascii, and + sta scr ; print to the screen. + rts ; End of bcd. + +scrl_down: + inc scr_str ; Increment the starting line of the screen. + inc scr_end ; Increment the ending line of the screen. + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + lda #'T' ; Print 'T' + sta scr ; to the screen, and end the escape sequence. + lda scr_row ; Get the cursor's line number. + pha #1 ; Save it in the stack. + lda wrapped ; Was the wrapped flag set? + beq @save ; Yes, so save the cursor position. +@redraw: + jsr rdrw_row ; No, so redraw this row. + lda wrapped ; Was the wrapped flag set? + beq @load ; Yes, so load the previous cursor position back. + jmp @end ; No, so we're done. +@save: + lda scr_col ; Get the cursor's column number. + pha #1 ; Save it in the stack. + jmp @redraw ; Start redrawing the current row. +@load: + pla #1 ; Get the cursor's previous column number back. + sta scr_col ; +@end: + pla #1 ; Get the cursor's previous line number back. + sta scr_row ; + jsr update_pos ; Update the cursor's position. + lda #0 ; Clear the wrapped flag. + sta wrapped ; +@end1: + rts ; End of scrl_down. + +scrl_up: + dec scr_str ; + dec scr_end ; + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + lda #'S' ; Print 'S' + sta scr ; to the screen, and end the escape sequence. + lda scr_row ; + pha #1 ; + lda scr_col ; + pha #1 ; + lda #0 ; + sta scr_row ; + jsr rdrw_row ; + pla #1 ; + sta scr_col ; + pla #1 ; + sta scr_row ; + jsr update_pos ; +@end: + rts ; + +rdrw_row: + lda #0 ; + sta scr_col ; + jsr update_pos ; +@loop: + lda (ptr3), y ; + beq @incr ; + sta scr ; +@incr: + inc scr_col ; + lda (ptr3), y ; + beq @skip ; +@incr1: + iny ; +@incr2: + lda scr_col ; + cmp #maxcol+1 ; + bcs @end ; + jmp @loop ; +@skip: + lda #' ' ; + sta scr ; to the screen. + jmp @incr1 ; +@end: + lda #0 ; + sta scr_col ; + jsr update_pos ; +@end1: + rts ; + +rdrw_ln: + lda scr_row ; + pha #1 ; + lda f ; + sta scr_row ; + lda scr_col ; + pha #1 ; + jsr update_pos ; +@loop: + lda scr_row ; + cmp e ; + beq @loop1 ; + bcs @end ; +@loop1: + jsr rdrw_row ; +@incr: + inc scr_row ; + jmp @loop ; +@end: + pla #1 ; + sta scr_col ; + pla #1 ; + sta scr_row ; + jsr update_pos ; + lda #0 ; + sta e ; + sta f ; + rts ; + +set_ptr: + cpb #1 ; Are we setting the second pointer? + beq @ptr2 ; Yes, so start setting it. + cpb #2 ; No, but are we setting the third pointer? + beq @ptr3 ; Yes, so start setting it. +@ptr1: + stb.q ptr ; Reset the first pointer. + sta.q ptr ; No, so set the first pointer. + jmp @end ; We are done. +@ptr2: + stb.q ptr2 ; Reset the second pointer. + sta.q ptr2 ; Set the second pointer. + jmp @end ; We are done. +@ptr3: + stb.q ptr3 ; Reset the third pointer. + sta.q ptr3 ; Set the third pointer. +@end: + rts ; End of set_ptr. + +; Entry point for SuBAsm. +parser: + +.org $FFC0 +.qword reset +a +d + diff --git a/programs/sub-suite/utils.s b/programs/sub-suite/utils.s new file mode 100644 index 0000000..580e4da --- /dev/null +++ b/programs/sub-suite/utils.s @@ -0,0 +1,394 @@ +; Utility subroutines for SuBAsm. + +.org util_data +; Hex character table. +hex_char: + .byte "0123456789ABCDEF" + +; Compare, and return table for pre-tokens. +ptok_tab: + .byte ".@:=+-><(),xy\"\'#;$%" +; Compare, and return table for isdelm. +dtab: + .byte "\n,\"\' " +; Compare, and return table for isdelm2. +dtab2: + .byte "),.+<>-=;\n" + +.org utils + +print_hi: + and #0 ; Reset A. + sta idx3 ; Clear the string index. + lda #'$' ; Print the hex delimiter. + jsr charcpy ; + lda.q idx0 ; Get the masked address. + ldx #$10 ; Set digit count to 16. + jsr print_hex ; Print the address. + lda.q hex_str ; Get the lower half of the string. + sta.q strbuf+1 ; Save it in the string buffer. + lda.q hex_str+8 ; Get the upper half of the string. + sta.q strbuf+9 ; Save it in the string buffer. + ldx #$11 ; Add 16 to the index. + stx idx3 ; + lda #':' ; Print a colon. + jsr charcpy ; + lda # ' ' ; Print a space. + jsr charcpy ; + rts ; End of print_hi. + +print_lo: + lda #0 ; Reset A. + sta idx3 ; Clear the string index. +@loop: + ldx #2 ; Set digit count to 2. + pha #1 ; Preserve the nibble offset. + jsr print_hex ; Print the low nibble offset. + lda.w (ptr3) ; Get the two digits. + jsr charcpy ; Copy the first digit. + lsr #8 ; Copy the next digit. + jsr charcpy ; + pla #1 ; Get the nibble offset back. + inc ; Increment the offset. + cmp #$10 ; Are we at the last offset? + bcs @end ; Yes, so we're done. +@loop1: + pha #1 ; No, so preserve the nibble offset. + lda #' ' ; Add a space to the string buffer. + jsr charcpy ; + pla #1 ; Get the nibble offset back. + jmp @loop ; Keep looping. +@end: + inx ; Increment the index by one. + lda #0 ; Null terminate the string buffer. + sta strbuf, x ; + tax ; Reset X. + lda.d #strbuf ; Print the string buffer. + jsr print_str ; + rts ; End of print_lo. + +print_chunk: + ldx #0 ; Reset X. + phy #2 ; Preserve the screen buffer index. + txy ; Copy the byte index to it. +@loop: + and #0 ; Reset A. + ldx #2 ; Set the digit count to 2. + lda (idx0), y ; Get the byte at that address. + jsr print_hex ; Print the byte. + lda.w (ptr3) ; Get the two digits. + jsr charcpy ; Copy the first digit. + lsr #8 ; Copy the next digit. + jsr charcpy ; + iny ; Increment the byte index. + cpy #$10 ; Have we read 16 bytes? + beq @end ; Yes, so we're done. + lda #' ' ; No, so add a soace to the string buffer. + jsr charcpy ; + jmp @loop ; Keep looping. +@end: + ply #2 ; Get the screen buffer index back. + inx ; Increment the index by one. + and #0 ; Null terminate the string. + sta strbuf, x ; + tax ; Reset X. + sta idx3 ; Clear the string index. + rts ; End of print_chunk. + + +print_hex: + pha #8 ; Preserve the hex value. + and #0 ; Reset A. + ldb #1 ; Set the second pointer + lda.w #hex_char ; to the start of hex character table. + jsr set_ptr ; + inb ; Set the third pointer + lda.d #hex_str ; to the end of hex string buffer. + clc ; Do a non carrying add. + adc #$10 ; + jsr set_ptr ; + ldb #0 ; Reset B. + pla #8 ; Get the hex value back. +@loop: + pha #8 ; Preserve the hex value. + and #$F ; Mask the lowest nibble. + phy #2 ; Preserve the screen buffer position. + tay ; Get the index for the hex digit. + lda (ptr2), y ; Get the hex digit. + dec ptr3 ; Decrement the string pointer. + sta (ptr3) ; Save the hex digit character in the string. + ply #2 ; Get back the screen buffer position. + pla #8 ; Get the hex value back. +@isauto: + cpx #1 ; Is the digit count less than one? + bcc @auto ; Yes, so don't decrement the digit count. + dex ; No, but was the digit count zero, when decremented? + beq @end ; Yes, so we're done. + jmp @next ; No, so get the next nibble. +@auto: + ldb #1 ; Enable auto digit count. +@next: + lsr #4 ; Is the next nibble, a zero? + beq @isauto1 ; Yes, so check if auto digit count is enabled. + jmp @loop ; No, so print the next digit. +@isauto1: + cpb #1 ; Is auto digit count enabled? + beq @end ; Yes, so we're done. + jmp @loop ; No, so keep printing more digits. +@end: + rts ; End of print_hex. + + +charcpy: + ldx idx3 ; Get the string index. + sta strbuf, x ; Save it in the string buffer. + inc idx3 ; Increment the string index. + rts ; End of charcpy. + + +strlen: + ldb #1 ; Set the second pointer + jsr set_ptr ; to the passed pointer. + deb ; Reset B. + tba ; Reset A. + tax ; Reset X. + phy #2 ; Preserve Y. + txy ; Reset Y. +@loop: + lda (ptr2), y ; Are we at the end of the string? + beq @end ; Yes, so we're done. + iny ; No, so increment the index. + jmp @loop ; Keep looping. +@end: + tyx ; Return the length in X. + ply #2 ; Get the preserved value back. + rts ; End of strlen. + + +strcmp: + ldb #1 ; Set the second pointer + jsr set_ptr ; to the passed pointer. + deb ; Reset B. + tba ; Reset A. + phy #2 ; Preserve Y. + tay ; Reset Y. +@loop: + ldb #0 ; Set the islong flag to false. + lda (ptr), y ; Are we at the end of the first string? + beq cmpr ; Yes, so check if we're too short, or too long. + ldb #1 ; No, so set the islong flag to true. + cmp (ptr2), y ; Is the character of both strings, the same? + bne cmpr ; No, so check if we're too short, or too long. + iny ; Yes, so increment the index. + jmp @loop ; Keep looping. + +strcasecmp: + ldb #1 ; Set the second pointer + jsr set_ptr ; to the passed pointer. + deb ; Reset B. + tba ; Reset A. + phy #2 ; Preserve Y. + tay ; Reset Y. +@loop: + ldb #0 ; Set the islong flag to false. + lda (ptr), y ; Are we at the end of the first string? + beq cmpr ; Yes, so check if we're too short, or too long. + ldb #1 ; No, so set the islong flag to true. + jsr tolower ; Convert the character of string 1 to lowercase. + phb #1 ; Preserve the islong flag. + pha #1 ; Preserve the converted character. + lda (ptr2), y ; Get the character of the second string. + jsr tolower ; Convert the character of string 2 to lowercase. + tab ; Place it in B. + pla #1 ; Get the character of string 1 back. + cab ; Is the character of both strings, the same? + plb #1 ; Get the islong flag back. + bne cmpr ; No, so check if we're too short, or too long. + iny ; Yes, so increment the index. + jmp @loop ; Keep looping. + +cmpr: + lda (ptr2), y ; Are we at the end of the second string? + beq @islong ; Yes, so check the islong flag. +@isshort: + lda (ptr), y ; No, but are we at the end of the first string? + beq @short ; Yes, so return -1. +@islong: + cpb #1 ; Is the islong flag true? + bne @equ ; No, so return 0. +@long: + lda #1 ; Yes, so return 1. + jmp @end ; We are done. +@equ: + lda #0 ; Return 0. + jmp @end ; We are done. +@short: + lda #$FF ; Return -1. +@end: + ply #2 ; Get the preserved value back. + rts ; End of strcmp. + + +isdigit: + sec ; Prepare for a non carrying subtraction. + sbc #'0' ; Subtract $30 from the passed character. + and #$FF ; Make sure that we have only one byte. + cmp #10 ; Is the subtracted value, less than 10? + bcs @false ; No, so return false. +@true: + lda #1 ; Yes, so return true. + jmp @end ; We are done. +@false: + lda #0 ; Return false. +@end: + rts ; End of isdigit. + +isxdigit: + pha #1 ; Preserve the character. + jsr isdigit ; Is this character, a decimal digit? + pla #1 ; Get the character back. + bne @true ; Yes, so return true. +@alpha: + sec ; No, so prepare for a non carrying subtract. + ora #$20 ; Convert it to lowercase. + sbc #'a' ; Subtract $61 from the character. + and #$FF ; Make sure that we have only one byte. + cmp #6 ; Is the subtracted value, less than 6? + bcs @false ; No, so return false. +@true: + lda #1 ; Yes, so return true. + jmp @end ; We are done. +@false: + lda #0 ; Return false. +@end: + rts ; End of isxdigit. + + +isupper: + sec ; Prepare for a non carrying subtraction. + sbc #'A' ; Subtract $41 from the passed character. + jmp isletter ; Check if it's less than 26. +islower: + sec ; Prepare for a non carrying subtraction. + sbc #'a' ; Subtract $61 from the passed character. +isletter: + and #$FF ; Make sure that we have only one byte. + cmp #26 ; Is the subtracted value, less than 26? + bcs @false ; No, so return false. +@true: + lda #1 ; Yes, so return true. + jmp @end ; We are done. +@false: + lda #0 ; Return false. +@end: + rts ; End of isletter. + + +tolower: + pha #1 ; Preserve the character. + jsr isupper ; Is this character, an uppercase character? + pla #1 ; Get the character back. + beq @end ; No, so we're done. +@lower: + ora #$20 ; Yes, so convert it to lowercase. +@end: + rts ; End of tolower. + + +toupper: + pha #1 ; Preserve the character. + jsr islower ; Is this character, a lowercase character? + pla #1 ; Get the character back. + beq @end ; No, so we're done. +@upper: + and #$5F ; Yes, so convert it to uppercase. +@end: + rts ; End of toupper. + + +isdelm2: + ldx #0 ; Reset X. +@loop: + ldb dtab2, x ; Get the compare value. + beq @other ; We hit the end of the table, so check for the others. + cab ; Are they the same? + beq @r1 ; Yes, so return 1. + inx ; No, so increment the table index. + jmp @loop ; Keep looping. +@other: + ldx #0 ; Reset X. + cmp #0 ; Is this a null terminator? + beq @r1 ; Yes, so return 1. + cmp #'\t' ; No, but is it a tab? + beq @r2 ; Yes, so return 2. + cmp #' ' ; No, but is it a space? + beq @r2 ; Yes, so also return 2. +@r0: + lda #0 ; Return 0. + rts ; End of isdelm2. +@r1: + ldx #0 ; Reset X. + lda #1 ; Return 1. + rts ; End of isdelm2. +@r2: + lda #2 ; Return 2. + rts ; End of isdelm2. + + +isdelm: + ldx #0 ; Reset X. + stx a ; Reset the shift value. +@loop: + ldb dtab, x ; Get the compare value. + beq @other ; We hit the end of the table, so check for the others. + cab ; Are they the same? + beq @rshft ; Yes, so return 1 << index. + inx ; No, so increment the table index. + jmp @loop ; Keep looping. +@other: + ldx #0 ; Reset X. + cmp #0 ; Is this a null terminator? + beq @rshft ; Yes, so return 1. + ldx #4 ; No, so set the shift amount to 4. + cmp #'\t' ; Is this a tab? + beq @rshft ; Yes, so return 16. + ldx #0 ; No, so reset X. +@r0: + lda #0 ; Return 0. + rts ; End of isdelm. +@rshft: + stx a ; Save the shift value. + ldx #0 ; Reset X. + lda #1 ; Set up the bitshift. + lsl a ; Return 1 << X. + rts ; End of isdelm. + + +get_ptok: + ldx #0 ; Reset X. + jsr tolower ; Conver the character to lowercase. +@loop: + ldb ptok_tab, x ; Get the compare value. + beq @other ; We hit the end of the table, so check for the others. + cab ; Are they the same? + beq @rtab ; Yes, so return X. + inx ; No, so increment the table index. + jmp @loop ; Keep looping. +@rtab: + txa ; Return X. + rts ; End of get_ptok. +@other: + tab ; Preserve the character. + jsr isdigit ; Is this character a digit? + bne @rnum ; Yes, so return PTOK_NUM. + tba ; No, so get the character back. + jsr islower ; Is it an alphabetical character? + bne @ralph ; Yes, so return PTOK_ALPH. + lda #PTOK_OTHR ; No, so return PTOK_OTHR. + rts ; End of get_ptok. +@rnum: + lda #PTOK_NUM ; Return PTOK_NUM. + rts ; End of get_ptok. +@ralph: + lda #PTOK_ALPH ; Return PTOK_ALPH. + rts ; End of get_ptok. diff --git a/programs/subasm.s b/programs/subasm.s deleted file mode 100644 index 3c8e767..0000000 --- a/programs/subasm.s +++ /dev/null @@ -1,383 +0,0 @@ -; SuBAsm -; The Sux Bootstrapped Assembler. -; -; by mr b0nk 500 - -MAX_SYM = $800 ; Max symbol size. - -.include "lexer.s" -.include "utils.s" - -.org incl -; String Constants. -asm_name: - .byte "SuBAsm" -asm_ver: - .byte "0.1" - -; Directives. -dir: - .byte "org" - .byte "byte" - .byte "word" - .byte "dword" - .byte "qword" - .byte "include" - -; Short form Commands. -sh_cmds: - .byte "vlahirs" - -; Commands. -cmds: - .byte "viewmem" - .byte "list" - .byte "asm" - .byte "help" - .byte "inst" - .byte "run" - .byte "set" - -; Instruction mnemonics, and opcodes. - -; Legend. -; mne = Mnemonic. -; imm = Immediate data. -; zm = Zero Matrix. -; zmx = Zero Matrix, indexed with X. -; zmy = Zero Matrix, indexed with Y. -; ind = Indirect. -; idx = Indexed Indirect. -; idy = Indirect Indexed. -; abs = Absolute. -; imp = Implied. - -mne: -; mne imm, zm, zmx, zmy, ind, idx, idy, abs, imp - .byte "CPS", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00 - .byte "ADC", $01, $06, $FF, $FF, $FF, $FF, $FF, $04, $FF - .byte "AAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $02 - .byte "PHP", $08, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "CPB", $09, $2D, $FF, $FF, $55, $AD, $AC, $2C, $FF - .byte "PHB", $0A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "DEC", $FF, $0D, $FF, $FF, $FF, $FF, $FF, $0C, $E5 - .byte "JMP", $FF, $0E, $FF, $FF, $CE, $FF, $FF, $10, $FF - .byte "SBC", $11, $16, $FF, $FF, $FF, $FF, $FF, $14, $FF - .byte "SAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $12 - .byte "ENT", $18, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "CPY", $19, $3D, $FF, $FF, $85, $FF, $FF, $4C, $FF - .byte "PLB", $1A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "INC", $FF, $1D, $FF, $FF, $FF, $FF, $FF, $1C, $F5 - .byte "JSR", $FF, $1E, $FF, $FF, $BE, $FF, $FF, $20, $FF - .byte "AND", $21, $26, $FF, $FF, $FF, $FF, $FF, $24, $FF - .byte "ABA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $22 - .byte "PLP", $28, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "CPX", $29, $4D, $FF, $FF, $B5, $FF, $FF, $3C, $FF - .byte "PHY", $2A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "BPO", $FF, $2E, $FF, $FF, $FF, $FF, $FF, $30, $FF - .byte "ORA", $31, $36, $FF, $FF, $FF, $FF, $FF, $34, $FF - .byte "OAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $32 - .byte "STT", $38, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "PLY", $3A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "BNG", $FF, $3E, $FF, $FF, $FF, $FF, $FF, $40, $FF - .byte "XOR", $41, $46, $FF, $FF, $FF, $FF, $FF, $44, $FF - .byte "XAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $42 - .byte "PHA", $48, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "PHX", $4A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "BCS", $FF, $4E, $FF, $FF, $FF, $FF, $FF, $50, $FF - .byte "LSL", $51, $56, $FF, $FF, $FF, $FF, $FF, $54, $FF - .byte "LLB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $52 - .byte "CLC", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $58 - .byte "PLX", $5A, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "BCC", $FF, $5E, $FF, $FF, $FF, $FF, $FF, $60, $FF - .byte "LSR", $61, $66, $FF, $FF, $FF, $FF, $FF, $64, $FF - .byte "LRB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $62 - .byte "PLA", $68, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "TAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $6A - .byte "BEQ", $FF, $6E, $FF, $FF, $FF, $FF, $FF, $70, $FF - .byte "ROL", $71, $76, $FF, $FF, $FF, $FF, $FF, $74, $FF - .byte "RLB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $72 - .byte "SEC", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $78 - .byte "TBA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $7A - .byte "BNE", $FF, $7E, $FF, $FF, $FF, $FF, $FF, $80, $FF - .byte "ROR", $81, $86, $FF, $FF, $FF, $FF, $FF, $84, $FF - .byte "RRB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $82 - .byte "DEY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $88 - .byte "TAY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $8A - .byte "BVS", $FF, $8E, $FF, $FF, $FF, $FF, $FF, $90, $FF - .byte "MUL", $91, $96, $FF, $FF, $FF, $FF, $FF, $94, $FF - .byte "MAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $92 - .byte "CLI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $98 - .byte "TYA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $9A - .byte "BVC", $FF, $9E, $FF, $FF, $FF, $FF, $FF, $A0, $FF - .byte "DIV", $A1, $A6, $FF, $FF, $FF, $FF, $FF, $A4, $FF - .byte "DAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $A2 - .byte "INY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $A8 - .byte "TAX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $AA - .byte "RTS", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $AE - .byte "CMP", $B1, $B6, $FF, $FF, $25, $7D, $7C, $B4, $FF - .byte "CAB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $B2 - .byte "SEI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $B8 - .byte "LDX", $B9, $BD, $FF, $C9, $95, $FF, $FF, $BC, $FF - .byte "TXA", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $BA - .byte "RTI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C0 - .byte "LDA", $C1, $C6, $79, $39, $05, $5D, $5C, $C4, $FF - .byte "DEX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C5 - .byte "CLV", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $C8 - .byte "TYX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $CA - .byte "STA", $FF, $CD, $89, $49, $15, $6D, $6C, $CC, $FF - .byte "TSX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D0 - .byte "LDB", $D1, $D6, $99, $59, $35, $8D, $8C, $D4, $FF - .byte "INX", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D5 - .byte "WAI", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $D8 - .byte "TXY", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $DA - .byte "STB", $FF, $DD, $A9, $69, $45, $9D, $9C, $DC, $FF - .byte "TXS", $E0, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF - .byte "LDY", $E1, $E6, $E9, $FF, $65, $FF, $FF, $E4, $FF - .byte "BRK", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $E8 - .byte "NOP", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $EA - .byte "STY", $FF, $ED, $F9, $FF, $75, $FF, $FF, $EC, $FF - .byte "DEB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $EE - .byte "ASR", $F1, $F6, $FF, $FF, $FF, $FF, $FF, $F4, $FF - .byte "ARB", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $F2 - .byte "STX", $FF, $FD, $FF, $D9, $A5, $FF, $FF, $FC, $FF - .byte "INB" $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FE - -; Command subroutine table. -cmd_srt: - .word viewmem - .word list - .word asm - .word help - .word inst - .word run - .word set - -; Data entry point for the lexer. -lexer_data: - - -; Token table. -.org $20000 -tokline: - -.org cmd_buf+$400 -; Program Counter. -prg_cnt: - .qword 0 -; Hex digit string buffer. -hex_str: - .qword 0, 0 -; String buffer. -strbuf: - -.org strbuf+$80 -; Subroutine pointer. -sub_ptr: - .word 0 - -; Indecies. -idx0: - .qword 0 -idx1: - .qword 0 -idx2: - .qword 0 -idx3: - .qword 0 - -; Current token line. -ctok: - .word 0 - -; Last token line. -ltok: - .word 0 - -; Lexeme string. -lexeme: - -; Symbol table. -.org lexeme+$100 -sym: - -; Fixup table. -; Fixups are unresolved symbols. -.org sym+$8000 -fix: - - -; Start of program code. -.org parser -subasm: - ldb #0 ; Set the first pointer - lda.d #cmd_buf ; to the command buffer. - jsr set_ptr ; - tba ; Reset A. - tax ; Reset X. - jsr chk_shcmd ; Did we get a shortend command? - bne @cmd ; Yes, so skip everything else. - jsr chk_cmd ; No, but did we get a full command? - bne @cmd ; Yes, so skip everything else. - jsr lex ; No, so start lexing this line. - jmp @end ; We are done. -@cmd: - ldb #1 ; Set the second pointer - lda.d #cmd_srt ; to the command subroutine table. - jsr set_ptr ; - deb ; Reset B. - tba ; Reset A. - lda f ; Get the command ID. - cmp #8 ; Is the command ID greater than the command count? - bcs @end ; Yes, so we're done. - lsl #1 ; No, so multiply the command ID by two. - phy #2 ; Preserve the screen buffer position. - tay ; Set the index to the offset that we just calculated. - lda.w (ptr2), y ; Get the command subroutine, from the command subroutine table. - ply #2 ; Get back the screen buffer position. - ldb #2 ; Save it in the third pointer. - jsr set_ptr ; - ldb #0 ; Reset B. - jsr (ptr3) ; Run the command's subroutine. -@end: - rts ; End of subasm. - -chk_shcmd: - tba ; Reset A. - inb ; Set the second pointer - lda.w #sh_cmds ; to the shortend command table. - jsr set_ptr ; - deb ; Reset B. - tba ; Reset A. - phy #2 ; Preserve the screen buffer position. - txy ; Set our index to zero. - lda (ptr), y ; Is there nothing in the command buffer? - beq @false ; Yes, so return that we failed. - cmp #' ' ; No, but is this character, a space? - beq @false ; Yes, so return that we failed. - jsr tolower ; No, so convert it to lowercase. -@loop: - ldb (ptr2), y ; Are we at the end of the table? - beq @false ; Yes, so return that we failed. - cab ; No, so did the character match? - beq @found ; Yes, so check if there are any arguments. - iny ; No, so check the next command. - jmp @loop ; Keep looping. -@found: - sty f ; Save the command ID. - ldy #1 ; Check the next character in the command buffer. - lda (ptr), y ; Is this the end of the buffer? - beq @true ; Yes, so return that we succeded. - cmp #' ' ; No, but is this a space? - beq @true ; Yes, so return that we succeded. - jmp @false ; No, so return that we failed. -@true: - lda #1 ; Return true. - jmp @end ; We are done. -@false: - ldb #0 ; Reset B. - tba ; Return false. - tax ; Reset X. -@end: - ply #2 ; Get back the screen buffer position. - rts ; End of chk_shcmd. - - -chk_cmd: - tba ; Reset A. - tax ; Reset X. - sta.q idx0 ; Reset the first index. - sta.q idx1 ; Reset the second index. -@loop: - lda.w #cmds ; Get pointer to the start of the command table. - clc ; Prepare for a non carrying add. - adc.w idx0 ; Offset the pointer, by the length of the previous string. - pha #8 ; Preserve the command string pointer. - jsr strcasecmp ; Is the command buffer, the same as the command string? - pla #8 ; Get the command string pointer back. - beq @true ; Yes, so return true. - ldb idx1 ; No, so Get the command ID. - cpb #7 ; Have we reached the end of the command table? - beq @false ; Yes, so return false. - inc idx1 ; No, so increment the command ID. -@getlen: - jsr strlen ; Get the string's length. - inx ; Add one to the length. - txa ; Place it in the accumulator. - clc ; Prepare for a non carrying add. - adc.w idx0 ; Add the string offset to the current length - sta.w idx0 ; Save the offset in the first index. - jmp @loop ; Keep looping. -@true: - ldb idx1 ; Get the command ID. - stb f ; Return the command ID. - ldb #1 ; Return true. - jmp @end ; We are done. -@false: - ldb #0 ; Return false. -@end: - rts ; End of chk_cmd. - -viewmem: - lda.q prg_cnt ; Get the program counter. - sta.q idx0 ; Save the address in the first index. - and #$F0 ; Clear the first four bits of the address. - sta idx0 ; Overwrite the first byte, with the masked byte. - lda #19 ; Move the cursor to the right, by 19 columns. - sta scr_col ; - jsr update_pos ; - jsr print_lo ; Print the low nibble offsets. - ldx #0 ; Reset X. - ldb #0 ; Reset B. - stb idx1 ; Reset the byte count. -@loop: - lda #'\n' ; Print a newline. - jsr print_char ; - jsr print_hi ; Place the address in the string buffer. - jsr print_chunk ; Place the next 16 bytes in the string buffer. - lda.d #strbuf ; Print the string buffer. - jsr print_str ; - inc idx1 ; Increment the chunk count. - ldb idx1 ; Get the chunk count. - cpb #$10 ; Did we print 16 chunks? - beq @end ; Yes, so we're done. - lda.q idx0 ; No, so get the address index. - clc ; Prepare for a non carrying add. - adc #$10 ; Add 16 to the address. - sta.q idx0 ; Put it back into the address. - and #0 ; Reset A. - jmp @loop ; Keep looping. -@end: - lda #'\n' ; Print a newline. - jsr print_char ; - and #0 ; Reset A. - rts ; End of viewmem. - - -list: - nop ; -@end: - rts ; End of list. -asm: - nop ; -@end: - rts ; End of asm. -help: - nop ; -@end: - rts ; End of help. -inst: - nop ; -@end: - rts ; End of inst. -run: - nop ; -@end: - rts ; End of run. -set: - nop ; -@end: - rts ; End of set. - -; Entry point for utility subroutines. -lexer: diff --git a/programs/subeditor.s b/programs/subeditor.s deleted file mode 100644 index 1768d62..0000000 --- a/programs/subeditor.s +++ /dev/null @@ -1,1234 +0,0 @@ -; SuBEditor. -; -; Writen in Sux assembly by -; mr b0nk 500 - -; I/O constants. -status = $100 ; Keyboard status. -scr = $101 ; Character that is to be printed. -kbd = $102 ; Character from the Keyboard. -step = $110 ; Enables clock stepping, when set. - -; Screen constants. -maxrow = 23 ; Screen's row count. -maxcol = 79 ; Screen's column count. - -; Include SuBAsm. -.include "subasm.s" - -.org $A000 -; String Literals/Constants. -tok: - .byte "dab" -msg: - .byte "oof, you divided a, and b on me.\n" - -ed_name: - .byte "SuBEditor" -ed_ver: - .byte "1" -ed_sver: - .byte ".0.0" - -ver_str: - .byte ", version " -made: - .byte "Created by, " - -author: - .byte "mr b0nk 500" - -string2: - .byte "You typed, " - -; Linewrap bitmask table. -bits: - .byte $80, $40, $20, $10, $08, $04, $02, $01 - -; This label is for any included files. -incl: - -; Linewrap table. -.org $30000 -bitabl: - .qword 0 - .qword 0 - -; SCreen buffer. -.org bitabl+$1000 -buffer: - -; Command buffer. -.org buffer+$2000 -cmd_buf: - - -; Screen variables. -.org 0 -scr_row: - .byte 0 -scr_col: - .byte 0 -scr_trow: - .byte 0 -scr_tcol: - .byte 0 -scr_ptr: - .word 0 -scr_ptr2: - .word 0 -scr_ptr3: - .word 0 - -; Pseudo registers. -a: - .byte 0 -b: - .byte 0 -c: - .byte 0 -d: - .byte 0 -e: - .byte 0 -f: - .byte 0 -g: - .byte 0 -; This pseudo register is always zero. -zero: - .qword 0 -; End of pseudo registers. - -end: - .qword 0 -bitmask: - .byte 0 -scr_str: - .byte 0 -scr_end: - .byte 0 -wrapped: - .byte 0 - -; Pointers -ptr: - .qword 0 -ptr2: - .qword 0 -ptr3: - .qword 0 - -; Main program -.org $8000 -reset: - cps ; Reset the processor status register. - ldx.w #$FFFF ; Reset the stack pointer. - txs ; - ldy #0 ; Reset the Y register. - sty end ; - tyx ; Reset the X register. - lda #maxrow ; Set the end of the screen to the screen's max row count. - sta scr_end ; - tya ; Reset the Accumulator. - sta scr_str ; Set the start of the screen back to zero. - sta.q bitabl ; Reset the first half of the linewrap table. - sta.q bitabl+8 ; Reset the second half of the linewrap table. - inc end ; - lda.w #$1FFF ; Set the clear count to $1FFF. - sta.w scr_ptr ; - lda.d #buffer ; Set the array to be cleared to the screen buffer. - jsr clr_arr ; Clear the screen buffer. - jsr pnt_strt ; Print the starting message. - jmp start ; Goto the start of the main program. - -clr_arr: - phb #1 ; Preserve whatever was in B. - ldb #0 ; Clear B. - jsr set_ptr ; Set the first pointer to the parameter. - adc #8 ; Set the second pointer to the parameter, plus eight. - inb ; Tell set_ptr to set the second pointer. - jsr set_ptr ; - deb ; Set B back to zero. - tba ; -@loop: - cpy.w scr_ptr ; Did we clear all of the array? - bcs @end ; Yes, so we're done. - sta.q (ptr), y ; No, so clear eight bytes. - sta.q (ptr2), y ; Clear eight more bytes. - tya ; Copy the array index. - adc #$10 ; Increment the index by 16. - tay ; Update the index. - tba ; Reset the Accumulator. - sta.q (ptr), y ; Do this one more time, to clear 32 bytes. - sta.q (ptr2), y ; - tya ; - adc #$10 ; - tay ; - tba ; - jmp @loop ; Keep looping. -@end: - ldy.w zero ; Set the index back to zero. - plb #1 ; Get whatever was in the B register, back. - rts ; End of clr_arr. - -pnt_strt: - lda.w #ed_name ; Print the name of the editor. - jsr print_str ; - lda.w #ver_str ; Print the version text. - jsr print_str ; - lda.w #ed_ver ; Print the version number. - jsr print_str ; - lda.w #ed_sver ; Print the sub version number. - jsr print_str ; - lda #'\n' ; Print a newline. - jsr print_char ; - lda.w #made ; Print the "Created by" text. - jsr print_str ; - lda.w #author ; Print the name of the author. - jsr print_str ; - lda #'\n' ; Print a newline. - jsr print_char ; - rts ; End of pnt_strt. - -start: - lda #0 ; TODO: Update this for the Super VIA. - sta status ; Clear the control register of the I/O adapter. - tax ; Reset X. - phy #2 ; Save the cursor index for later. - tay ; Reset the cursor index. - lda.w #$3FF ; Set the clear count to $3FF. - sta.w scr_ptr ; - lda.d #cmd_buf ; Set the array to be cleared to the command buffer. - jsr clr_arr ; Clear the command buffer. - ply #2 ; Get back the cursor index. - and #0 ; Reset the Accumulator. - sta end ; - jmp read ; Start reading the keyboard. - -read: - lda #0 ; Reset the Accumulator. - sta end ; Disable the dummy flag. - inc end ; Enable the dummy flag. - lda status ; Did we get a key? - beq read ; No, so try again. - jsr getchar ; Yes, and was it a newline? - beq parse ; Yes, so start parsing the line. - jmp read ; No, so keep looping. - -print_str: - ldx #0 ; Reset X. - sta.q end ; Save the parameter. -@reset: - lda.q end ; Get the parameter. - ldb #0 ; Clear the B register. - jsr set_ptr ; Set the first pointer to the parameter. - tba ; Clear the Accumulator. -@loop: - ldb #1 ; Enable replace mode. - stb b ; - lda.q ptr ; Get the first pointer. - cmp.q end ; Did the pointer change? - bne @reset ; Yes, so set it back. - and #0 ; No, reset the accumulator. - phy #2 ; Save the cursor index. - txy ; Copy the string index into Y. - lda (ptr), y ; Are we at the end of the string? - ply #2 ; Get the cursor index back. - beq @end ; Yes, so we're done. - inx ; No, so increment the string index. - jsr print_char ; Print the character. - jmp @loop ; Keep looping. -@end: - ldb #0 ; Enable insert mode. - stb b ; - rts ; End of print_str. - -getbit: - clc ; Clear the carry flag. - lda scr_str ; Has the screen been scrolled? - bne getbt0 ; Yes, so add the screen offset to the current line number. - ldx scr_row ; No, so just use the current line number. - jmp getbt1 ; Start getting the bit. -getbt0: - lda scr_row ; Get the current line number. - adc scr_str ; Add the screen offset to it. - tax ; Use it as the wrap index. -getbt1: - pha #1 ; Save the parameter. - ldb #1 ; Make sure that set_ptr sets the second pointer. - lda.d #bitabl ; Set the second pointer to the linewrap table. - jsr set_ptr ; - lsr #$10 ; Clear the Accumulator. - pla #1 ; Get the return byte back. - jsr bitpos ; Get the bit, and byte position. - phy #2 ; Save the screen index. - txy ; Get the byte position. - ldb (ptr2), y ; Get one byte of the wrap table. - ply #2 ; Get the screen index back. - aba ; Mask out the bit of the current line number. - cmp #1 ; Set the carry flag, if true. - jmp bitout ; We are done. - -clrbit: - pha #1 ; Save the parameter. - ldb #1 ; Make sure that set_ptr sets the second pointer. - lda.d #bitabl ; Set the second pointer to the linewrap table. - jsr set_ptr ; - and #0 ; Clear the Accumulator. - pla #1 ; Get the return byte back. - jsr bitpos ; Get the bit, and byte position. - xor #$FF ; Invert the bitmask. - phy #2 ; Save the screen index. - txy ; Get the byte position. - ldb (ptr2), y ; Get one byte of the wrap table. - aba ; Clear the bit of the current line number. -bitsav: - sta (ptr2), y ; Update the wrap table. - ply #2 ; Get the screen index back. -bitout: - ldx bitmask ; Return the bitmask. - rts ; We are done. - -setbit: - pha #1 ; Save the parameter. - ldb #1 ; Make sure that set_ptr sets the second pointer. - lda.d #bitabl ; Set the second pointer to the linewrap table. - jsr set_ptr ; - and #0 ; Clear the Accumulator. - pla #1 ; Get the return byte back. - jsr bitpos ; Get the bit, and byte position. - phy #2 ; Save the screen index. - txy ; Get the byte position. - ldb (ptr2), y ; Get one byte of the wrap table. - oab ; Set the bit of the current line number. - jmp bitsav ; Save the bit. - -bitpos: - pha #1 ; Save the parameter. - ldb #0 ; Make sure that set_ptr sets the first pointer. - lda.w #bits ; Set the first pointer to the bitmask table. - jsr set_ptr ; - and #0 ; Clear the Accumulator. - pla #1 ; Get the parameter back. - stx bitmask ; Make the line number the bitmask. - txa ; Copy it to the Accumulator. - and #7 ; Get the bit position. - phy #2 ; Save the cursor index. - tay ; Use the bit position as the index. - tax ; Copy it into X. - lda (ptr), y ; Get the bitmask. - ply #2 ; Get back the cursor index. - pha #1 ; Save the bitmask. - lda bitmask ; Get the line number. - lsr #3 ; Get the byte position. - tax ; Copy it into X. - pla #1 ; Get back the bitmask. - rts ; End of bitpos. - -getchar: - lda kbd ; Get the character that was typed from the keyboard. - ldb #0 ; Reset the B register. - stb e ; Set the temporary row position to zero, in case we get a newline. - stb b ; Enable insert mode. - pha #1 ; Save the character. - phy #2 ; Save the cursor index. - cmp #'\n' ; Was the character that was typed, a newline? - bne @print ; No, so just print the character. - jsr cmd_cpy ; Yes, so start copying the line to the command buffer. -@print: - ply #2 ; Get back the cursor index. - pla #1 ; Get back the character. - ldb e ; Is the temporary row position non zero? - bne @row ; Yes, so reset the row positon. -@print1: - jsr print_char ; No, so print the character. - lda a ; Get the return value. - cmp #'\n' ; Is the return value, a newline? - beq @true ; Yes, so return true. - jmp @false ; No, so return false. -@row: - ldb e ; Get the temporary row position. - cpb #maxrow ; Is temporary row position, at, or above the bottom of the screen? - beq @row2 ; Yes, so leave it as is. - bcs @row1 ; No, so set it to the bottom of the screen. - jmp @row2 ; Yes, so leave it as is. -@row1: - ldb #maxrow ; Set the row position to the bottom of the screen. -@row2: - stb scr_row ; Set the row position. - jmp @print1 ; Print the character. -@true: - lda #0 ; Return true. - jmp @end ; We are done. -@false: - lda #1 ; Return false. -@end: - rts ; End of getchar. - - -cmd_cpy: - lda scr_row ; Get the row position. - sta scr_trow ; Save it for later. - jsr findend ; Find the end of the line. - ldb scr_str ; Has the screen been scrolled? - beq @start ; No, so don't subtract the screen's starting point from the line number. -@offset: - sec ; Yes, so make sure that we don't subtract by the starting point, plus one. - sbc scr_str ; Offset the row position, back by the screen's starting point. - clc ; Clear the carry flag, so that nothing odd occurs. -@start: - sta scr_row ; Set the row position to the end of the line. - sta e ; Save it into the temporary row posiition. - jsr findst ; Find the start of the line. - clc ; Clear the carry flag. - lda scr_row ; Get the row position. - adc scr_str ; Add it with the screen's starting row. - mul #maxcol+1 ; Multiply it with the width of the screen, plus one. - tay ; Place it into the index. - ldx.w #0 ; Reset the X register. - ldb #0 ; Make sure that set_ptr sets the first pointer. - lda.d #buffer ; Set the first pointer to the start of the screen buffer. - jsr set_ptr ; - inb ; Make sure that set_ptr sets the second pointer. - lda.d #cmd_buf ; Set the second pointer to the start of the command buffer. - jsr set_ptr ; - deb ; Set B back to zero. - tba ; Set the accumulator to zero. -@loop: - ldb #0 ; Reset the B register. - lda.q (ptr), y ; Get eight bytes from the current line. -@loop1: - phy #2 ; Save the screen index. - txy ; Get the command buffer index. - sta (ptr2), y ; Copy one byte from the screen buffer, to the command buffer. - inx ; Increment the command buffer index. - ply #2 ; Get back the screen index. - cpx.w #$3FF ; Are we at the end of the command buffer? - bcs @end ; Yes, so we're done. - iny ; No, so increment the screen index. - inb ; Increment the byte count. - lsr #8 ; Shift in the next byte. - stb g ; Save the byte count. - tab ; Save the string buffer. - and #$FF ; Is this byte of the buffer, a null terminator? - beq @end1 ; Yes, so we're done. - tba ; No so get back the string buffer. - ldb g ; Get back the byte count. - cpb #7 ; Did we shift in eight bytes? - beq @loop ; Yes, so get eight more bytes. - jmp @loop1 ; No, so keep shifting in more bytes. -@end: - ldb #0 ; Reset B. - phy #2 ; Save the screen index. - txy ; Get the command buffer index. - stb (ptr2), y ; Terminate the command buffer. - ply #2 ; Get back the screen index. -@end1: - tab ; The B register is zero, so clear the Accumulator. - rts ; End of cmd_cpy. - - -findst: - lda #0 ; Reset A. -@loop: - pha #1 ; Save the current line number. - jsr getbit ; Is this the start of the line? - pla #1 ; Get the current line number back. - bcc @end ; Yes, so we're done. - inc ; No, so check the next physical line. - dec scr_row ; Are we at the top of the screen? - bpo @loop ; No, so keep looping. - dec ; Yes, so move back one line. - inc scr_row ; Put the row postiion back to zero. -@end: - cmp #0 ; Update all the flags. - rts ; End of findst. - - -fndend: - phb #1 ; Save the contents of the B register. - ldb #0 ; Make sure that set_ptr sets the first pointer. - lda.d #buffer ; Set the first pointer to the start of the screen buffer. - jsr set_ptr ; - tba ; Set the Accumulator to zero. - plb #1 ; Restore the contents of the B register. - phy #2 ; -@loop: - lda (ptr), y ; Are we at the end of the string? - beq @end ; Yes, so we're done. - iny ; No, so increment the cursor index. - jmp @loop ; Keep looping. -@end: - sty.w scr_ptr3 ; - ply #2 ; - rts ; End of fndend. - -findend: - jsr fndend ; - lda.w scr_ptr3 ; - div #maxcol+1 ; - rts ; - -parse: - lda #0 ; - tax ; - jsr subasm ; - jmp start ; - -print_char: - sta a ; Save the typed character for now. - ldb #2 ; Make sure that set_ptr sets the third pointer. - lda.d #buffer ; Set the third pointer to the start of the screen buffer. - jsr set_ptr ; - ldb #0 ; Set B to zero. - tba ; Set the Accumulator to zero. - lda a ; Get back the character. - cmp #$1B ; Did the user type an escape character? - beq esc ; Yes, so go check the escape code. - cmp #'\n' ; No, but did the user type a newline? - beq nl ; Yes, so handle the newline. - cmp #$C ; No, but did the user type Ctrl+L? - beq clr_scr ; Yes, so clear the screen. - cmp #19 ; No, but did the user type Ctrl+S? - beq en_step ; Yes, so enable clock/instruction stepping. - cmp #18 ; No, but did the user type Ctrl+R? - beq dis_step ; Yes, so disable clock/instruction stepping. - cmp #'\b' ; No, but did the user type a backspace? - beq bs ; Yes, so handle the backspace. - cmp #$7F ; No, but did they type Delete? - beq bs ; Yes, so treat it as a backspace. -printc: - lda #0 ; No, so start trying to print a character. - sta d ; - lda (ptr3), y ; Are we at the end of the string? - beq @save ; Yes, so just print the character. - lda b ; No, but was the flag set? - bne @save ; Yes, so don't shift the line. - sty.w scr_ptr ; No, so save the cursor index for later. - jsr fndend ; Find the end of the line. - jmp @shift ; Start shifting the line right. -@update: - lda scr_col ; Save the current column position for later. - sta scr_tcol ; -@update1: - jsr findend ; Find the end of the line. - sta e ; Use it for redrawing the line. - sta scr_row ; Set the row position to to the end of the line. - jsr findst ; Find the start of the line. - lda scr_row ; Get the start of the line. -@update2: - sta f ; Set the starting line, to the start of the line. - jsr rdrw_ln ; Redraw the line. - lda scr_trow ; Get the real row position back. - sta scr_row ; - lda scr_tcol ; Get the real column position back. - sta scr_col ; - jsr update_pos ; Update the cursor's position. - dec d ; - jmp @save1 ; -@shift: - ldy.w scr_ptr3 ; - inc scr_ptr3 ; - tyx ; - dey ; - ldb #1 ; - stb d ; - jsr shftln ; - ldb #1 ; - stb d ; - lda a ; - sta (ptr3), y ; store typed character into the input buffer. - lda scr_row ; - sta scr_trow ; - jmp @update ; -@save: - ldb d ; - bne @update ; -@save1: - lda a ; - sta (ptr3), y ; store typed character into the input buffer. -@incr: - inc scr_col ; Increment the cursor's x coordinate. - iny ; -@wrapped: - ldb #1 ; - stb f ; - ldb scr_col ; - cpb #maxcol+1 ; - bcs @scrolled ; -@print: - sta scr ; Echo typed character. - ldb f ; - beq @wrap ; - jmp printc_end ; -@scrolled: - ldb scr_row ; - cpb #maxrow ; - bcs @scroll ; -@wrapped2: - ldb #0 ; - stb f ; - jmp @print ; -@scroll: - sta scr ; Echo typed character. - clc ; - lda #1 ; - sta wrapped ; - jsr scrl_down ; -@wrap: - ldb #0 - stb scr_col ; - ldb scr_row ; - cpb #maxrow ; - bcs @wrap2 ; -@wrap1: - inc scr_row ; -@wrap2: - phx #2 ; - clc ; - lda scr_row ; - adc scr_str ; - tax ; - jsr setbit ; - plx #2 ; - jsr update_pos ; -printc_end: - rts ; - -nl: - lda #0 ; Reset A. - ldb (ptr3), y ; Is this character not a null terminator? - bne @scroll ; Yes, so don't overwrite it. - sta (ptr3), y ; No, so overwrite it. -@scroll: - sta scr_col ; Move the cursor to the start of the next line. - lda scr_row ; Get the row position. - cmp #maxrow ; Are we at the bottom of the screen? - bcc @incr ; No, so move down one line. - jsr scrl_down ; Yes, so scroll down one line. - jmp @end ; We are done. -@incr: - inc scr_row ; Move the cursor down by one line. - jsr update_pos ; Update the cursor's position. -@end: - lda #'\n' ; Print the newline. - sta a ; - jmp printc_end ; - -clr_scr: - lda #maxrow ; - sta scr_end ; - lda #0 ; - sta scr_str ; - sta.q bitabl ; - sta.q bitabl+8 ; - tay ; - lda.w #$1FFF ; Set the clear count to $1FFF. - sta.w scr_ptr ; - lda.d #buffer ; Set the array to be cleared to the screen buffer. - jsr clr_arr ; Clear the screen buffer. - tay ; - lda.w #$3FF ; Set the clear count to $3FF. - sta.w scr_ptr ; - lda.d #cmd_buf ; Set the array to be cleared to the command buffer. - jsr clr_arr ; Clear the screen buffer. - sta scr_col ; - sta scr_row ; - jsr update_pos ; - lda #$C ; - sta scr ; - jmp printc_end ; - -en_step: - lda step ; - beq step_en ; - jmp printc_end ; -step_en: - lda #1 ; - sta step ; - jmp printc_end ; - -dis_step: - lda step ; - bne step_dis ; - jmp printc_end ; -step_dis: - lda #0 ; - sta step ; - jmp printc_end ; - -back: - ldb #0 ; Reset B, and some flags. - stb e ; - stb f ; - lda scr_row ; Save the current row position for later. - sta scr_trow ; - jsr findend ; Find the end of the line. - sta scr_row ; Set our row position to the end of the line. -@find_st: - jsr findst ; Does this line take up more than one real line? - beq @shift ; No, so skip updating any other lines. - bcs @update ; Yes, so update the other lines. - lda scr_trow ; Get the real row position back. - sta scr_row ; -@shift: - dey ; Decrement the buffer's offset. - lda #0 ; Place a null terminator - sta (ptr3), y ; into the buffer. - tyx ; Copy the current cursor index to X. - iny ; Increment cursor index. - ldb #0 ; Set shifting direction to left. - stb d ; - jsr shftln ; Shift line back by one character. - lda #$7F ; Print a backspace to the screen. - sta scr ; - lda e ; Are we updating more than one line? - beq @load ; No, so skip to the next step. -@find_end: - jsr findend ; Yes, so find the end of the line. - sta e ; Set the end parameter to it. - lda scr_col ; Save the current column position for now. - sta scr_tcol ; - jsr rdrw_ln ; Start redrawing the line. - lda scr_tcol ; Get the real column position back. - sta scr_col ; -@load: - lda scr_trow ; Get the real row position back. - sta scr_row ; - dec scr_col ; Move the cursor back by one column, - jsr update_pos ; and update it's position. - jmp printc_end ; We are done. -@update: - lda scr_row ; Set the line to start redrawing, to the start of the line. - sta f ; - inc e ; Set the redraw flag to true. - jmp @shift ; Start shifting the line back. - -bs: - lda scr_col ; Are we at the far left of the screen? - beq @wrap ; Yes, so check for a wrapped line. - jmp back ; No, so add the backspace to the buffer. -@wrap: - jsr getbit ; Is this line, a wrapped line? - bcs @wrap1 ; Yes, so check if the cursor is at the top. - jmp printc_end ; No, so we're done. -@wrap1: - lda scr_row ; Are we at the top of the screen? - beq @wrap2 ; Yes, so check if the screen is at the top of the buffer. - jmp @wrap3 ; No, so start clearing the wrap bit. -@wrap2: - lda scr_str ; Are we at the top of the buffer? - bne @scroll ; Yes, so scroll up. - jmp printc_end ; No, so we're done. -@scroll: - clc ; Clear the carry flag, so that we don't get odd behaviour. - jsr scrl_up ; Scroll up. - inc scr_row ; Move down by one row. -@wrap3: - clc ; Clear the carry flag. - lda scr_row ; Add the cursor's row position, - adc scr_str ; and the screen's starting row. - tax ; Transfer that into X. -@wrap4: - dec scr_row ; Move up by one row. - ldb #maxcol+1 ; Move the cursor to the absolute right of the screen. - stb scr_col ; - jsr update_pos ; Update the cursor's position. - jmp back ; Delete the previous character. - -shftln: - ldb d ; Is the flag not set? - beq @dec_loop ; Yes, so shift, and decrement. - ldb #0 ; Clear the B register. - jmp @inc_loop ; No, so shift, and increment. -@neg: - ldy.w zero ; Set the source poition to 0. - stb (ptr3), y ; Clear the character that is in the source. - jmp @end ; We are done. -@inc_loop: - sty.w scr_ptr2 ; Save the source position for later. - ldy.w scr_ptr ; Get the previous cursor index. - cpy.w scr_ptr2 ; Is the source position, at, or below the cursor index? - beq @inc_loop1 ; Yes, so keep looping. - bcs @end ; No, so we're done. -@inc_loop1: - ldy.w scr_ptr2 ; Get the source position. - lda (ptr3), y ; Get the character from the source position. - phy #2 ; Save the source position for later. - txy ; Set our position to the destination. - sta (ptr3), y ; Place the character from the source position, to the destination position. - ply #2 ; Set our position back to the source. - stb (ptr3), y ; Clear the character that is in the source. - bng @neg ; The source underflowed, so set it back to zero, - dey ; Decrement the source position. - dex ; Decrement the destination position. - jmp @inc_loop ; Keep looping. -@dec_loop: - stx.w scr_ptr2 ; Save the destination position for later. - lda (ptr3), y ; Is the character at the source position, a null terminator? - beq @end3 ; Yes, so we're done. - phy #2 ; No, so save the source position for later. - txy ; Set our position to the destination. - sta (ptr3), y ; Place the character from the source position, to the destination position. - inx ; Increment the destination position. - ply #2 ; Set our position back to the source. - stb (ptr3), y ; Clear the character that is in the source. - iny ; Increment the source position. - jmp @dec_loop ; Keep looping. -@wrap: - tax ; Use the ending line as a parameter for setbit. - jsr setbit ; Set the wrap bit of the ending line. - jmp @end5 ; We are done. -@wrap1: - tax ; Use the ending line as a parameter for clrbit. - jsr clrbit ; Clear the wrap bit of the ending line. - jmp @end5 ; We are done. -@end: - lda (ptr3), y ; Is this character a null terminator? - bne @end1 ; No, so just find the end of the line. - lda #$20 ; Yes, so convert it to a space for now. - sta (ptr3), y ; -@end1: - jsr findend ; Find the ending line. - sta d ; Save ending line for later. - lda (ptr3), y ; Is this character a space? - cmp #$20 ; - bne @end5 ; No, so skip the conversion. - lda #0 ; Yes, so convert it back to zero. - sta (ptr3), y ; -@end2: - lda d ; Get the ending line. - cmp scr_row ; Is the ending line greater than the starting line? - beq @end5 ; No, so we're done. - bcs @wrap ; Yes, so set the wrap bit. - jmp @end5 ; No, so we're done. -@end3: - jsr findend ; Find the ending line. - cpb #0 ; Is the remainder zero? - beq @end4 ; Yes, so check if the ending line is greater than the starting line. - jmp @end5 ; No, so we're done. -@end4: - cmp scr_row ; Is the ending line greater than the starting line? - beq @end5 ; No, so we're done. - bcs @wrap1 ; Yes, so clear the wrap bit. -@end5: - rts ; End of shftln. - -esc: - lda status ; Get the next character. - lda kbd ; - cmp #$1B ; Is this character an escape character? - beq shftesc ; Yes, so check the other set of escape routines. - lda status ; No, so wait for the next character. - beq printc_end ; We have an error, so discard it, and go back to getting user input. - lda kbd ; Get the escape code. - sta c ; Store the escape code, until we need it. - lda #0 ; Set the D pseudo register to zero. - sta d ; - jsr isup ; Check if the user pressed up. - lda d ; Did the user press up? - bne esc_end ; Yes, so we're done. - jsr isdown ; No, so check if the user pressed down. - lda d ; Did the user press down? - bne esc_end ; Yes, so we're done. - lda #0 ; No, so check if the user pressed left. - jsr isleft ; - lda d ; Did the user press left? - bne esc_end ; Yes, so we're done. - jsr isright ; No, so check if the user pressed right. -esc_end: - lda #0 ; Clear the D pseudo register. - sta d ; - jmp printc_end ; We are done. - -shftesc: - lda status ; Skip the '['. - lda kbd ; - lda status ; Wait for the next character. - beq printc_end ; We have an error, so discard it, and go back to getting user input. - lda kbd ; Get the escape code. - sta c ; Store the escape code, until we need it. - lda #0 ; Use the D pseudo register as a skip flag. - sta d ; - jsr isshftup ; Check if the user pressed shift+up. - lda d ; Was it successful? - bne shftesc_end ; Yes, so we're done. - jsr isshftdown ; No, so check if the user pressed shift+down. -shftesc_end: - lda #0 ; Clear the D pseudo register. - sta d ; - jmp printc_end ; We are done. - -isup: - lda c ; Load the escape code into the accumulator. - cmp #'A' ; Did the user press the up arrow key? - bne @end ; No, so we're done. - lda scr_row ; Yes, but is the cursor at the top of the screen? - beq @scroll ; Yes, so check if we need to scroll. -@check2: - lda c ; No, so load the escape code back into the accumulator. - cmp #'A' ; Did the user press the up arrow key? - beq up ; Yes, so move the cursor up. - jmp @end ; No, so we're done. -@scroll: - lda scr_str ; Are we at the top of the screen buffer? - beq @end ; Yes, so we're done. - jsr scrl_up ; No, so scroll up. - lda #1 ; Tell the escape routine that we were successful. - sta d ; -@end: -isup_done: - rts ; End of isup. - -isdown: - lda c ; Load the escape code into the accumulator. - cmp #'B' ; Did the user press the down arrow key? - bne @end ; No, so we're done. - lda scr_row ; Yes, so start checking the y coordinate of the cursor. - cmp #maxrow ; Is the cursor at the bottom of the screen? - beq @scroll ; Yes, so scroll down. - lda c ; No, so load the escape code back into the accumulator. - cmp #'B' ; Did the user press the down arrow key? - beq down ; Yes, so move the cursor down. - jmp @end ; No, so we're done. -@scroll: - lda scr_row ; Save the cursor's row number. - sta scr_trow ; - lda scr_col ; Save the cursor's column number. - sta scr_tcol ; - jsr scrl_down ; Scroll down. - lda scr_trow ; Load the cursor's row number. - sta scr_row ; - lda scr_tcol ; Load the cursor's column number. - sta scr_col ; - lda #1 ; Tell the escape routine that we were successful. - sta d ; -@end: -isdown_done: - rts ; End of isdown. - -isright: - lda c ; Load the escape code into the accumulator. - cmp #'C' ; Did the user press the right arrow key? - bne @end2 ; No, so we're done. - lda scr_col ; Yes, so start checking the x coordinate of the cursor. - cmp #maxcol ; Is the cursor at the far right of the screen? - beq @wrap ; Yes, so check if this is a wrapped line. - jmp right ; No, so move the cursor right, like normal. -@wrap: - inc scr_row ; Move down a row. - jsr getbit ; Is the current line, a wrapped line? - bcs @incr ; Yes, so leave the cursor where it is. - dec scr_row ; No, so move the cursor back up a row. - jmp @end2 ; We are done. -@scroll: - lda scr_str ; Are we at the top of the screen buffer? - beq @end ; Yes, so we're done. - lda #1 ; No, so scroll down. - sta wrapped ; Set the wrapped flag. - jsr scrl_down ; Scroll down. - jmp @end ; We are done. -@incr: - lda #0 ; Set the cursor to the far left of the screen. - sta scr_col ; - lda scr_row ; Get the current row number. - cmp #maxrow ; Are we at the bottom of the screen? - beq @end1 ; No, so we're done. - bcs @scroll ; Yes, so check if we are scrolling down. - jmp @end1 ; No, so we're done. -@end: - dec scr_row ; Move back up a row. -@end1: - jsr update_pos ; Update the cursor position. -@end2: -isright_dne: - lda #0 ; Unset the wrapped flag. - sta wrapped ; - rts ; End of isright. - -isleft: - lda c ; Load the escape code into the accumulator. - cmp #'C' ; Did the user press right? - beq @end1 ; Yes, so we're done - lda scr_col ; No, but is the cursor at the far left of the screen? - beq @wrap ; Yes, so start checking if this is a wrapped line. - lda c ; No, so load the escape code back into the accumulator. - cmp #'D' ; Did the user press the left arrow key? - beq left ; Yes, so move the cursor left. - jmp @end1 ; No, so we're done. -@wrap: - jsr getbit ; Is the current line, a wrapped line? - bcs @decr ; Yes, so wrap back up a line. - jmp @end1 ; No, so we're done. -@decr: - lda scr_row ; Is the cursor at the top of the screen? - beq @decr1 ; Yes, so don't move up a line. - lda #1 ; No, so set the wrapped flag. - sta wrapped ; - dec scr_row ; Move the cursor up one line. -@decr1: - lda #maxcol ; Move the Cursor to the far right of the screen. - sta scr_col ; - lda #1 ; Tell the escape routine that we were successful. - sta d ; - lda scr_row ; Are we at the top of the screen? - beq @scroll ; Yes, so check if we need to scroll. - jmp @end ; No, so we're done. -@scroll: - lda wrapped ; Was the wrapped flag set somewhere else? - bne @end ; Yes so we're done. - lda scr_str ; No, but are we actually at the top of the screen buffer? - beq @end1 ; Yes, so we're done. - jsr scrl_up ; No, so scroll up. - jmp @end1 ; We are done. -@end: - jsr update_pos ; Update the cursor position. -@end1: -isleft_done: - lda #0 ; Unset the wrapped flag. - sta wrapped ; - rts ; End of isleft. - -up: - dec scr_row ; Move the cursor up a line. - jsr update_pos ; Update it's position. - lda #1 ; Tell the escape routine that we succeded. - sta d ; - jmp isup_done ; We are done. -down: - inc scr_row ; Move the cursor down a line. - jsr update_pos ; Update it's position. - lda #1 ; Tell the escape routine that we succeded. - sta d ; - jmp isdown_done ; We are done. -right: - inc scr_col ; Move the cursor right by one character. - jsr update_pos ; Update it's position. - jmp isright_dne ; We are done. -left: - dec scr_col ; Move the cursor left a character. - jsr update_pos ; Update it's position. - lda #1 ; Tell the escape routine that we succeded. - sta d ; - jmp isleft_done ; We are done - -isshftup: - lda c ; Load the escape code back into the accumulator. - cmp #'A' ; Did the user press the up arrow key? - bne shftup_done ; - lda #1 ; - sta d ; - lda scr_str ; - beq shftup_done ; - jmp shftup ; -shftup_done: - rts ; - -isshftdown: - lda c ; Load the escape code back into the accumulator. - cmp #'B' ; Did the user press the down arrow key? - bne shftdn_done ; - lda #1 ; - sta d ; - lda scr_end ; - cmp #71 ; - bcs shftdn_done ; - jmp shftdown ; -shftdn_done: - rts ; - -shftup: - jsr scrl_up ; - lda #1 ; - sta d ; - jmp shftup_done ; - -shftdown: - jsr scrl_down ; - lda #1 ; - sta d ; - jmp shftdn_done ; - -update_pos: - ldb #1 ; Set the F pseudo register to one, to fix some bugs. - stb f ; - clc ; Clear the carry flag. - lda scr_row ; Add the cursor's line number, - adc scr_str ; with the starting line number to get the absolute line number. - tay ; Place it in the Y regster for now. - mul #maxcol+1 ; Multiply the line number by the screen's max column count, plus 1. - clc ; Clear the carry flag. - adc scr_col ; Add the cursor's column number to get the screen index. - tay ; Place the index into the Y register. - tba ; Reset A. - lda #$1B ; Print an escape character - sta scr ; to the screen. - lda #'[' ; Print '[' - sta scr ; to the screen, and start the escape sequence. - jsr getrow ; Start printing the row number to the screen. - jsr getcol ; Start printing the column number to the screen. - lda #'H' ; Print 'H' - sta scr ; to the screen. - rts ; End of update_pos. - -getrow: - lda scr_row ; Get the cursor's y coordinate. - jmp bcd ; Convert it to BCD. -getcol: - lda #';' ; Print ';' - sta scr ; to the screen. - lda scr_col ; Get the cursor's x coordinate. -bcd: - div #10 ; Divide A by 10. - ora #'0' ; Convert it to ascii, and - sta scr ; print to the screen. - tba ; Get the remainder. - ora #'0' ; Convert it to ascii, and - sta scr ; print to the screen. - rts ; End of bcd. - -scrl_down: - inc scr_str ; Increment the starting line of the screen. - inc scr_end ; Increment the ending line of the screen. - lda #$1B ; Print an escape character - sta scr ; to the screen. - lda #'[' ; Print '[' - sta scr ; to the screen, and start the escape sequence. - lda #'T' ; Print 'T' - sta scr ; to the screen, and end the escape sequence. - lda scr_row ; Get the cursor's line number. - pha #1 ; Save it in the stack. - lda wrapped ; Was the wrapped flag set? - beq @save ; Yes, so save the cursor position. -@redraw: - jsr rdrw_row ; No, so redraw this row. - lda wrapped ; Was the wrapped flag set? - beq @load ; Yes, so load the previous cursor position back. - jmp @end ; No, so we're done. -@save: - lda scr_col ; Get the cursor's column number. - pha #1 ; Save it in the stack. - jmp @redraw ; Start redrawing the current row. -@load: - pla #1 ; Get the cursor's previous column number back. - sta scr_col ; -@end: - pla #1 ; Get the cursor's previous line number back. - sta scr_row ; - jsr update_pos ; Update the cursor's position. - lda #0 ; Clear the wrapped flag. - sta wrapped ; -@end1: - rts ; End of scrl_down. - -scrl_up: - dec scr_str ; - dec scr_end ; - lda #$1B ; Print an escape character - sta scr ; to the screen. - lda #'[' ; Print '[' - sta scr ; to the screen, and start the escape sequence. - lda #'S' ; Print 'S' - sta scr ; to the screen, and end the escape sequence. - lda scr_row ; - pha #1 ; - lda scr_col ; - pha #1 ; - lda #0 ; - sta scr_row ; - jsr rdrw_row ; - pla #1 ; - sta scr_col ; - pla #1 ; - sta scr_row ; - jsr update_pos ; -@end: - rts ; - -rdrw_row: - lda #0 ; - sta scr_col ; - jsr update_pos ; -@loop: - lda (ptr3), y ; - beq @incr ; - sta scr ; -@incr: - inc scr_col ; - lda (ptr3), y ; - beq @skip ; -@incr1: - iny ; -@incr2: - lda scr_col ; - cmp #maxcol+1 ; - bcs @end ; - jmp @loop ; -@skip: - lda #' ' ; - sta scr ; to the screen. - jmp @incr1 ; -@end: - lda #0 ; - sta scr_col ; - jsr update_pos ; -@end1: - rts ; - -rdrw_ln: - lda scr_row ; - pha #1 ; - lda f ; - sta scr_row ; - lda scr_col ; - pha #1 ; - jsr update_pos ; -@loop: - lda scr_row ; - cmp e ; - beq @loop1 ; - bcs @end ; -@loop1: - jsr rdrw_row ; -@incr: - inc scr_row ; - jmp @loop ; -@end: - pla #1 ; - sta scr_col ; - pla #1 ; - sta scr_row ; - jsr update_pos ; - lda #0 ; - sta e ; - sta f ; - rts ; - -set_ptr: - cpb #1 ; Are we setting the second pointer? - beq @ptr2 ; Yes, so start setting it. - cpb #2 ; No, but are we setting the third pointer? - beq @ptr3 ; Yes, so start setting it. -@ptr1: - stb.q ptr ; Reset the first pointer. - sta.q ptr ; No, so set the first pointer. - jmp @end ; We are done. -@ptr2: - stb.q ptr2 ; Reset the second pointer. - sta.q ptr2 ; Set the second pointer. - jmp @end ; We are done. -@ptr3: - stb.q ptr3 ; Reset the third pointer. - sta.q ptr3 ; Set the third pointer. -@end: - rts ; End of set_ptr. - -; Entry point for SuBAsm. -parser: - -.org $FFC0 -.qword reset -a -d - diff --git a/programs/utils.s b/programs/utils.s deleted file mode 100644 index d8d4aa2..0000000 --- a/programs/utils.s +++ /dev/null @@ -1,393 +0,0 @@ -; Utility subroutines for SuBAsm. - -.org util_data -; Hex character table. -hex_char: - .byte "0123456789ABCDEF" - -; Compare, and return table for pre-tokens. -ptok_tab: - .byte ".@:=+-><(),xy\"\'#;$%" -; Compare, and return table for isdelm. -dtab: - .byte "\n,\"\' " -; Compare, and return table for isdelm2. -dtab2: - .byte "),.+<>-=;\n" - -.org utils - -print_hi: - and #0 ; Reset A. - sta idx3 ; Clear the string index. - lda #'$' ; Print the hex delimiter. - jsr charcpy ; - lda.q idx0 ; Get the masked address. - ldx #$10 ; Set digit count to 16. - jsr print_hex ; Print the address. - lda.q hex_str ; Get the lower half of the string. - sta.q strbuf+1 ; Save it in the string buffer. - lda.q hex_str+8 ; Get the upper half of the string. - sta.q strbuf+9 ; Save it in the string buffer. - ldx #$11 ; Add 16 to the index. - stx idx3 ; - lda #':' ; Print a colon. - jsr charcpy ; - lda # ' ' ; Print a space. - jsr charcpy ; - rts ; End of print_hi. - -print_lo: - lda #0 ; Reset A. - sta idx3 ; Clear the string index. -@loop: - ldx #2 ; Set digit count to 2. - pha #1 ; Preserve the nibble offset. - jsr print_hex ; Print the low nibble offset. - lda.w (ptr3) ; Get the two digits. - jsr charcpy ; Copy the first digit. - lsr #8 ; Copy the next digit. - jsr charcpy ; - pla #1 ; Get the nibble offset back. - inc ; Increment the offset. - cmp #$10 ; Are we at the last offset? - bcs @end ; Yes, so we're done. -@loop1: - pha #1 ; No, so preserve the nibble offset. - lda #' ' ; Add a space to the string buffer. - jsr charcpy ; - pla #1 ; Get the nibble offset back. - jmp @loop ; Keep looping. -@end: - inx ; Increment the index by one. - lda #0 ; Null terminate the string buffer. - sta strbuf, x ; - tax ; Reset X. - lda.d #strbuf ; Print the string buffer. - jsr print_str ; - rts ; End of print_lo. - -print_chunk: - ldx #0 ; Reset X. - phy #2 ; Preserve the screen buffer index. - txy ; Copy the byte index to it. -@loop: - and #0 ; Reset A. - ldx #2 ; Set the digit count to 2. - lda (idx0), y ; Get the byte at that address. - jsr print_hex ; Print the byte. - lda.w (ptr3) ; Get the two digits. - jsr charcpy ; Copy the first digit. - lsr #8 ; Copy the next digit. - jsr charcpy ; - iny ; Increment the byte index. - cpy #$10 ; Have we read 16 bytes? - beq @end ; Yes, so we're done. - lda #' ' ; No, so add a soace to the string buffer. - jsr charcpy ; - jmp @loop ; Keep looping. -@end: - ply #2 ; Get the screen buffer index back. - inx ; Increment the index by one. - and #0 ; Null terminate the string. - sta strbuf, x ; - tax ; Reset X. - sta idx3 ; Clear the string index. - rts ; End of print_chunk. - - -print_hex: - pha #8 ; Preserve the hex value. - and #0 ; Reset A. - ldb #1 ; Set the second pointer - lda.w #hex_char ; to the start of hex character table. - jsr set_ptr ; - inb ; Set the third pointer - lda.d #hex_str ; to the end of hex string buffer. - clc ; Do a non carrying add. - adc #$10 ; - jsr set_ptr ; - ldb #0 ; Reset B. - pla #8 ; Get the hex value back. -@loop: - pha #8 ; Preserve the hex value. - and #$F ; Mask the lowest nibble. - phy #2 ; Preserve the screen buffer position. - tay ; Get the index for the hex digit. - lda (ptr2), y ; Get the hex digit. - dec ptr3 ; Decrement the string pointer. - sta (ptr3) ; Save the hex digit character in the string. - ply #2 ; Get back the screen buffer position. - pla #8 ; Get the hex value back. -@isauto: - cpx #1 ; Is the digit count less than one? - bcc @auto ; Yes, so don't decrement the digit count. - dex ; No, but was the digit count zero, when decremented? - beq @end ; Yes, so we're done. - jmp @next ; No, so get the next nibble. -@auto: - ldb #1 ; Enable auto digit count. -@next: - lsr #4 ; Is the next nibble, a zero? - beq @isauto1 ; Yes, so check if auto digit count is enabled. - jmp @loop ; No, so print the next digit. -@isauto1: - cpb #1 ; Is auto digit count enabled? - beq @end ; Yes, so we're done. - jmp @loop ; No, so keep printing more digits. -@end: - rts ; End of print_hex. - - -charcpy: - ldx idx3 ; Get the string index. - sta strbuf, x ; Save it in the string buffer. - inc idx3 ; Increment the string index. - rts ; End of charcpy. - - -strlen: - ldb #1 ; Set the second pointer - jsr set_ptr ; to the passed pointer. - deb ; Reset B. - tba ; Reset A. - tax ; Reset X. - phy #2 ; Preserve Y. - txy ; Reset Y. -@loop: - lda (ptr2), y ; Are we at the end of the string? - beq @end ; Yes, so we're done. - iny ; No, so increment the index. - jmp @loop ; Keep looping. -@end: - tyx ; Return the length in X. - ply #2 ; Get the preserved value back. - rts ; End of strlen. - - -strcmp: - ldb #1 ; Set the second pointer - jsr set_ptr ; to the passed pointer. - deb ; Reset B. - tba ; Reset A. - phy #2 ; Preserve Y. - tay ; Reset Y. -@loop: - ldb #0 ; Set the islong flag to false. - lda (ptr), y ; Are we at the end of the first string? - beq cmpr ; Yes, so check if we're too short, or too long. - ldb #1 ; No, so set the islong flag to true. - cmp (ptr2), y ; Is the character of both strings, the same? - bne cmpr ; No, so check if we're too short, or too long. - iny ; Yes, so increment the index. - jmp @loop ; Keep looping. - -strcasecmp: - ldb #1 ; Set the second pointer - jsr set_ptr ; to the passed pointer. - deb ; Reset B. - tba ; Reset A. - phy #2 ; Preserve Y. - tay ; Reset Y. -@loop: - ldb #0 ; Set the islong flag to false. - lda (ptr), y ; Are we at the end of the first string? - beq cmpr ; Yes, so check if we're too short, or too long. - ldb #1 ; No, so set the islong flag to true. - jsr tolower ; Convert the character of string 1 to lowercase. - phb #1 ; Preserve the islong flag. - pha #1 ; Preserve the converted character. - lda (ptr2), y ; Get the character of the second string. - jsr tolower ; Convert the character of string 2 to lowercase. - tab ; Place it in B. - pla #1 ; Get the character of string 1 back. - cab ; Is the character of both strings, the same? - plb #1 ; Get the islong flag back. - bne cmpr ; No, so check if we're too short, or too long. - iny ; Yes, so increment the index. - jmp @loop ; Keep looping. - -cmpr: - lda (ptr2), y ; Are we at the end of the second string? - beq @islong ; Yes, so check the islong flag. -@isshort: - lda (ptr), y ; No, but are we at the end of the first string? - beq @short ; Yes, so return -1. -@islong: - cpb #1 ; Is the islong flag true? - bne @equ ; No, so return 0. -@long: - lda #1 ; Yes, so return 1. - jmp @end ; We are done. -@equ: - lda #0 ; Return 0. - jmp @end ; We are done. -@short: - lda #$FF ; Return -1. -@end: - ply #2 ; Get the preserved value back. - rts ; End of strcmp. - - -isdigit: - sec ; Prepare for a non carrying subtraction. - sbc #'0' ; Subtract $30 from the passed character. - and #$FF ; Make sure that we have only one byte. - cmp #10 ; Is the subtracted value, less than 10? - bcs @false ; No, so return false. -@true: - lda #1 ; Yes, so return true. - jmp @end ; We are done. -@false: - lda #0 ; Return false. -@end: - rts ; End of isdigit. - -isxdigit: - pha #1 ; Preserve the character. - jsr isdigit ; Is this character, a decimal digit? - pla #1 ; Get the character back. - bne @true ; Yes, so return true. -@alpha: - sec ; No, so prepare for a non carrying subtract. - ora #$20 ; Convert it to lowercase. - sbc #'a' ; Subtract $61 from the character. - and #$FF ; Make sure that we have only one byte. - cmp #6 ; Is the subtracted value, less than 6? - bcs @false ; No, so return false. -@true: - lda #1 ; Yes, so return true. - jmp @end ; We are done. -@false: - lda #0 ; Return false. -@end: - rts ; End of isxdigit. - - -isupper: - sec ; Prepare for a non carrying subtraction. - sbc #'A' ; Subtract $41 from the passed character. - jmp isletter ; Check if it's less than 26. -islower: - sec ; Prepare for a non carrying subtraction. - sbc #'a' ; Subtract $61 from the passed character. -isletter: - and #$FF ; Make sure that we have only one byte. - cmp #26 ; Is the subtracted value, less than 26? - bcs @false ; No, so return false. -@true: - lda #1 ; Yes, so return true. - jmp @end ; We are done. -@false: - lda #0 ; Return false. -@end: - rts ; End of isletter. - - -tolower: - pha #1 ; Preserve the character. - jsr isupper ; Is this character, an uppercase character? - pla #1 ; Get the character back. - beq @end ; No, so we're done. -@lower: - ora #$20 ; Yes, so convert it to lowercase. -@end: - rts ; End of tolower. - - -toupper: - pha #1 ; Preserve the character. - jsr islower ; Is this character, a lowercase character? - pla #1 ; Get the character back. - beq @end ; No, so we're done. -@upper: - and #$5F ; Yes, so convert it to uppercase. -@end: - rts ; End of toupper. - - -isdelm2: - ldx #0 ; Reset X. -@loop: - ldb dtab2, x ; Get the compare value. - beq @other ; We hit the end of the table, so check for the others. - cab ; Are they the same? - beq @r1 ; Yes, so return 1. - inx ; No, so increment the table index. - jmp @loop ; Keep looping. -@other: - ldx #0 ; Reset X. - cmp #0 ; Is this a null terminator? - beq @r1 ; Yes, so return 1. - cmp #'\t' ; No, but is it a tab? - beq @r2 ; Yes, so return 2. - cmp #' ' ; No, but is it a space? - beq @r2 ; Yes, so also return 2. -@r0: - lda #0 ; Return 0. - rts ; End of isdelm2. -@r1: - ldx #0 ; Reset X. - lda #1 ; Return 1. - rts ; End of isdelm2. -@r2: - lda #2 ; Return 2. - rts ; End of isdelm2. - - -isdelm: - ldx #0 ; Reset X. -@loop: - ldb dtab, x ; Get the compare value. - beq @other ; We hit the end of the table, so check for the others. - cab ; Are they the same? - beq @rshft ; Yes, so return 1 << index. - inx ; No, so increment the table index. - jmp @loop ; Keep looping. -@other: - ldx #0 ; Reset X. - cmp #0 ; Is this a null terminator? - beq @rshft ; Yes, so return 1. - ldx #4 ; No, so set the shift amount to 4. - cmp #'\t' ; Is this a tab? - beq @rshft ; Yes, so return 16. - ldx #0 ; No, so reset X. -@r0: - lda #0 ; Return 0. - rts ; End of isdelm. -@rshft: - stx a ; Save the shift value. - ldx #0 ; Reset X. - lda #1 ; Set up the bitshift. - lsl a ; Return 1 << X. - rts ; End of isdelm. - - -get_ptok: - ldx #0 ; Reset X. - jsr tolower ; Conver the character to lowercase. -@loop: - ldb ptok_tab, x ; Get the compare value. - beq @other ; We hit the end of the table, so check for the others. - cab ; Are they the same? - beq @rtab ; Yes, so return X. - inx ; No, so increment the table index. - jmp @loop ; Keep looping. -@rtab: - txa ; Return X. - rts ; End of get_ptok. -@other: - tab ; Preserve the character. - jsr isdigit ; Is this character a digit? - bne @rnum ; Yes, so return PTOK_NUM. - tba ; No, so get the character back. - jsr islower ; Is it an alphabetical character? - bne @ralph ; Yes, so return PTOK_ALPH. - lda #PTOK_OTHR ; No, so return PTOK_OTHR. - rts ; End of get_ptok. -@rnum: - lda #PTOK_NUM ; Return PTOK_NUM. - rts ; End of get_ptok. -@ralph: - lda #PTOK_ALPH ; Return PTOK_ALPH. - rts ; End of get_ptok. diff --git a/sux.c b/sux.c index 49ec881..a2fc04b 100644 --- a/sux.c +++ b/sux.c @@ -579,7 +579,7 @@ int main(int argc, char **argv) { } } else { #if debug - subdbg = !strcmp(argv[1], "programs/subeditor.s"); + subdbg = !strcmp(argv[1], "programs/sub-suite/subeditor.s"); #endif if (asmmon(argv[1]) == 2) { return 0; -- cgit v1.2.3-13-gbd6f