; SuBAsm ; The Sux Bootstrapped Assembler. ; ; by mr b0nk 500 ; Variables .org $1000 prg_name: .byte "SuBAsm" ver_txt: .byte ", version " ver_num: .byte "0.1" 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: ; 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 str_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 str_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: jmp parse ; Keep printing. jsr clr_sbuf rts forg: iny ; Increment offset. lda str_buf, y jsr iswhite bcs forg ; Reset y, if we hit the null terminator. cmp #$2E ; Is this character a '.'? bne forg_exit ; No, so return. sty org ; Yes, so store the origin. forg_end: iny ; Increment offset. lda str_buf, y jsr istoken bcs forg_end dey sty scr_col forg_exit: rts ; End of forg. 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 #$09 ; 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 #$1000 beq clr_end sta buf, y iny jmp clr_buf clr_sbuf: lda #$0 cpy.w #$40 beq clr_end sta str_buf, y iny jmp clr_sbuf clr_end: rts echo: sta a 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: lda a sta scr ; Echo typed character. inc scr_col ; Increment the cursor's x coordinate. sta str_buf, y ; Store typed character into the input buffer. iny ; Increment the buffer offset. rts ; Return. .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 ;viewmem ;.org $100 ;viewmem ;q done