; SuBEditor. ; ; Writen in Sux assembly by ; mr b0nk 500 .org $8000 reset: cps ; Reset the processor status register. lds.d #$2FFFF ; Reset the stack pointer. lea 0 ; Reset E. ldy #0 ; Reset Y. tyx ; Reset X. jsr init_heap ; Initialize the heap. mov sp, a ; Set the stack pointer to the end of RAM. ; txs ; sub.d #STKSIZE ; Subtract the stack size, from the end of RAM. sta.q heapend ; Save the end of the heap. and #0 ; Reset A. tax ; Reset X. clc ; Reset the carry flag, just in case. jsr init_tables ; Initialize the main tables. ; jsr test_free ; jsr clr_scr ; Clear the screen. jsr pnt_strt ; Print the starting message. bra start ; Goto the start of the main program. init_heap: lea HEAPORG ; Get the heap's starting point. ste.q heapptr ; mov d, e ; jsr findramend ; Find the end of the heap. rts ; End of init_heap. init_tables: lea d, SCRSIZE ; Allocate SCRSIZE bytes of RAM for the screen buffer. jsr malloc ; sta.q buffer ; lea d, CMDSIZE ; Allocate CMDSIZE bytes of RAM for the command buffer. jsr malloc ; sta.q cmd_buf ; lea d, LWSIZE ; Allocate LWSIZE bytes of RAM for the linewrap table. jsr malloc ; sta.q bitabl ; rts ; End of init_tables. ;test_free: ; inc step ; ; mov.q d, bitabl ; ; jsr free ; ; mov.q d, buffer ; ; jsr free ; ; lea d, LWSIZE ; Allocate LWSIZE bytes of RAM for the linewrap table. ; jsr malloc ; ; sta.q bitabl ; ; mov.q d, cmd_buf; ; jsr free ; ; lea d, SCRSIZE ; Allocate SCRSIZE bytes of RAM for the screen buffer. ; jsr malloc ; ; sta.q buffer ; ; lea d, CMDSIZE ; Allocate CMDSIZE bytes of RAM for the command buffer. ; jsr malloc ; ; sta.q cmd_buf ; ; and #0 ; Reset A. ; rts ; End of test_free. clr_arr: pha.q ; Preserve A. and #0 ; Reset A. @loop: mov.q (d+s), a ; Clear 16 bytes. mov.q (d+s+8), a ; sub s, #16 ; Subtract 16 from the size. bcs @loop ; We haven't reached the end, so keep looping. @end: pla.q ; Restore A. rts ; End of clr_arr. pnt_strt: lea d, ed_name ; Print the name of the editor. jsr print_str ; lea d, ver_str ; Print the version text. jsr print_str ; lea d, ed_ver ; Print the version number. jsr print_str ; lea d, ed_sver ; Print the sub version number. jsr print_str ; lea d, '\n' ; Print a newline. lda #'\n' ; Print a newline. jsr print_char ; lea d, made ; Print the "Created by" text. jsr print_str ; lea d, author ; Print the name of the author. jsr print_str ; lea d, '\n' ; Print a newline. lda #'\n' ; Print a newline. jsr print_char ; rts ; End of pnt_strt. clr_cmd: and #0 ; Reset A. tay ; Reset Y. lea s, CMDSIZE ; Set the clear count to CMDSIZE. lea d, (cmd_buf); Set the array to be cleared to the command buffer. jsr clr_arr ; Clear the command buffer. rts ; End of clr_cmd. start: lda #0 ; TODO: Update this for the Super VIA. sta status ; Clear the control register of the I/O adapter. tax ; Reset X. jsr clr_cmd ; Clear the command buffer. jsr update_ptr ; Get the screen buffer index. tay ; Save it in Y. and #0 ; Reset the Accumulator. bra read ; Start reading the keyboard. read: jsr getchar ; Get a character. jsr handle_char ; Send the character to the handler routine. beq parse ; The handled character was a newline, so start parsing. bra read ; Keep looping. parse: and #0 ; Reset A. tax ; Reset X. jsr subasm ; Call SuBAsm, and start parsing this line. bra start ; Go back to reading the keyboard. getchar: and #0 ; Reset A. @loop: lda status ; Did we get a key? beq @loop ; No, so try again. lda kbd ; Yes, so get the typed character. @end: rts ; End of getchar. print_str: pha.q ; Preserve A. phb.q ; Preserve B. and #0 ; Reset A. tba ; Reset B. @loop: mov regb, #1 ; Enable replace mode. and #0 ; Reset A. mov b, (d) ; Are we at the end of the string? beq @end ; Yes, so we're done. jsr update_ptr ; No, so get the screen buffer index. tay ; Save it in Y. tba ; Get the character back. inc d ; Increment the string pointer. jsr print_char ; Print the character. bra @loop ; Keep looping. @end: stz regb ; Enable insert mode. and #0 ; Reset A. tab ; Reset B. pla.q ; Restore A. plb.q ; Restore B. rts ; End of print_str. getbit: des ; Create the stack frame. add d, s ; Add the row position with the row offset position. lea s, (sp+1) ; Get the address of the bitmask. jsr bitpos ; Get the bit, and byte position. ins ; Cleanup the stack frame. mov a, (bitabl)+a ; Get the bit of the row position. and a, (s) ; Return the masked bit. rts ; End of getbit. clrbit: pha.q ; Preserve A. des ; Create the stack frame. lea s, (sp+1) ; Get the address of the bitmask. jsr bitpos ; Get the bit, and byte position. ins ; Cleanup the stack frame. not (s) ; Invert the bitmask. and (bitabl)+a, (s) ; Set the bit of the current row number to zero. pla.q ; Restore A. rts ; End of clrbit. setbit: pha.q ; Preserve A. phb.q ; Preserve B. mov b, s ; Save the bit. des ; Create the stack frame. lea s, (sp+1) ; Get the address of the bitmask. jsr bitpos ; Get the bit, and byte position. ins ; Cleanup the stack frame. cpb #1 ; Is the bit set? bne @clear ; No, so clear the bit. @set: or (bitabl)+a, (s) ; Set the bit of the current row number to one. bra @end ; We are done. @clear: not (s) ; Invert the bitmask. and (bitabl)+a, (s) ; Set the bit of the current row number to zero. @end: plb.q ; Restore B. pla.q ; Restore A. rts ; End of setbit. bitpos: mov a, d ; Preserve the row number. and d, #7 ; Get the bit position. lsr #3 ; Return the byte position. mov (s), (d+bits) ; Place the bitmask into the mask argument. rts ; End of bitpos. handle_char: ldb #0 ; Reset the B register. stb rege ; Set the temporary row position to zero, in case we get a newline. stb regb ; Enable insert mode. pha ; Save the character. phy.w ; 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.w ; Get back the cursor index. pla ; Get back the character. ldb rege ; 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 rega ; Get the return value. cmp #'\n' ; Is the return value, a newline? beq @true ; Yes, so return true. bra @false ; No, so return false. @row: ldb rege ; 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. bra @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. bra @print1 ; Print the character. @true: lda #0 ; Return true. bra @end ; We are done. @false: lda #1 ; Return false. @end: rts ; End of handle_char. cmd_cpy: lda scr_row ; Get the row position. sta scr_trow ; Save it for later. lea d, (buffer) ; Get the screen buffer. mov s, y ; Get the cursor index. ; jsr find_end ; Find the end of the line. ; mov f, a ; Save the end of the line. ; div #maxcol+1 ; Get the ending line. jsr get_endrow ; Get the ending line. ; inc step ; sub scr_str ; Offset the row position, back by the screen's starting point. @start: sta scr_row ; Set the row position to the end of the line. sta rege ; Save it into the temporary row posiition. jsr findst ; Find the start of the line. lda scr_row ; Get the row position. add 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.q 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.q 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. @@loop: phy.w ; 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.w ; Get back the screen index. cpx.w #CMDSIZE ; 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 regg ; Save the byte count. tab ; Save the string buffer. and #$FF ; Is this byte of the buffer, a null terminator? beq @@end ; Yes, so we're done. tba ; No so get back the string buffer. ldb regg ; Get back the byte count. cpb #7 ; Did we shift in eight bytes? beq @loop ; Yes, so get eight more bytes. bra @@loop ; No, so keep shifting in more bytes. @@end: ldb #0 ; Reset B. phy.w ; Save the screen index. txy ; Get the command buffer index. stb (ptr2), y ; Terminate the command buffer. ply.w ; Get back the screen index. @end: tab ; The B register is zero, so clear the Accumulator. rts ; End of cmd_cpy. findst: ; lda #0 ; Reset A. ; xor d, d ; Reset D. ; xor s, s ; Reset S. mov d, scr_row ; Get the row position. mov s, scr_str ; Get the row offset. @loop: ; pha ; Save the current line number. jsr getbit ; Is this the start of the line? ; pla ; Get the current line number back. beq @end ; Yes, so we're done. inc d ; 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 d ; Yes, so move back one line. inc scr_row ; Put the row postiion back to zero. @end: cmp d, #0 ; Update all the flags. rts ; End of findst. ;find_end: ; mov a, s ; Set the loop counter. ;@loop: ; inc ; Increment the loop counter. ; cmp (d+a-1), #0 ; Did we hit the null terminator? ; bne @loop ; No, so keep looping. ;@end: ; rts ; End of find_end2. find_end: phb.q ; Preserve B. phx.q ; Preserve X. phy.q ; Preserve Y. mov a, s ; Set the loop counter. div #maxcol+1 ; Get the row position. tay ; Save the row position. mov b, d ; Preserve the string pointer. mov x, s ; Preserve the cursor position. mov d, a ; @loop: xor s, s ; Reset S. iny ; Increment the line. mov d, y ; Get the line. jsr getbit ; Is this the end of the line? bne @loop ; No, so keep looping. @loop2_init: tya ; Get the ending row position. dec ; Decrement the row position. mul #maxcol+1 ; Get the loop counter. cmp a, x ; Is the new loop counter less than the old loop counter? mcc a, x ; Set the loop counter to the old loop counter if so. mov d, b ; Restore the string pointer. mov s, x ; Restore the cursor position. @loop2: inc ; Increment the loop counter. cmp (d+a-1), #0 ; Did we hit the null terminator? bne @loop2 ; No, so keep looping. @end: ply.q ; Restore Y. plx.q ; Restore X. plb.q ; Restore B. rts ; End of find_end. get_endrow: jsr find_end ; Find the end of the line. div #maxcol+1 ; Get the ending row. rts ; End of get_endrow ;get_endrow2: ; jsr find_end2 ; Find the end of the line. ; div #maxcol+1 ; Get the ending row. ; rts ; End of get_endrow print_char: phb.q ; Preserve B. phx.q ; Preserve X. phe.q ; Preserve E. sta rega ; Preserve the character. ldb #2 ; Make sure that set_ptr sets the third pointer. lda.q buffer ; Set the third pointer to the start of the screen buffer. jsr set_ptr ; deb ; Set B to one. tba ; Reset A. ; inc step ; lda rega ; Get the character back. jsr get_ctrlidx ; Get the control code jump table index. lea ct_jtb ; Get the pointer to the jump table. mov.w e, (e+2*a); Get the address of the control code handler. deb ; Reset B. tba ; Reset A. jsr (e) ; Jump to the handler for that control code. ple.q ; Restore E. plx.q ; Restore X. plb.q ; Restore B. rts printc: lda #0 ; start trying to print a character. sta regd ; lda (ptr3), y ; Are we at the end of the string? beq @save ; Yes, so just print the character. lda regb ; 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. bra @shift ; Start shifting the line right. @update: lda scr_col ; Save the current column position for later. sta scr_tcol ; @update1: lea d, (buffer) ; Get the screen buffer. mov s, y ; Get the cursor index. jsr get_endrow ; Get the ending line. mov d, a ; mov s, scr_trow ; Get the current row position. lda scr_trow ; Get the current row position. @update2: 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 regd ; bra @save1 ; @shift: ; ldy.w scr_ptr3 ; ; inc scr_ptr3 ; ; tyx ; ; dey ; ; ldb #1 ; ; stb regd ; lea d, (buffer) ; Get the screen buffer. mov.w s, scr_ptr; Get the cursor index. lea f, 1 ; Set the shift length to one. lea c, 1 ; Set the left flag to true. jsr shftln ; ldb #1 ; stb regd ; lda rega ; sta (ptr3), y ; store typed character into the input buffer. lda scr_row ; sta scr_trow ; bra @update ; @save: ldb regd ; bne @update ; @save1: lda rega ; sta (ptr3), y ; store typed character into the input buffer. @incr: inc scr_col ; Increment the cursor's x coordinate. inc.w scr_ptr ; Increment the screen index. iny ; @wrapped: ldb #1 ; stb regf ; ldb scr_col ; cpb #maxcol+1 ; bcs @scrolled ; @print: sta scr ; Echo typed character. ldb regf ; beq @wrap ; bra printc_end ; @scrolled: ldb scr_row ; cpb #maxrow ; bcs @scroll ; @wrapped2: ldb #0 ; stb regf ; bra @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.w ; ; clc ; ; lda scr_row ; ; adc scr_str ; ; tax ; mov d, scr_row ; Get the row position. add d, scr_str ; Add the row offset to the row position. lea s, 1 ; Set the bit to one. jsr setbit ; Set the bit of that row. ; plx.w ; 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. bra @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 rega ; rts ; clr_scr: lda #maxrow ; sta scr_end ; stz scr_str ; tay ; lea s, LWSIZE ; Set the clear count to LWSIZE. lea d, (bitabl) ; Set the array to be cleared to the linewrap table. jsr clr_arr ; Clear the linewrap table. lea s, SCRSIZE ; Set the clear count to SCRSIZE. lea d, (buffer) ; Set the array to be cleared to the screen buffer. jsr clr_arr ; Clear the screen buffer. ; lda.w #CMDSIZE ; Set the clear count to CMDSIZE. ; lea (cmd_buf) ; Set the array to be cleared to the command buffer. ; jsr clr_arr ; Clear the screen buffer. stz scr_col ; stz scr_row ; jsr update_pos ; lda #$C ; sta scr ; rts ; en_step: lda step ; beq step_en ; rts ; step_en: lda #1 ; sta step ; rts ; dis_step: lda step ; bne step_dis ; rts ; step_dis: lda #0 ; sta step ; rts ; bs: lda scr_col ; Are we at the far left of the screen? beq @wrap ; Yes, so check for a wrapped line. bra back ; No, so add the backspace to the buffer. @wrap: mov d, scr_row ; Get the row position. mov s, scr_str ; Get the row offset. jsr getbit ; Is this line, a wrapped line? bne @wrap1 ; Yes, so check if the cursor is at the top. rts ; 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. bra @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. rts ; No, so we're done. @scroll: jsr scrl_up ; Scroll up. inc scr_row ; Move down by one row. @wrap3: lda scr_row ; Add the cursor's row position, add 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. back: ldb #0 ; Reset B, and some flags. stb rege ; stb regf ; lda scr_row ; Save the current row position for later. sta scr_trow ; lea d, (buffer) ; Get the screen buffer. mov s, y ; Get the cursor index. jsr get_endrow ; Get the ending 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 regd ; lea d, (buffer) ; Get the screen buffer. mov s, y ; Get the cursor index. lea f, 1 ; Set the shift length to one. lea c, 0 ; Set the left flag to false. jsr shftln ; Shift line back by one character. lda #$7F ; Print a backspace to the screen. sta scr ; lda rege ; Are we updating more than one line? beq @load ; No, so skip to the next step. @find_end: lea d, (buffer) ; Get the screen buffer. mov s, y ; Get the cursor index. jsr get_endrow ; Yes, so Get the ending line. mov d, a ; mov s, scr_trow ; Get the current row position. 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. rts ; We are done. @update: lda (ptr3), y ; Are we at the end of the line? beq @shift ; Yes, so skip redrawing. lda scr_trow ; No, so set the line to start redrawing, to the line that the cursor is on. inc rege ; Set the redraw flag to true. bra @shift ; Start shifting the line back. ;shftln: ; pha.q ; Preserve A. ; phb.q ; Preserve B. ; and f, f ; Is the left flag not set? ; beq @right ; Yes, so shift the line to the right. ;; txa ; Get the end of the line. ; jsr find_end ; Find the end of the line. ; dec ; Decrement the source position. ; bra @left ; No, so shift the line to the left. ;@minus: ; and #0 ; Set the source poition to 0. ; mov (d), a ; Clear the character that is in the source. ; bra @lend ; We are done. ;@left: ; cmp s, a ; Is the cursor index, at, or below the source position? ; beq @left1 ; Yes, so keep looping. ; bcs @lend ; No, so we're done. ;@left1: ; cmp #0 ; Is the source position less than 0? ; bcc @minus ; Yes, so set the source position to zero. ; mov (d+a+1), (d+a) ; No, so shift the current character to the left by one. ; mov (d+a), #0 ; Clear the current character. ; dec ; Decrement the source position. ; bra @left ; Keep looping. ;@right: ; cmp (d+s), #0 ; Is this character a null terminator? ; beq @rend ; Yes, so we're done. ; mov (d+s-1), (d+s) ; No, so shift the current character to the right by one. ; mov (d+s), #0 ; Clear the current character. ; inc s ; Increment the source position. ; bra @right ; Keep looping. ;@wrap: ; mov d, a ; Get the ending line. ; lea s, f ; Set the bit to the left flag. ; jsr setbit ; Set the wrap bit of the ending line. ; bra @end ; We are done. ;@lend: ; lea s, (a+2) ; Add 2 to the source position. ; jsr find_end ; Find the end of the line. ; dec ; Decrement the end of line position. ; div #maxcol+1 ; Get the ending line. ;@lend2: ; cmp scr_row ; Is the ending line greater than the starting line? ; beq @end ; No, so we're done. ; bcs @wrap ; Yes, so set the wrap bit. ; bra @end ; No, so we're done. ;@rend: ; lea f, 0 ; Set the decrement offset to one. ; jsr find_end ; Find the end of the line. ; dec ; Decrement the end of line position. ; div #maxcol+1 ; Get the ending line. ; cpb #0 ; Is the remainder zero? ; bne @end ; No, so we're done. ;@rend2: ; cmp scr_row ; Is the ending line greater than the starting line? ; beq @end ; No, so we're done. ; bcs @wrap ; Yes, so clear the wrap bit. ;@end: ; plb.q ; Restore B. ; pla.q ; Restore A. ; rts ; End of shftln. ;minmax: ; psh.q d ; Preserve D. ; psh.q s ; Preserve S. ; mov d, e ; Get the shift length. ; mov s, b ; Get the ending position. ; jsr max ; Get the largest value. ; mov f, a ; Save the largest value. ; jsr min ; Get the smallest value. ; pul.q s ; Restore S. ; pul.q d ; Restore D. ; rts ; End of minmax. ;shftln: ; pha.q ; Preserve A. ; phb.q ; Preserve B. ; phx.q ; Preserve X. ; phy.q ; Preserve Y. ; phe.q ; Preserve E. ; mov x, d ; Get the string pointer. ; mov y, s ; Get the cursor position. ; mov e, f ; Get the shift length. ;@find_end: ; lea f, 1 ; Set the decrement offset to the left flag. ; jsr find_end ; Find the end of the line. ; mov f, e ; Get the shift length. ; tab ; Save the end position for later. ; and #0 ; Reset A. ; dec ; Set our offset to -1. ; and c, c ; Is the left flag set? ; mne a, f ; Set our offset to the length argument if so. ;@copy: ; add a, s ; Add the cursor position with the offset. ; lea s, (d+s) ; Get the address of the string pointer, at the cursor position. ; lea d, (d+a) ; Get the address of the string pointer, at the cursor position, plus the offset. ; jsr minmax ; Get the minimum, and maximum values. ;@check_length: ; cpe #2 ; Is the shift length greater than one? ; bcc @offset0 ; No, so skip the subtraction below. ; cmp f, y ; Yes, and is the end position greater than, or equal to the the cursor position? ; bcc @offset ; No, so skip the subtraction below. ; and c, c ; Yes, and is the left flag set? ; beq @offset0 ; No, so skip the subtraction below. ;@sub: ; tya ; Set the offset to the cursor position. ; bra @offset ; Subtract the offset. ;@offset0: ; sub f, a ; Subtract the end position by the shift length. ; bra @sub ; Subtract the cursor position. ;@offset: ; sub f, a ; Subtract the offset. ;@copy2: ; jsr memcpy ; Copy the string from the cursor, to the cursor plus the offset. ;@clear: ; jsr minmax ; Get the minimum, and maximum values. ; cmp #1 ; Is the smallest value equal to one? ; bne @clear2 ; No, so skip incrementing the value. ; inc ; Increment the smallest value. ;@clear2: ; sub f, a ; Subtract the end position by the shift length. ; mov d, y ; Get the cursor position. ; and c, c ; Is the left flag set? ; meq d, f ; Get the end position, minus the shift length if so. ; lea d, (x+d) ; Get the address of the string pointer, at the offset. ; xor s, s ; Reset S. ; mov f, e ; Restore the shift length. ; jsr memset ; Clear shift length bytes of the string, from the offset. ;@neg: ; and c, c ; Is the left flag set? ; bne @get_rows ; Yes, so don't negate the shift length. ; neg f ; Negate the shift length. ;@get_rows: ; mov x, b ; Save the end position. ; lea a, (b+f) ; Add, or subtract the end position, by the shift length. ; div #maxcol+1 ; Get the new ending line. ; mov e, a ; Save the ending line. ; xor f, f ; Reset F. ; and c, c ; Is the left flag set? ; meq f, b ; Save the remainder of the ending line if not. ; tya ; Get the cursor position. ; div #maxcol+1 ; Get the cursor line. ; and c, c ; Is the left flag set? ; meq a, e ; Set the starting line to the new ending line if not. ; tay ; Save the starting line. ; txa ; Get the end position. ; div #maxcol+1 ; Get the old ending line. ; and c, c ; Is the left flag set? ; mne a, e ; Set the ending line to the new ending line if so. ; tab ; Save the ending line. ; and c, c ; Is the left flag set? ; bne @inc ; Yes, so increment the starting line. ; cmp y, b ; No, but is the starting line less than the ending line? ; bcs @loop ; No, so don't increment. ; iny ; Yes, so increment the starting line. ; bra @getbit ; Get the bit. ;@loop: ; xor s, s ; Reset S. ; cmp y, b ; Is the current line greater than the ending line? ; beq @rem ; The current line is equal to the ending line, so check the remainder. ; bcs @end ; Yes, so we're done. ; bra @getbit ; No, so get the bit. ;@rem: ; and f, f ; Is the remainder zero? ; bne @end ; No, so we're done. ;@getbit: ; mov d, y ; Get the current line. ; jsr getbit ; Get the linewrap bit of that line. ; cmp a, c ; Is the linewrap bit the opposite value of the left flag? ; beq @inc ; No, so keep looping. ;@setbit: ; mov d, y ; Get the current line. ; mov s, c ; Get the left flag. ; jsr setbit ; Set the linewrap bit to the left flag. ;@inc: ; iny ; Increment the current line. ; bra @loop ; Keep looping. ;@end: ; ple.q ; Restore E. ; ply.q ; Restore Y. ; plx.q ; Restore X. ; plb.q ; Restore B. ; pla.q ; Restore A. ; rts ; End of shftln. shftln: pha.q ; Preserve A. phb.q ; Preserve B. phx.q ; Preserve X. phy.q ; Preserve Y. phe.q ; Preserve E. psh.q bp ; Preserve BP. mov x, d ; Get the string pointer. mov y, s ; Get the cursor position. mov e, f ; Get the shift length. and c, c ; Is the left flag set? bne @find_end ; Yes, so find the end of the line. cmp s, f ; No, but is the cursor position greater than, or equal to the shift length? bcc @end ; No, so we're done. @find_end: jsr find_end ; Find the end of the line. sub a, c ; Decrement the old end position, if the left flag is set. tab ; Save the old end position for later. mov a, f ; Get the shift length. neg a ; Negate the shift length. and c, c ; Is the left flag set? mne a, f ; Set our offset to the shift length if so. lea bp, (b+a) ; Add the old end position, with the offset to get the new end position. @copy: add a, y ; Add the cursor position with the offset. lea s, (x+y) ; Get the address of the string pointer, at the cursor position. lea d, (x+a) ; Get the address of the string pointer, at the cursor position, plus the offset. mov f, b ; Get the old end position. sub f, y ; Subtract the old end position, by the cursor position. jsr memcpy ; Copy the string from the cursor, to the cursor plus the offset. @clear: tya ; Get the cursor position. and c, c ; Is the left flag set? meq a, bp ; Set our offset to the new end position if not. lea d, (x+a) ; Get the address of the string pointer, at the offset position. xor s, s ; Reset S. mov f, e ; Get the shift length. jsr memset ; Clear shift length bytes of the string, from the offset. @get_rows: mov x, b ; Save the old end position. mov a, bp ; Get the new end position. div #maxcol+1 ; Get the new ending line. mov e, a ; Save the ending line. mov r11, f ; Get the shift length. xor f, f ; Reset F. and c, c ; Is the left flag set? meq f, b ; Save the remainder of the ending line if not. ; div #maxcol+1 ; Get the line length. ; dec ; Decrement the line length. ; mov bp, a ; Save the line length. tya ; Get the cursor position. div #maxcol+1 ; Get the cursor line. mov bp, a ; Save the cursor line. and c, c ; Is the left flag set? meq a, e ; Set the starting line to the new ending line if not. tay ; Save the starting line. txa ; Get the old end position. div #maxcol+1 ; Get the old ending line. cmp bp, a ; Is the cursor line greater than, or equal to the old ending line? mcs a, bp ; Get the cursor line if so. cmp r11, #maxcol+1 ; Is the shift length greater than, or equal to the max column count? adc #0 ; Increment the starting line if so. and c, c ; Is the left flag set? mne a, e ; Set the ending line to the new ending line if so. tab ; Save the ending line. and c, c ; Is the left flag set? bne @inc ; Yes, so increment the starting line. cmp y, b ; No, but is the starting line less than the ending line? bcc @inc ; Yes, so increment the starting line. @loop: xor s, s ; Reset S. cmp y, b ; Is the current line greater than the ending line? beq @rem ; The current line is equal to the ending line, so check the remainder. bcs @end ; Yes, so we're done. bra @getbit ; No, so get the bit. @rem: and f, f ; Is the remainder zero? bne @end ; No, so we're done. @getbit: mov d, y ; Get the current line. jsr getbit ; Get the linewrap bit of that line. cmp a, c ; Is the linewrap bit the opposite value of the left flag? beq @inc ; No, so keep looping. @setbit: mov d, y ; Get the current line. mov s, c ; Get the left flag. jsr setbit ; Set the linewrap bit to the left flag. @inc: iny ; Increment the current line. bra @loop ; Keep looping. @end: pul.q bp ; Restore BP. ple.q ; Restore E. ply.q ; Restore Y. plx.q ; Restore X. plb.q ; Restore B. pla.q ; Restore A. rts ; End of shftln. esc: lda status ; Get the next character. lda kbd ; cmp #'\e' ; 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 @end ; We have an error, so discard it, and go back to getting user input. lda kbd ; Get the escape code. sta regc ; Store the escape code, until we need it. lda #0 ; Set the D pseudo register to zero. sta regd ; jsr isup ; Check if the user pressed up. lda regd ; Did the user press up? bne @end ; Yes, so we're done. jsr isdown ; No, so check if the user pressed down. lda regd ; Did the user press down? bne @end ; Yes, so we're done. lda #0 ; No, so check if the user pressed left. jsr isleft ; lda regd ; Did the user press left? bne @end ; Yes, so we're done. jsr isright ; No, so check if the user pressed right. @end: lda #0 ; Clear the D pseudo register. sta regd ; rts ; We are done. shftesc: lda status ; Skip the '['. lda kbd ; lda status ; Wait for the next character. beq @end ; We have an error, so discard it, and go back to getting user input. lda kbd ; Get the escape code. sta regc ; Store the escape code, until we need it. lda #0 ; Use the D pseudo register as a skip flag. sta regd ; jsr isshftup ; Check if the user pressed shift+up. lda regd ; Was it successful? bne @end ; Yes, so we're done. jsr isshftdown ; No, so check if the user pressed shift+down. @end: lda #0 ; Clear the D pseudo register. sta regd ; rts ; We are done. isup: lda regc ; 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 regc ; 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. bra @end ; No, so we're done. @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 regd ; rts ; We are 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 regd ; @end: rts ; End of isup. isdown: lda regc ; 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 regc ; 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. bra @end ; No, so we're 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 regd ; rts ; We are 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 regd ; @end: rts ; End of isdown. isright: lda regc ; 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. bra @right ; No, so move the cursor right, like normal. @wrap: inc scr_row ; Move down a row. mov d, scr_row ; Get the row position. mov s, scr_str ; Get the row offset. jsr getbit ; Is the current line, a wrapped line? bne @incr ; Yes, so leave the cursor where it is. dec scr_row ; No, so move the cursor back up a row. bra @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. bra @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. bra @end1 ; No, so we're done. @right: inc scr_col ; Move the cursor right by one character. jsr update_pos ; Update it's position. rts ; End of isright. @end: dec scr_row ; Move back up a row. @end1: jsr update_pos ; Update the cursor position. @end2: lda #0 ; Unset the wrapped flag. sta wrapped ; rts ; End of isright. isleft: lda regc ; 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 regc ; 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. bra @end1 ; No, so we're done. @wrap: mov d, scr_row ; Get the row position. mov s, scr_str ; Get the row offset. jsr getbit ; Is the current line, a wrapped line? bne @decr ; Yes, so wrap back up a line. bra @end1 ; No, so we're done. @decr: lda scr_row ; Is the cursor at the top of the screen? beq @@decr ; 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. @@decr: 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 regd ; lda scr_row ; Are we at the top of the screen? beq @scroll ; Yes, so check if we need to scroll. bra @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. bra @end1 ; 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 regd ; rts ; We are done @end: jsr update_pos ; Update the cursor position. @end1: lda #0 ; Unset the wrapped flag. sta wrapped ; rts ; End of isleft. isshftup: lda regc ; Load the escape code back into the accumulator. cmp #'A' ; Did the user press the up arrow key? bne @end ; lda #1 ; sta regd ; lda scr_str ; beq @end ; @shftup: jsr scrl_up ; lda #1 ; sta regd ; @end: rts ; isshftdown: lda regc ; Load the escape code back into the accumulator. cmp #'B' ; Did the user press the down arrow key? bne @end ; lda #1 ; sta regd ; lda scr_end ; cmp #71 ; bcs @end ; @shftdown: jsr scrl_down ; lda #1 ; sta regd ; @end: rts ; update_ptr: lda scr_row ; Add the cursor's line number, add scr_str ; with the starting line number to get the absolute line number. mul #maxcol+1 ; Multiply the line number by the screen's max column count, plus 1. add scr_col ; Add the cursor's column number to get the screen index. sta.w scr_ptr ; Save the screen index. ; cmp.w #$2000 ; Is the index greater than, or equal to the end of the screen buffer? ; bcc @end ; No, so we're done. ;@wrap: ; and #0 ; Reset the screen's starting line. ; sta scr_str ; ; sta regf ; Setup the starting line for rdrw_ln. ; lda #maxrow ; Reset the screen's ending line. ; sta scr_end ; ; sta rege ; Setup the ending line for rdrw_ln. ; jsr rdrw_ln ; Redraw the entire screen. ; bra update_ptr ; Get the screen index. @end: rts ; End of update_ptr. update_pos: phb.q ; Preserve B. and #0 ; Reset A. tab ; Reset B. ldb #1 ; Set the F pseudo register to one, to fix some bugs. stb regf ; jsr update_ptr ; Update the screen buffer index. tay ; Place the index into the Y register. tba ; Reset A. mov scr, #'\e' ; Print an escape character to the screen. mov scr, #'[' ; Print '[' to the screen, and start the escape sequence. jsr getrow ; Start printing the row number to the screen. mov scr, #';' ; Print ';' to the screen. jsr getcol ; Start printing the column number to the screen. mov scr, #'H' ; Print 'H' to the screen. plb.q ; Restore B. rts ; End of update_pos. getrow: lda scr_row ; Get the cursor's y coordinate. bra bcd ; Convert it to BCD. getcol: lda scr_col ; Get the cursor's x coordinate. bcd: inc ; Add one to A. 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. mov scr, #'\e' ; Print an escape character to the screen. mov scr, #'[' ; Print '[' to the screen, and start the escape sequence. mov scr, #'T' ; Print 'T' to the screen, and end the escape sequence. lda scr_row ; Get the cursor's line number. pha ; Save it in the stack. lda wrapped ; Was the wrapped flag set? beq @save ; Yes, so save the cursor position. @redraw: lea d, (buffer) ; Get the screen buffer. 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. bra @end ; No, so we're done. @save: lda scr_col ; Get the cursor's column number. pha ; Save it in the stack. bra @redraw ; Start redrawing the current row. @load: pla ; Get the cursor's previous column number back. sta scr_col ; @end: pla ; 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 ; mov scr, #'\e' ; Print an escape character to the screen. mov scr, #'[' ; Print '[' to the screen, and start the escape sequence. mov scr, #'S' ; Print 'S' to the screen, and end the escape sequence. lda scr_row ; pha ; lda scr_col ; pha ; lda #0 ; sta scr_row ; lea d, (buffer) ; Get the screen buffer. jsr rdrw_row ; pla ; sta scr_col ; pla ; sta scr_row ; jsr update_pos ; @end: rts ; rdrw_row: pha.q ; Preserve A. phb.q ; Preserve B. stz scr_col ; Reset the column position. jsr update_pos ; Update the cursor position. xor b, b ; Reset B. tya ; Get the screen index. tab ; add b, #maxcol+1; Get the end of the row plus one. @loop: cmp (d+a), #0 ; Is this a null terminator? mne scr, (d+a) ; No, so print the character. meq scr, #' ' ; Yes, so print a space. inc ; Increment the screen index. cmp b ; Is the column position at, or above the maximum column count? bcc @loop ; No, so keep looping. @end: stz scr_col ; Reset the column position. jsr update_pos ; Update the cursor position. plb.q ; Restore B. pla.q ; Restore A. rts ; End of rdrw_row. rdrw_ln: pha.q ; Preserve A. psh scr_row ; Preserve the row position. psh scr_col ; Preserve the column position. mov scr_row, s ; Set the row position to the starting position. jsr update_pos ; Update the cursor position. mov a, d ; Get the ending position. lea d, (buffer) ; Get the address of the screen buffer. @loop: cmp scr_row, a ; Is the row position at, or below the ending position? beq @redraw ; Yes, so redraw the row. bcs @end ; No, so we're done. @redraw: jsr rdrw_row ; Redraw the line. @incr: inc scr_row ; Increment the row position. bra @loop ; Keep looping @end: pul scr_col ; Restore the column position. pul scr_row ; Restore the row position. jsr update_pos ; Update the cursor position. pla.q ; Restore A. rts ; End of rdrw_ln. 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. bra @end ; We are done. @ptr2: stb.q ptr2 ; Reset the second pointer. sta.q ptr2 ; Set the second pointer. bra @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.