CHROUT screen output routine split, size and performance optimizations

This commit is contained in:
FeralChild64 committed 2019-10-09 18:45:37 +02:00
1 parent a442bf910f
commit 2cc6587b5c
8 files changed
+627 -521

No files matched your search

+16 -521
View File
@@ -14,285 +14,24 @@ chrout_screen:
lda SCHAR
tax
// Check for special characters
// All the PETSCII control codes are within $0x, $1x, $8x, $9x, remaining
// ones are always printable characters; separate away control codes
cmp #$00
bne not_00
jmp chrout_done
not_00:
// Linefeed (simply ignored)
// Trivia: BASIC does CRLF with READY. prompt
cmp #$0a
bne not_0a
jmp chrout_done
not_0a:
// Carriage return
cmp #$0d
bne not_0d
// RETURN clears quote and insert modes, it also clears reverse flag
lda #$00
sta QTSW
sta INSRT
sta RVS
jmp screen_advance_to_next_line
not_0d:
cmp #$94
bne not_94
// Insert (shift-DELETE)
// Abort if line already max length, ie 79th char is not a space
jsr get_current_line_logical_length
cmp #79
bne definitely_not_too_long
tay
lda (PNT),y
cmp #$20
beq definitely_not_too_long
// Line is too long to extend
jmp chrout_done
definitely_not_too_long:
// Work out if line needs to be expanded, and if so expand it
ldy #39
lda (PNT),y
cmp #$20
beq no_need_to_extend
jsr screen_grow_logical_line
no_need_to_extend:
// Shuffle chars towards end of line
jsr get_current_line_logical_length
tay
!:
// Note: While the following routine is obvious to any skilled
// in the art as the most obvious simple and efficient solution,
// if the screen writes are before the colour writes, it results
// in a relatively long verbatim stretch of bytes when compared to
// the C64 KERNAL. Thus we have swapped the order, just to reduce
// the potential for any argument of copyright infringement, even
// though we really don't believe that the routine can be copyrighted
// due to the lack of creativity.
dey
lda (USER),y
iny
sta (USER),y
dey
lda (PNT),y
iny
sta (PNT),y
dey
cpy PNTR
bne !-
// Increase insert mode count (which causes quote-mode like behaviour)
inc INSRT
// Put space in the inserted gap
lda #$20
sta (PNT),y
jmp chrout_done
not_94:
// DELETE in insert mode embeds control character
ldx INSRT
bne not_14
cmp #$14
bne not_14
// Delete
ldx PNTR
bne delete_non_zero_column
delete_at_column_0:
ldy TBLX
bne not_row_0
// delete from row 0, col 0 does nothing
jmp chrout_done
not_row_0:
// Column 0 delete just moves us to the end of the
// previous line, without actually deleting anything
dec TBLX
jsr get_current_line_logical_length
lda LNMX
sta PNTR
jsr calculate_screen_line_pointer
jmp chrout_done
delete_non_zero_column:
// Copy rest of line down
jsr get_current_line_logical_length
ldy PNTR
cpy LNMX
beq done_delete
dey
!:
iny
lda (PNT),y
dey
sta (PNT),y
iny
lda (USER),y
dey
sta (USER),y
iny
cpy LNMX
bne !-
// Clear char at end of line
jsr get_current_line_logical_length
tay
lda #$20
sta (PNT),y
done_delete:
dec PNTR
jmp chrout_done
not_14:
// Check for quote mode
ldx QTSW
bne is_quote_mode
ldx INSRT
bne is_quote_mode
jmp not_quote_mode
is_quote_mode:
// Is it a control code?
// control codes are $00-$1f and $80-$9f
// (from reading C64 PRG p379-381)
// so we can just check if bits 5 or 6 are set, and if so,
// then it isn't a control character.
pha
and #$60
bne !+
// Yes, a control code in quote mode means we display it as a reverse character
pla
// Low control codes are just +$80
clc
adc #$80
// If it overflowed, then it is a high control code,
// so we need to make it be $80 + $40 + char
// as we will have flipped back to just $00 + char, we should
// now add $c0 if C is set from overflow
bcc low_ctrl_char
adc #$bf // C=1, so adding $BF + C = add $C0
low_ctrl_char:
jmp output_literal_char
jmp chrout_screen_control
!:
pla
not_quote_mode:
txa
// Check for colours
ldx #$f
colour_check_loop:
cmp colour_codes,x
bne !+
stx COLOR
jmp chrout_done
!: dex
bpl colour_check_loop
// Compute's Mapping the 64 p38
cmp #$12
bne not_12
lda #$80
sta RVS
jmp chrout_done
not_12:
// Compute's Mapping the 64 p 38
cmp #$92
bne not_92
lda #$00
sta RVS
jmp chrout_done
not_92:
// Check for cursor movement keys
cmp #$11
bne not_11
lda PNTR
clc
adc #40
sta PNTR
// We need to advance the pointer manually, as normalising
// now will break things. The pointer update is required
// so that we can tell if we really are on the bottom phys
// screen line or not
jsr scroll_up_if_on_last_line
jsr calculate_screen_line_pointer
jmp chrout_done
not_11:
cmp #$1d
bne not_1d
inc PNTR
jsr calculate_screen_line_pointer
jmp chrout_done
not_1d:
cmp #$91
bne not_91
lda PNTR
sec
sbc #40
sta PNTR
jsr calculate_screen_line_pointer
jmp chrout_done
not_91:
cmp #$9d
bne not_9d
lda TBLX
ora PNTR
beq !+ // branch if top-left screen character
dec PNTR
jsr calculate_screen_line_pointer
!:
jmp chrout_done
not_9d:
// Home cursor
cmp #$13
bne not_13
lda #0
sta PNTR
sta TBLX
jsr calculate_screen_line_pointer
jmp chrout_done
not_13:
// Clear screen
cmp #$93
bne not_clearscreen
jsr clear_screen
jmp chrout_done
not_clearscreen:
// Convert PETSCII to screen code
// Don't print other control codes
cmp #$1f
bcs !+
jmp chrout_done
!:
// Literals - first convert PETSCII to screen code
// Codes $C0-$DF become $40-$5F
// But
cmp #$e0
cmp #$E0
bcs !+
cmp #$c0
cmp #$C0
bcc !+
and #$7f
and #$7F
jmp output_literal_char // not high char
!:
@@ -368,127 +107,9 @@ not_quote:
no_screen_advance_to_next_line:
jmp chrout_done
screen_grow_logical_line:
ldy TBLX
// Don't grow line if it is already grown
lda LDTBL,y
bpl !+
jmp not_last_line // doneb grow line
!:
lda #$80
sta LDTBL,y
// Now make space for the extra line added.
// If we are on the last physical line of the screen,
// Then we need to scroll the screen up
jsr scroll_up_if_on_last_line
// Scroll screen down to make space
// As we are scrolling down, we start from the end,
// and work backwards. We can't be as simple and efficient
// here as we are for scrolling up, because we don't know
// how much must be scrolled.
// Simple solution is to work out how many physical lines
// need shifting down, and then move lines at a time after
// initialising the pointers to the end area of the screen.
ldx #25-2
ldy #0
count_rows_loop:
dex
lda LDTBL,y
bpl !+
dex
!: iny
cpy TBLX
bne count_rows_loop
cpx #0
beq no_copy_down
bmi no_copy_down
// Set pointers to end of screen line, and one line
// above. (It is always one physical line, because
// this can only happen when expanding a line from 40 to
// 80 characters).
// XXX - This is not very efficient, and longer than it
// needs to be. Better would be to work out size to
// copy, and count it down in a pointer somewhere, so
// that loop iteration logic is simpler.
lda HIBASE
clc
adc #3
sta PNT+1
sta SAL+1
lda #>$DBC0
sta EAL+1
sta USER+1
lda #<$03C0
sta PNT+0
sta USER+0
// souce address is line above
sec
sbc #40
sta SAL+0
sta EAL+0
copy_line_down_loop:
ldy #39
cl_inner:
lda (EAL),y
sta (USER),y
lda (SAL),y
sta (PNT),y
dey
bpl cl_inner
// Decrement all pointers by 40
// Low bytes are in common pairs
// Old source is new destination
// Use different registers to minimise byte similarity with C64 KERNAl
ldy SAL+1
sty PNT+1
lda EAL+1
ldy SAL+0
sta USER+1
sty PNT+0
sty USER+0
// Decrementing source pointers
lda SAL+0
sec
sbc #<40
sta SAL+0
sta EAL+0
lda SAL+1
sbc #>40
sta SAL+1
// convert to screen equivalent
sec
sbc HIBASE
clc
adc #>$D800
sta EAL+1
dex
bne copy_line_down_loop
no_copy_down:
jsr calculate_screen_line_pointer
// Erase newly inserted line
ldy #79
!:
lda COLOR
sta (USER),y
lda #$20
sta (PNT),y
dey
cpy #40
bne !-
rts
not_last_line:
rts
@@ -607,6 +228,14 @@ link_copy:
rts
get_current_line_logical_length:
ldy TBLX
lda LDTBL,y
@@ -663,138 +292,4 @@ screen_advance_to_next_line:
!:
jsr calculate_screen_line_pointer
jmp chrout_done
add_40_to_screen_x:
lda PNTR
clc
adc #40
sta PNTR
rts
normalise_screen_x_y:
// Normalise X and Y values
// If X < 0, then make X = X + 40 (or 80, if previous line is linked)
!: lda PNTR
bpl x_not_negative
dec TBLX
// Check that we didn't go backwards off the top of the screen
bpl !+
lda #0
sta TBLX
!: jsr add_40_to_screen_x
// Check if line is linked, if so, add 40 again
ldy TBLX
lda LDTBL,y
bpl !+
jsr add_40_to_screen_x
!:
x_not_negative:
// Work out if X is too big
ldy TBLX
lda LDTBL,y
bpl !+
lda #79
.byte $2C // BIT $nnnn, used to skip next instruction
!: lda #39
cmp PNTR
bcs x_not_too_big
// X value is too big, so subtract 40 and increment Y
lda PNTR
sec
sbc #40
sta PNTR
inc TBLX
x_not_too_big:
// Make sure Y isn't negative
lda TBLX
bpl !+
lda #0
sta TBLX
!:
// Make sure Y isn't too large for absolute size of
// screen
cmp #24
bcc !+
lda #24
sta TBLX
!:
// Make sure Y isn't too much for the screen, taking
// into account the line link table
ldy #24 // max allowable line
ldx #0
link_count_loop:
lda LDTBL,x
bpl !+
dey
!: inx
cpx #25
bne link_count_loop
tya
cmp TBLX
bcs y_ok
sta TBLX
y_ok:
rts
calculate_screen_line_pointer:
jsr normalise_screen_x_y
// Reset pointer to start of screen
lda HIBASE
sta PNT+1
lda #0
sta PNT+0
// Add 40 for every line, or 80 if the lines are linked
ldx TBLX
!:
// Stop if we have counted enough lines
beq !+
// Add 40 or 80 based on whether the line is linked
// or not.
ldy #40
// -1 offset is because we count down from N to 1, not
// N-1 to 0.
lda LDTBL-1,x
bpl cslp_l1
ldy #80
cslp_l1:
// Add computed line length to pointer value
tya
clc
adc PNT+0
sta PNT+0
lda PNT+1
adc #0
sta PNT+1
// Loop back to next line
dex
jmp !-
!:
// FALL THROUGH
update_colour_line_pointer:
// Now setup pointer to colour RAM
lda PNT+0
sta USER+0
lda PNT+1
sec
sbc HIBASE
clc
adc #>$d800
sta USER+1
rts
+206
View File
@@ -0,0 +1,206 @@
//
// CHROUT routine - screen support, control codes
//
chrout_screen_control:
txa
// Order here is not random
// 1. First handle the ones that do not depend on quoote mode
// 2. Handle remaining control codes starting from the most commonly used
// in situations when speed might matter, we want to be
// as snappy as possible
chrout_try_RETURN:
cmp #$0D
bne !+
// RETURN clears quote and insert modes, it also clears reverse flag
lda #$00
sta QTSW
sta INSRT
sta RVS
jmp screen_advance_to_next_line
!:
chrout_try_DEL:
cmp #$14
bne !+
jmp chrout_screen_del
!:
chrout_try_quote:
lda QTSW
ora INSRT
beq !+
jmp chrout_screen_quote
!:
txa
chrout_try_CRSR_UP:
cmp #$91
bne !+
lda PNTR
sec
sbc #40
sta PNTR
jsr calculate_screen_line_pointer
jmp chrout_done
!:
chrout_try_CRSR_DOWN:
cmp #$11
bne !+
lda PNTR
clc
adc #40
sta PNTR
// We need to advance the pointer manually, as normalising
// now will break things. The pointer update is required
// so that we can tell if we really are on the bottom phys
// screen line or not
jsr scroll_up_if_on_last_line
jsr calculate_screen_line_pointer
jmp chrout_done
!:
chrout_try_CRSR_LEFT:
cmp #$9D
bne !+
lda TBLX
ora PNTR
beq chrout_screen_control_done // if top-left screen character
dec PNTR
jmp chrout_screen_control_calcptr_done
!:
chrout_try_CRSR_RIGHT:
cmp #$1D
bne !+
inc PNTR
jsr calculate_screen_line_pointer
jmp chrout_done
!:
chrout_try_RVS_ON:
cmp #$12
bne !+
lda #$80
sta RVS
bne chrout_screen_control_done // branch always
!:
chrout_try_RVS_OFF:
cmp #$92
bne !+
lda #$00
sta RVS
beq chrout_screen_control_done // branch always
!:
chrout_try_MODE_TXT:
cmp #$0E
bne !+
// XXX
jmp chrout_done
!:
chrout_try_MODE_GFX:
cmp #$8E
bne !+
// XXX
jmp chrout_done
!:
chrout_try_COLOR:
ldx #$0F
colour_check_loop:
cmp colour_codes,x
bne !+
stx COLOR
jmp chrout_done
!:
dex
bpl colour_check_loop
chrout_try_SHIFT_ENABLE:
cmp #$09
bne !+
// XXX
jmp chrout_done
!:
chrout_try_SHIFT_DISABLE:
cmp #$08
bne !+
// XXX
jmp chrout_done
!:
chrout_try_HOME:
cmp #$13
bne !+
// XXX try cursor_home instead
lda #$00
sta PNTR
sta TBLX
beq chrout_screen_control_calcptr_done // branch always
!:
chrout_try_CLR:
cmp #$93
bne !+
jsr clear_screen
jmp chrout_done
!:
chrout_try_INS:
cmp #$94
bne !+
jmp chrout_screen_ins
!:
chrout_try_RUN_STOP:
cmp #$03
bne !+
// XXX
jmp chrout_done
!:
chrout_try_FKEY:
// XXX
// FALLTROUGH
chrout_screen_control_done: // unknown, LF, or no more actions required // XXX to !csc_done
jmp chrout_done
chrout_screen_control_calcptr_done: // XXX to !csc_calcptr_done
jsr calculate_screen_line_pointer
jmp chrout_done
+63
View File
@@ -0,0 +1,63 @@
//
// CHROUT routine - screen support, DEL key handling
//
chrout_screen_del:
// In insert mode it embeds control character
ldx INSRT
beq !+
jmp chrout_screen_quote
!:
ldx PNTR
bne chrout_screen_del_column_non_0
// FALLTROUGH
chrout_screen_del_column_0:
ldy TBLX
beq chrout_screen_del_done // delete from row 0, col 0 does nothing
// Column 0 delete just moves us to the end of the
// previous line, without actually deleting anything
dec TBLX
jsr get_current_line_logical_length
lda LNMX
sta PNTR
jmp chrout_screen_control_calcptr_done
chrout_screen_del_column_non_0:
// Copy rest of line down
jsr get_current_line_logical_length
ldy PNTR
cpy LNMX
beq !++
dey
!:
iny
lda (PNT),y
dey
sta (PNT),y
iny
lda (USER),y
dey
sta (USER),y
iny
cpy LNMX
bne !-
// Clear char at end of line
jsr get_current_line_logical_length
tay
lda #$20
sta (PNT),y
!:
dec PNTR
chrout_screen_del_done:
jmp chrout_done
+64
View File
@@ -0,0 +1,64 @@
//
// CHROUT routine - screen support, INS key handling
//
chrout_screen_ins:
// Insert (shift-DELETE)
// Abort if line already max length, ie 79th char is not a space
jsr get_current_line_logical_length
cmp #79
bne !+
tay
lda (PNT),y
cmp #$20
beq !+
// Line is too long to extend
jmp chrout_done
!:
// Work out if line needs to be expanded, and if so expand it
ldy #39
lda (PNT),y
cmp #$20
beq !+
jsr screen_grow_logical_line
!:
// Shuffle chars towards end of line
jsr get_current_line_logical_length
tay
!:
// Note: While the following routine is obvious to any skilled
// in the art as the most obvious simple and efficient solution,
// if the screen writes are before the colour writes, it results
// in a relatively long verbatim stretch of bytes when compared to
// the C64 KERNAL. Thus we have swapped the order, just to reduce
// the potential for any argument of copyright infringement, even
// though we really don't believe that the routine can be copyrighted
// due to the lack of creativity.
dey
lda (USER),y
iny
sta (USER),y
dey
lda (PNT),y
iny
sta (PNT),y
dey
cpy PNTR
bne !-
// Increase insert mode count (which causes quote-mode like behaviour)
inc INSRT
// Put space in the inserted gap
lda #$20
sta (PNT),y
jmp chrout_done
+20
View File
@@ -0,0 +1,20 @@
//
// CHROUT routine - screen support, control codes in quote mode
//
chrout_screen_quote:
// Low control codes are just +$80
clc
adc #$80
// If it overflowed, then it is a high control code,
// so we need to make it be $80 + $40 + char
// as we will have flipped back to just $00 + char, we should
// now add $c0 if C is set from overflow
bcc !+
adc #$BF // C=1, so adding $BF + C = add $C0
!:
jmp output_literal_char
@@ -0,0 +1,54 @@
calculate_screen_line_pointer: // XXX rename to screen_calculate_line_pointer
jsr screen_normalize_xy
// Reset pointer to start of screen
lda HIBASE
sta PNT+1
lda #0
sta PNT+0
// Add 40 for every line, or 80 if the lines are linked
ldx TBLX
!:
// Stop if we have counted enough lines
beq !+
// Add 40 or 80 based on whether the line is linked
// or not.
ldy #40
// -1 offset is because we count down from N to 1, not
// N-1 to 0.
lda LDTBL-1,x
bpl cslp_l1
ldy #80
cslp_l1:
// Add computed line length to pointer value
tya
clc
adc PNT+0
sta PNT+0
lda PNT+1
adc #0
sta PNT+1
// Loop back to next line
dex
jmp !-
!:
// FALLTHROUGH
update_colour_line_pointer:
// Now setup pointer to colour RAM
lda PNT+0
sta USER+0
lda PNT+1
sec
sbc HIBASE
clc
adc #>$d800
sta USER+1
rts
@@ -0,0 +1,122 @@
screen_grow_logical_line:
ldy TBLX
// Don't grow line if it is already grown
lda LDTBL,y
bpl !+
jmp not_last_line // doneb grow line
!:
lda #$80
sta LDTBL,y
// Now make space for the extra line added.
// If we are on the last physical line of the screen,
// Then we need to scroll the screen up
jsr scroll_up_if_on_last_line
// Scroll screen down to make space
// As we are scrolling down, we start from the end,
// and work backwards. We can't be as simple and efficient
// here as we are for scrolling up, because we don't know
// how much must be scrolled.
// Simple solution is to work out how many physical lines
// need shifting down, and then move lines at a time after
// initialising the pointers to the end area of the screen.
ldx #25-2
ldy #0
count_rows_loop:
dex
lda LDTBL,y
bpl !+
dex
!: iny
cpy TBLX
bne count_rows_loop
cpx #0
beq no_copy_down
bmi no_copy_down
// Set pointers to end of screen line, and one line
// above. (It is always one physical line, because
// this can only happen when expanding a line from 40 to
// 80 characters).
// XXX - This is not very efficient, and longer than it
// needs to be. Better would be to work out size to
// copy, and count it down in a pointer somewhere, so
// that loop iteration logic is simpler.
lda HIBASE
clc
adc #3
sta PNT+1
sta SAL+1
lda #>$DBC0
sta EAL+1
sta USER+1
lda #<$03C0
sta PNT+0
sta USER+0
// souce address is line above
sec
sbc #40
sta SAL+0
sta EAL+0
copy_line_down_loop:
ldy #39
cl_inner:
lda (EAL),y
sta (USER),y
lda (SAL),y
sta (PNT),y
dey
bpl cl_inner
// Decrement all pointers by 40
// Low bytes are in common pairs
// Old source is new destination
// Use different registers to minimise byte similarity with C64 KERNAl
ldy SAL+1
sty PNT+1
lda EAL+1
ldy SAL+0
sta USER+1
sty PNT+0
sty USER+0
// Decrementing source pointers
lda SAL+0
sec
sbc #<40
sta SAL+0
sta EAL+0
lda SAL+1
sbc #>40
sta SAL+1
// convert to screen equivalent
sec
sbc HIBASE
clc
adc #>$D800
sta EAL+1
dex
bne copy_line_down_loop
no_copy_down:
jsr calculate_screen_line_pointer
// Erase newly inserted line
ldy #79
!:
lda COLOR
sta (USER),y
lda #$20
sta (PNT),y
dey
cpy #40
bne !-
rts
+82
View File
@@ -0,0 +1,82 @@
//
// Normalise X and Y values
// If X < 0, then make X = X + 40 (or 80, if previous line is linked)
//
screen_normalize_xy:
lda PNTR
bpl x_not_negative
dec TBLX
// Check that we didn't go backwards off the top of the screen
bpl !+
lda #0
sta TBLX
!: jsr add_40_to_screen_x
// Check if line is linked, if so, add 40 again
ldy TBLX
lda LDTBL,y
bpl !+
jsr add_40_to_screen_x
!:
x_not_negative:
// Work out if X is too big
ldy TBLX
lda LDTBL,y
bpl !+
lda #79
.byte $2C // BIT $nnnn, used to skip next instruction
!: lda #39
cmp PNTR
bcs x_not_too_big
// X value is too big, so subtract 40 and increment Y
lda PNTR
sec
sbc #40
sta PNTR
inc TBLX
x_not_too_big:
// Make sure Y isn't negative
lda TBLX
bpl !+
lda #0
sta TBLX
!:
// Make sure Y isn't too large for absolute size of
// screen
cmp #24
bcc !+
lda #24
sta TBLX
!:
// Make sure Y isn't too much for the screen, taking
// into account the line link table
ldy #24 // max allowable line
ldx #0
link_count_loop:
lda LDTBL,x
bpl !+
dey
!: inx
cpx #25
bne link_count_loop
tya
cmp TBLX
bcs y_ok
sta TBLX
y_ok:
rts
add_40_to_screen_x:
lda PNTR
clc
adc #40
sta PNTR
rts