summaryrefslogtreecommitdiff
path: root/programs/subasm.s
diff options
context:
space:
mode:
authormrb0nk500 <b0nk@b0nk.xyz>2020-05-28 20:03:09 -0400
committermrb0nk500 <b0nk@b0nk.xyz>2020-05-28 20:03:09 -0400
commit7ba25336342282bfe57dbb6ddf8f3e2ae3e1b719 (patch)
tree1e9a5921d19056be61b9f613f254556edf5242a7 /programs/subasm.s
parent691ae45b3916379b0b1d845a5581d9068426b134 (diff)
Refactored the assembler, yet again, and implemented
support for comma separated values. The assembler now uses a linked list of tokenized lines, each containing a linked list of tokens for that line. I also moved all of the large tables into the higher parts of memory, in order to free up the lower part of memory for the user. Comma sepparated values only work with directives, and only with the byte", word, dword, and qword directives. I also added support for getting the upper, and lower halves of an address. The tokens for both of those are '<', and '>' respectively.
Diffstat (limited to 'programs/subasm.s')
-rw-r--r--programs/subasm.s1019
1 files changed, 457 insertions, 562 deletions
diff --git a/programs/subasm.s b/programs/subasm.s
index 50f2e8d..350e105 100644
--- a/programs/subasm.s
+++ b/programs/subasm.s
@@ -3,576 +3,471 @@
;
; by mr b0nk 500 <b0nk@b0nk.xyz>
-; Variables
-.org $1000
-prg_name:
+MAX_SYM = $800 ; Max symbol size.
+
+.org incl
+; String Constants.
+asm_name:
.byte "SuBAsm"
-ver_txt:
- .byte ", version "
-ver_num:
+asm_ver:
.byte "0.1"
; Directives.
dir:
- .byte "org"
+ .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.
-; Instruction mnemonics.
mne:
- .byte "CPS"
- .byte "ADC"
- .byte "AAB"
- .byte "PHB"
- .byte "PHP"
- .byte "PHA"
- .byte "PHY"
- .byte "TAY"
- .byte "PHX"
- .byte "TAX"
- .byte "TYX"
- .byte "JMP"
- .byte "SBC"
- .byte "SAB"
- .byte "PLB"
- .byte "PLP"
- .byte "PLA"
- .byte "PLY"
- .byte "TYA"
- .byte "PLX"
- .byte "TXA"
- .byte "TXY"
- .byte "JSR"
- .byte "AND"
- .byte "ABA"
- .byte "STT"
- .byte "TAB"
- .byte "TSX"
- .byte "BPO"
- .byte "ORA"
- .byte "OAB"
- .byte "TBA"
- .byte "SEI"
- .byte "TXS"
- .byte "BNG"
- .byte "XOR"
- .byte "XAB"
- .byte "CLI"
- .byte "BCS"
- .byte "LSL"
- .byte "LLB"
- .byte "STB"
- .byte "SEC"
- .byte "STA"
- .byte "STY"
- .byte "STX"
- .byte "BCC"
- .byte "LSR"
- .byte "LRB"
- .byte "LDB"
- .byte "CLC"
- .byte "LDA"
- .byte "LDY"
- .byte "LDX"
- .byte "BEQ"
- .byte "ROL"
- .byte "RLB"
- .byte "SSP"
- .byte "BNE"
- .byte "ROR"
- .byte "RRB"
- .byte "CSP"
- .byte "BVS"
- .byte "MUL"
- .byte "MAB"
- .byte "SEV"
- .byte "BVC"
- .byte "DIV"
- .byte "DAB"
- .byte "CLV"
- .byte "RTS"
- .byte "CMP"
- .byte "CAB"
- .byte "CPY"
- .byte "CPX"
- .byte "CPB"
- .byte "ENT"
- .byte "RTI"
- .byte "INC"
- .byte "IAB"
- .byte "INY"
- .byte "INX"
- .byte "DEC"
- .byte "DBA"
- .byte "DEY"
- .byte "DEX"
- .byte "WAI"
- .byte "JSL"
- .byte "ASR"
- .byte "ARB"
- .byte "NOP"
- .byte "RTL"
- .byte "BRK"
-
-
-scr_row:
- .byte $0
-scr_col:
- .byte $0
-a:
- .word $0
-b:
- .word $0
-c:
- .word $0
-d:
- .word $0
-
-str_buf:
-
-; Input buffer.
-.org $2000
-buf:
-
-.org $2400
-ptr1:
- .qword $2500
-
-ptr2:
- .qword $2900
-
-; Control Register.
-.org $C000
-ctrl_reg:
-
-; Screen.
-.org $C001
-scr:
-
-; Keyboard.
-.org $C002
-kbd:
-
-; Main program.
-.org $0
-reset:
- cps
- ldx.w #$FFFF
- txs
- ldy #0
- jsr clr_buf
- ldx.w #0 ; Reset x.
- ldy #0 ; Reset y.
- jmp print_title
-
-read:
- lda ctrl_reg ; Is the keyboard ready?
- beq read ; Loop until the keyboard is ready.
- lda #0 ; Start resetting the control register.
- sta ctrl_reg ; Reset the control register.
- jmp getchar ; We got a key.
-
-rset_x:
-
- ldx #0 ; Reset x.
- stx.w x
- rts
-
-print_title:
- lda prg_name, x
- beq print_ver ; Did we find a null terminator?
- sta ; Print character.
- inx ; Increment offset.
- inc x
- jmp print_title ; Keep printing more characters.
-
-print_ver
- jsr rset_x
- lda ver_txt, x
- beq print_num ; Did we find a null terminator?
- sta scr ; Print character.
- inx ; Increment offset.
- jmp print_ver ; Keep printing more characters.
-
-print_num:
- lda ver_num, x
- beq getline ; Did we find a null terminator?
- sta scr ; Print character.
- inx ; Increment offset.
- jmp print_num ; Keep printing more characters.
-getline:
- lda #$A
- sta scr ; Print newline
- inc scr_row
- lda #0
- sta scr_col
- inc y
- jsr rset_x
- jmp read
-
-getchar:
- lda kbd ; Get typed character.
- cmp #$1B ; Did the user type an escape?
- beq esc ; Yes, so start getting the escape code.
- cmp #$A ; Did the user type a newline?
- beq nl ; Yes, so start parsing the input.
- cmp #8 ; Did the user type a backspace?
- beq bs ; Yes, so start checking the buffer.
- jsr echo ; Print character to screen.
-
-store_char:
- sta buf, y ; Store typed character into the input buffer.
- iny ; Increment buffer offset.
- jmp read ; Get another character.
-
-esc:
- lda ctrl_reg ; Skip the '['.
- lda ctrl_reg ; Get the next character.
- beq read ; 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.
- jsr isup ; Check if the user pressed up.
- lda d
- cmp #0
- bne esc_end
- jsr isdown ; Check if the user pressed down.
- lda d
- cmp #0
- bne esc_end
- lda #0
- jsr isleft ; Check if the user pressed left.
- lda d
- cmp #0
- bne esc_end
- jsr isright ; Check if the user pressed right.
-esc_end:
- lda #$0
- sta d
- jmp rset_a ; Go back to getting user input.
-
-isup:
- lda scr_row ; Is the cursor at the top of the screen?
- beq isup_done ; Yes, so return.
- lda c ; No, so load the escape code back into the accumulator.
- cmp #$41 ; Did the user press the up arrow key?
- beq up ; Yes, so move the cursor up.
-isup_done:
- rts ; End of isup.
-
-isdown:
- lda scr_row ; Start checking the y coordinate of the cursor.
- cmp #$17 ; Is the cursor at the bottom of the screen?
- beq isdown_done ; Yes, so return.
- lda c ; No, so load the escape code back into the accumulator.
- cmp #$42 ; Did the user press the down arrow key?
- beq down ; Yes, so move the cursor down.
-isdown_done:
- rts ; End of isdown.
-
-isright:
- lda scr_col ; Start checking the x coordinate of the cursor.
- cmp #$4F ; Is the cursor at the far right of the screen?
- beq isright_end ; Yes, so return.
- lda c ; No, so load the escape code back into the accumulator.
- cmp #$43 ; Did the user press the right arrow key?
- beq right ; Yes, so move the cursor right.
-isright_end:
- rts ; End of isright.
-
-isleft:
- lda scr_col ; Is the cursor at the far left of the screen?
- beq isleft_done ; Yes, so return.
- lda c ; No, so load the escape code back into the accumulator.
- cmp #$44 ; Did the user press the left arrow key?
- beq left ; Yes, so move the cursor left.
-isleft_done:
- rts ; End of isleft.
-
-up:
- dec scr_row
- jsr update_pos
- lda #1
- sta d
- jmp isup_done
-down:
- inc scr_row
- jsr update_pos
- lda #1
- sta d
- jmp isdown_done
-right:
- inc scr_col
- jsr update_pos
- jmp isright_end
-left:
- dec scr_col
- jsr update_pos
- lda #1
- sta d
- jmp isleft_done
-
-update_pos:
- lda #$1B ; Print an escape character
- sta scr ; to the screen.
- lda #$5B ; 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 #$48 ; Print 'H'
- sta scr ; to the screen.
- rts ; End of update_pos.
-getrow:
- lda scr_row ; Get the cursor's y coordinate.
- div #$A ; Divide A by 10.
- adc #$30 ; Convert it to ascii, and
- sta scr ; print to the screen.
- tba ; Get the remainder.
- adc #$30 ; Convert it to ascii, and
- sta scr ; print to the screen.
- rts ; End of getrow.
-getcol:
- lda #$3B ; Print ';'
- sta scr ; to the screen.
- lda scr_col ; Get the cursor's x coordinate.
- div #$A ; Divide A by 10.
- adc #$30 ; Convert it to ascii, and
- sta scr ; print to the screen.
- tba ; Get the remainder.
- adc #$30 ; Convert it to ascii, and
- sta scr ; print to the screen.
- rts ; End of getrow.
-
-
-
-nl:
- sta scr ; Print newline.
- inc scr_row ; Move the cursor down one line.
- lda #0 ; Put a null terminator, in place of the newline.
- sta scr_col ; Move the cursor back to column 0.
- sta buf, y ; Place it into the input buffer.
- ldy.w #0 ; Reset y, to parse the input.
- jsr parse ; Start parsing input.
-
-back:
- sta scr ; Print backspace.
- lda #0 ; Put a null terminator, in place of the backspace.
- sta buf, y ; Place it into the input buffer.
- dey ; Decrement buffer offset.
- dec scr_col
- jmp read ; Get next character.
-
-bs:
- cpy #0 ; Are we at the start of the buffer?
- beq read ; We are, so do not store the backspace into the buffer.
- jmp back ; We are not, so add the backspace to the buffer.
-
-parse:
- jsr getdir
- jsr
- rts
-
-getdir:
- iny ; Increment offset.
- lda buf, y
- jsr iswhite
- bcs getdir ; Reset y, if we hit the null terminator.
- cmp #$2E ; Is this character a '.'?
- bne getdir_exit ; No, so return.
- jsr clr_ptr
-
-getdir_end:
- iny ; Increment offset.
- lda buf, y
- jsr iswhite
- bcs getdir_cmp
- ora #%00100000 ; Make character lower case.
- sta (ptr1), y
- jmp getdir_end
-gettok:
- ply #1
- iny
-gettok2:
- lda buf, y
- jsr istoken
- bcs gettok3
- jmp gettok2
-gettok3:
- cmp #$
- cmp #$24 ; Is this character, a '$'?
- beq getaddr ; Yes, so start getting the address.
-
-
-
-getdir_cmp:
- phy #1
- ldy.w #0
- tyx
-getdir_cpl:
- ldb dir, x ; Start checking if the directive we're using, is "org".
- stb (ptr2), y
- beq getdir_scmp
- inx
- iny
- jmp getdir_cpl
-getdir_scmp:
- ldy #0
- jsr strcmp
- cpx #0
- beq getdir_tok
-getdir_exit:
- rts ; End of getdir.
-
-
-istoken:
- cmp #$20 ; Is this character a space?
- beq istoken_f ; Yes, so return false.
- cmp #$09 ; Is this character a tab?
- beq istoken_f ; Yes, so return false.
- cmp #$A ; Is this character a newline?
- beq istoken_f ; Yes, so return false.
- cmp #$3B ; Is this character a ';'?
- beq istoken_f ; Yes, so return false.
- cmp #0 ; Is this character a null terminator?
- beq istoken_f ; Yes, so return false.
- sec ; Return true.
- rts ; End of istoken.
-istoken_f
- clc ; Return false.
- rts ; End of istoken_f.
-
-iswhite:
- cmp #$20 ; Is this character a space?
- beq iswhite_t ; Yes, so return true.
- cmp #9 ; Is this character a tab?
- beq iswhite_t ; Yes, so return true.
- clc ; No, so return false.
- rts ; End of iswhite.
-iswhite_t:
- sec ; Return true.
- rts ; End of iswhite_t.
-
-rset_y:
- ldy.w #0
- jmp print_buf ; Print the input buffer.
-
-print_buf:
- lda buf, y ; Get a character from the input buffer.
- beq fin ; Are we done with printing the buffer?
- sta scr ; Print said character.
- iny
- jmp print_buf ; Keep printing the buffer.
-
-spin:
- nop
- nop
- nop
- jmp spin
-
-clr_buf:
- lda #0
- cpy.w #$3FF
- beq clr_end
- sta buf, y
- iny
- jmp clr_buf
-clr_sbuf:
- lda #0
- cpy.w #$1FF
- beq clr_end
- sta str_buf, y
- iny
- jmp clr_sbuf
-
-clr_end:
- rts
-
-echo:
- tab
- ldx scr_col
- cpx #$4F
- bne echo_print
- cmp #$A
- beq linewrap
-linewrap:
- inc scr_row
- ldx #0
- stx scr_col
- jsr update_pos
-echo_print:
- tba
- sta scr ; Echo typed character.
- inc scr_col ; Increment the cursor's x coordinate.
- sta buf, y ; Store typed character into the input buffer.
- iny ; Increment the buffer offset.
- rts ; Return.
-
-clr_ptr:
- lda #0
- cpy.w #$3FF
- beq ptr_end
- sta (ptr1), y
- sta (ptr2), y
- iny
- jmp clr_ptr
-ptr_end:
- rts
-
-strcmp:
- lda (ptr1), y
- cmp (ptr2), y
- bne strcmp_l1
- tax
- beq strcmp_l3
- iny
- bne strcmp
- jmp strcmp
-
-
-strcmp_l1:
- bcs strcmp_l2
- ldx #0
- dex
- rts
-
-strcmp_l2:
- ldx #1
-strcmp_l3:
- rts
-
-
-.org $FFC0
-.qword reset
-
-.org $FF50
-.qword spin
-.qword spin
-.qword spin
-.qword spin
-.qword spin
-.qword spin
-.qword spin
-
-.org $FFA0
-.qword irq_routine
-.org $0
-v
-.org $100
-v
-.org $200
-v
-.org $300
-v
-.org $1000
-v
-.org $1100
-v
-.org $1200
-v
-.org $1300
-v
-.org $1400
-v
-q
-
+; 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, $FF, $FF
+ .byte "JSL", $FF, $FF, $FF, $FF, $FF, $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 "RTL", $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $B0
+ .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
+
+; Hex character table.
+hex_char:
+ .byte "0123456789ABCDEF"
+
+
+; 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
+
+; Lexeme string.
+lexeme:
+
+; Symbol tables.
+.org lexeme+$100
+sym_val:
+.org sym_val+$4000
+sym_id:
+.org sym_id+$1000
+sym_def:
+.org sym_def+$100
+sym_name:
+
+; Fixup table.
+; Fixups are unresolved symbols.
+.org sym_name+$1000
+fix_sym:
+.org fix_sym+$1000
+fix_ln:
+.org fix_ln+$1000
+fix_val:
+
+
+; Start of program code.
+.org parser
+subasm:
+ ldb #0 ; Set the first pointer
+ lda.d #cmd_buf ; to the command buffer.
+ jsl set_ptr ;
+ tba ; Reset A.
+ tax ; Reset X.
+ jsl chk_shcmd ; Did we get a shortend command?
+ bne parse_cmd ; Yes, so skip everything else.
+ jmp subasm_end ;
+ jsl chk_cmd ; No, but did we get a full command?
+ bne parse_cmd ; Yes, so skip everything else.
+ jsl lexer ; No, so start lexing this line.
+subasm_end:
+ rtl ; End of subasm.
+
+parse_cmd:
+ ldb #1 ; Set the second pointer
+ lda.d #cmd_srt ; to the command subroutine table.
+ jsl 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 subasm_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.
+ jsl set_ptr ;
+ ldb #0 ; Reset B.
+ jsr (ptr3) ; Run the command's subroutine.
+ jmp subasm_end ; We are done.
+
+chk_shcmd:
+ tba ; Reset A.
+ inb ; Set the second pointer
+ lda.w #sh_cmds ; to the shortend command table.
+ jsl 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 shcmd_fail ; Yes, so return that we failed.
+ cmp #' ' ; No, but is this character, a space?
+ beq shcmd_fail ; Yes, so return that we failed.
+shcmd_loop:
+ ldb (ptr2), y ; Are we at the end of the table?
+ beq shcmd_fail ; Yes, so return that we failed.
+ cab ; No, so did the character match?
+ beq shcmd_fnd ; Yes, so check if there are any arguments.
+ iny ; No, so check the next command.
+ jmp shcmd_loop ; Keep looping.
+shcmd_fnd:
+ 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 shcmd_true ; Yes, so return that we succeded.
+ cmp #' ' ; No, but is this a space?
+ beq shcmd_true ; Yes, so return that we succeded.
+ jmp shcmd_fail ; No, so return that we failed.
+shcmd_true:
+ lda #1 ; Return true.
+ jmp shcmd_end ; We are done.
+shcmd_fail:
+ ldb #0 ; Reset B.
+ tba ; Return false.
+ tax ; Reset X.
+shcmd_end:
+ ply #2 ; Get back the screen buffer position.
+ rtl ; End of chk_shcmd.
+
+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.
+ jsl 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 ;
+ jsl set_ptr ;
+ ldb #0 ; Reset B.
+ pla #8 ; Get the hex value back.
+pnthex_lp:
+ 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.
+pnthex_lp1:
+ cpx #1 ; Is the digit count less than one?
+ bcc pnthex_lp2 ; Yes, so don't decrement the digit count.
+ dex ; No, but was the digit count zero, when decremented?
+ beq pnthex_end ; Yes, so we're done.
+ jmp pnthex_lp3 ; No, so get the next nibble.
+pnthex_lp2:
+ ldb #1 ; Enable auto digit count.
+pnthex_lp3:
+ lsr #4 ; No, but is the next nibble, a zero?
+ beq pnthex_lp4 ; Yes, so check if auto digit count is enabled.
+ jmp pnthex_lp ; No, so print the next digit.
+pnthex_lp4:
+ cpb #1 ; Is auto digit count enabled?
+ beq pnthex_end ; Yes, so we're done.
+ jmp pnthex_lp ; No, so keep printing more digits.
+pnthex_end:
+ rtl ; 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.
+ rtl ; End of charcpy.
+
+print_hi:
+ and #0 ; Reset A.
+ sta idx3 ; Clear the string index.
+ lda #'$' ; Print the hex delimiter.
+ jsl charcpy ;
+ lda.q idx0 ; Get the masked address.
+ ldx #$10 ; Set digit count to 16.
+ jsl 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.
+ jsl charcpy ;
+ lda # ' ' ; Print a space.
+ jsl charcpy ;
+ rtl ; End of print_hi.
+
+print_lo:
+ lda #0 ; Reset A.
+ sta idx3 ; Clear the string index.
+pntlo_lp:
+ ldx #2 ; Set digit count to 2.
+ pha #1 ; Preserve the nibble offset.
+ jsl print_hex ; Print the low nibble offset.
+ lda.w (ptr3) ; Get the two digits.
+ jsl charcpy ; Copy the first digit.
+ lsr #8 ; Copy the next digit.
+ jsl charcpy ;
+ pla #1 ; Get the nibble offset back.
+ inc ; Increment the offset.
+ cmp #$10 ; Are we at the last offset?
+ bcs pntlo_end ; Yes, so we're done.
+pntlo_lp1:
+ pha #1 ; No, so preserve the nibble offset.
+ lda #' ' ; Add a space to the string buffer.
+ jsl charcpy ;
+ pla #1 ; Get the nibble offset back.
+ jmp pntlo_lp ; Keep looping.
+pntlo_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.
+ jsl print_str ;
+ rtl ; End of print_lo.
+
+print_chunk:
+ ldx #0 ; Reset X.
+ phy #2 ; Preserve the screen buffer index.
+ txy ; Copy the byte index to it.
+pntchnk_lp:
+ and #0 ; Reset A.
+ ldx #2 ; Set the digit count to 2.
+ lda (idx0), y ; Get the byte at that address.
+ jsl print_hex ; Print the byte.
+ lda.w (ptr3) ; Get the two digits.
+ jsl charcpy ; Copy the first digit.
+ lsr #8 ; Copy the next digit.
+ jsl charcpy ;
+ iny ; Increment the byte index.
+ cpy #$10 ; Have we read 16 bytes?
+ beq pntchnk_end ; Yes, so we're done.
+ lda #' ' ; No, so add a soace to the string buffer.
+ jsl charcpy ;
+ jmp pntchnk_lp ; Keep looping.
+pntchnk_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.
+ rtl ; End of print_chunk.
+
+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 ;
+ jsl update_pos ;
+ jsl print_lo ; Print the low nibble offsets.
+ ldx #0 ; Reset X.
+ ldb #0 ; Reset B.
+ stb idx1 ; Reset the byte count.
+vmem_lp0:
+ lda #'\n' ; Print a newline.
+ jsl print_char ;
+ jsl print_hi ; Place the address in the string buffer.
+ jsl print_chunk ; Place the next 16 bytes in the string buffer.
+ lda.d #strbuf ; Print the string buffer.
+ jsl print_str ;
+ inc idx1 ; Increment the chunk count.
+ ldb idx1 ; Get the chunk count.
+ cpb #$10 ; Did we print 16 chunks?
+ beq vmem_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 vmem_lp0 ; Keep looping.
+vmem_end:
+ lda #'\n' ; Print a newline.
+ jsl print_char ;
+ and #0 ; Reset A.
+ rts ; End of viewmem.
+
+
+list:
+ nop ;
+list_end:
+ rts ; End of list.
+asm:
+ nop ;
+asm_end:
+ rts ; End of asm.
+help:
+ nop ;
+help_end:
+ rts ; End of help.
+inst:
+ nop ;
+inst_end:
+ rts ; End of inst.
+run:
+ nop ;
+run_end:
+ rts ; End of run.
+set:
+ nop ;
+set_end:
+ rts ; End of set.