517 lines
9.8 KiB
ArmAsm
517 lines
9.8 KiB
ArmAsm
; Function defined on pp272-273 of C64 Programmers Reference Guide
|
|
chrout:
|
|
;; Crude implementation of character output
|
|
|
|
;; Save X and Y values
|
|
;; (Confirmed by writing a test program that X and Y
|
|
;; don't get modified, in agreement with C64 PRG's
|
|
;; description of CHROUT)
|
|
sta last_printed_character_ascii
|
|
txa
|
|
pha
|
|
tya
|
|
pha
|
|
|
|
jsr hide_cursor_if_visible
|
|
|
|
lda last_printed_character_ascii
|
|
tax
|
|
|
|
;; Check for special characters
|
|
|
|
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
|
|
jmp screen_advance_to_next_line
|
|
not_0d:
|
|
|
|
;; Check for quote mode
|
|
|
|
;; Check for colours
|
|
ldx #$f
|
|
colour_check_loop:
|
|
cmp colour_codes,x
|
|
bne +
|
|
stx text_colour
|
|
jmp chrout_done
|
|
* dex
|
|
bpl colour_check_loop
|
|
|
|
;; Check for cursor movement keys
|
|
cmp #$11
|
|
bne not_11
|
|
lda current_screen_x
|
|
clc
|
|
adc #40
|
|
sta current_screen_x
|
|
jsr calculate_screen_line_pointer
|
|
jmp chrout_done
|
|
not_11:
|
|
cmp #$1d
|
|
bne not_1d
|
|
inc current_screen_x
|
|
jsr calculate_screen_line_pointer
|
|
jmp chrout_done
|
|
not_1d:
|
|
cmp #$91
|
|
bne not_91
|
|
lda current_screen_x
|
|
sec
|
|
sbc #40
|
|
sta current_screen_x
|
|
jsr calculate_screen_line_pointer
|
|
jmp chrout_done
|
|
not_91:
|
|
cmp #$9d
|
|
bne not_9d
|
|
dec current_screen_x
|
|
jsr calculate_screen_line_pointer
|
|
jmp chrout_done
|
|
not_9d:
|
|
|
|
cmp #$14
|
|
bne not_14
|
|
|
|
;; Delete
|
|
ldx current_screen_x
|
|
bne delete_non_zero_column
|
|
delete_at_column_0:
|
|
ldy current_screen_y
|
|
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 current_screen_y
|
|
jsr get_current_line_logical_length
|
|
lda logical_line_length
|
|
|
|
sta current_screen_x
|
|
jsr calculate_screen_line_pointer
|
|
jmp chrout_done
|
|
|
|
delete_non_zero_column:
|
|
;; Copy rest of line down
|
|
jsr get_current_line_logical_length
|
|
ldy current_screen_x
|
|
cpy logical_line_length
|
|
beq done_delete
|
|
*
|
|
lda (current_screen_line_ptr),y
|
|
dey
|
|
sta (current_screen_line_ptr),y
|
|
iny
|
|
lda (current_screen_line_colour_ptr),y
|
|
dey
|
|
sta (current_screen_line_colour_ptr),y
|
|
iny
|
|
iny
|
|
cpy logical_line_length
|
|
bne -
|
|
done_delete:
|
|
dec current_screen_x
|
|
jmp chrout_done
|
|
|
|
not_14:
|
|
|
|
;; Home cursor
|
|
cmp #$13
|
|
bne not_13
|
|
lda #0
|
|
sta current_screen_x
|
|
sta current_screen_y
|
|
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
|
|
cmp #$40
|
|
bcc chrout_l1
|
|
cmp #$41+26
|
|
bcs chrout_l1
|
|
and #$1f
|
|
|
|
chrout_l1:
|
|
;; Write normal character on the screen
|
|
ldy current_screen_x
|
|
sta (current_screen_line_ptr),y
|
|
|
|
;; Set colour
|
|
lda text_colour
|
|
sta (current_screen_line_colour_ptr),y
|
|
|
|
;; Advance the column, and scroll screen down if we need
|
|
;; to insert a 2nd line in this logical line.
|
|
;; (eg Compute's Mapping the 64 p41)
|
|
ldx current_screen_y
|
|
iny
|
|
sty current_screen_x
|
|
cpy #40
|
|
bne no_screen_advance_to_next_line
|
|
jsr screen_grow_logical_line
|
|
cpy #79
|
|
bcc no_screen_advance_to_next_line
|
|
jmp screen_advance_to_next_line
|
|
no_screen_advance_to_next_line:
|
|
chrout_done:
|
|
;; Make cursor immediately visible
|
|
jsr show_cursor
|
|
|
|
;; Restore X and Y, set carry to mark success on exit
|
|
pla
|
|
tay
|
|
pla
|
|
tax
|
|
lda last_printed_character_ascii
|
|
clc ; indicate success
|
|
rts
|
|
|
|
screen_grow_logical_line:
|
|
ldy current_screen_y
|
|
;; Don't grow line if it is already grown
|
|
lda screen_line_link_table,y
|
|
bmi done_grow_line
|
|
|
|
lda #$80
|
|
sta screen_line_link_table,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
|
|
|
|
;; XXX - Scroll screen down to make space
|
|
;; XXX - And scroll up if required
|
|
|
|
|
|
done_grow_line:
|
|
not_last_line:
|
|
rts
|
|
|
|
scroll_up_if_on_last_line:
|
|
;; Colour RAM is always in fixed place, so is easiest
|
|
;; to use to check if we are on the last line.
|
|
;; The last line is at $D800 + 24*40 = $DBC0
|
|
lda current_screen_line_colour_ptr+0
|
|
cmp #<$DBC0
|
|
bne not_last_line
|
|
lda current_screen_line_colour_ptr+1
|
|
cmp #>$DBC0
|
|
bne not_last_line
|
|
|
|
dec current_screen_y
|
|
|
|
;; FALL THROUGH
|
|
|
|
scroll_screen_up:
|
|
;; Now scroll the whole screen up either one or two lines
|
|
;; based on whether the first screen line is linked or not.
|
|
|
|
jsr hide_cursor_if_visible
|
|
|
|
;; Get pointers to start of screen + colour RAM
|
|
lda HIBASE
|
|
sta current_screen_line_ptr+1
|
|
sta load_or_scroll_temp_pointer+1
|
|
lda #>$D800
|
|
sta current_screen_line_colour_ptr+1
|
|
sta load_save_verify_end_address+1
|
|
lda #$00
|
|
sta current_screen_line_ptr+0
|
|
sta current_screen_line_colour_ptr+0
|
|
|
|
;; Get pointers to screen/colour RAM source
|
|
lda screen_line_link_table+0
|
|
bmi +
|
|
lda #40
|
|
.byte $2C ; BIT $nnnn to skip next instruction
|
|
*
|
|
lda #80
|
|
sta load_or_scroll_temp_pointer+0
|
|
sta load_save_verify_end_address+0
|
|
|
|
;; Copy first three pages
|
|
ldy #$00
|
|
ldx #3
|
|
scroll_copy_loop:
|
|
lda (load_or_scroll_temp_pointer),y
|
|
sta (current_screen_line_ptr),y
|
|
lda (load_save_verify_end_address),y
|
|
sta (current_screen_line_colour_ptr),y
|
|
|
|
iny
|
|
bne scroll_copy_loop
|
|
|
|
inc load_or_scroll_temp_pointer+1
|
|
inc current_screen_line_ptr+1
|
|
inc load_save_verify_end_address+1
|
|
inc current_screen_line_colour_ptr+1
|
|
dex
|
|
bne scroll_copy_loop
|
|
|
|
;; Copy last partial page
|
|
;; We need to copy 1000-(3*256)-line length
|
|
;; = 232 - line length
|
|
lda 232
|
|
sec
|
|
sbc load_or_scroll_temp_pointer+0
|
|
tax
|
|
scroll_copy_loop2:
|
|
lda (load_or_scroll_temp_pointer),y
|
|
sta (current_screen_line_ptr),y
|
|
lda (load_save_verify_end_address),y
|
|
sta (current_screen_line_colour_ptr),y
|
|
iny
|
|
dex
|
|
bne scroll_copy_loop2
|
|
|
|
inc $d020
|
|
|
|
;; Shift line linkage list
|
|
ldy #0
|
|
ldx #24
|
|
link_copy:
|
|
lda screen_line_link_table+1,y
|
|
sta screen_line_link_table+0,y
|
|
iny
|
|
dex
|
|
bne link_copy
|
|
|
|
;; Now erase last line
|
|
lda HIBASE
|
|
clc
|
|
adc #3
|
|
sta current_screen_line_ptr+1
|
|
lda #>$DBC0
|
|
sta current_screen_line_colour_ptr+1
|
|
lda #$c0
|
|
sta current_screen_line_ptr+0
|
|
sta current_screen_line_colour_ptr+0
|
|
clear_current_physical_line:
|
|
ldy #39
|
|
* lda #$20
|
|
sta (current_screen_line_ptr),y
|
|
lda text_colour
|
|
sta (current_screen_line_colour_ptr),y
|
|
dey
|
|
bpl -
|
|
|
|
;; Restore correct line pointers
|
|
jsr calculate_screen_line_pointer
|
|
|
|
rts
|
|
|
|
get_current_line_logical_length:
|
|
ldy current_screen_y
|
|
lda screen_line_link_table,y
|
|
bpl line_not_linked_del
|
|
lda #79
|
|
.byte $2c ; BIT absolute mode, which we use to skip the next two instruction bytes
|
|
line_not_linked_del:
|
|
lda #39
|
|
sta logical_line_length
|
|
rts
|
|
|
|
screen_advance_to_next_line:
|
|
;; Go to start of line
|
|
lda #0
|
|
sta current_screen_x
|
|
;; Advance line number
|
|
ldy current_screen_y
|
|
inc current_screen_y
|
|
|
|
jsr calculate_screen_line_pointer
|
|
|
|
;; Work out if we have gone off the bottom of the screen?
|
|
;; 1040 > 1024, so if high byte of screen pointer is >= (HIBASE+4),
|
|
;; then we are off the bottom of the screen
|
|
lda current_screen_line_ptr+1
|
|
sec
|
|
sbc HIBASE
|
|
cmp #3
|
|
bcc +
|
|
|
|
;; Off the bottom of the screen
|
|
jsr scroll_screen_up
|
|
|
|
*
|
|
jmp chrout_done
|
|
|
|
add_40_to_screen_x:
|
|
lda current_screen_x
|
|
clc
|
|
adc #40
|
|
sta current_screen_x
|
|
rts
|
|
|
|
normalise_screen_x_y:
|
|
;; Normalise X and Y values
|
|
|
|
;; lda current_screen_x
|
|
;; sta $0400
|
|
;; lda current_screen_y
|
|
;; sta $0401
|
|
|
|
;; If X < 0, then make X = X + 40 (or 80, if previous line is linked)
|
|
* lda current_screen_x
|
|
bpl x_not_negative
|
|
dec current_screen_y
|
|
;; Check that we didn't go backwards off the top of the screen
|
|
bpl +
|
|
lda #0
|
|
sta current_screen_y
|
|
|
|
* jsr add_40_to_screen_x
|
|
|
|
;; Check if line is linked, if so, add 40 again
|
|
ldy current_screen_y
|
|
lda screen_line_link_table,y
|
|
bpl +
|
|
jsr add_40_to_screen_x
|
|
*
|
|
|
|
x_not_negative:
|
|
;; Work out if X is too big
|
|
ldy current_screen_y
|
|
lda screen_line_link_table,y
|
|
bpl +
|
|
lda #79
|
|
.byte $2C ; BIT $nnnn, used to skip next instruction
|
|
* lda #39
|
|
cmp current_screen_x
|
|
bcs x_not_too_big
|
|
|
|
;; X value is too big, so subtract 40 and increment Y
|
|
lda current_screen_x
|
|
sec
|
|
sbc #40
|
|
sta current_screen_x
|
|
inc current_screen_y
|
|
|
|
x_not_too_big:
|
|
|
|
;; Make sure Y isn't negative
|
|
lda current_screen_y
|
|
bpl +
|
|
lda #0
|
|
sta current_screen_y
|
|
*
|
|
;; Make sure Y isn't too large for absolute size of
|
|
;; screen
|
|
cmp #24
|
|
bcc +
|
|
lda #24
|
|
sta current_screen_y
|
|
*
|
|
;; Make sure Y isn't too much for the screen, taking
|
|
;; into account
|
|
|
|
|
|
;; lda current_screen_x
|
|
;; sta $0403
|
|
;; lda current_screen_y
|
|
;; sta $0404
|
|
rts
|
|
|
|
calculate_screen_line_pointer:
|
|
jsr normalise_screen_x_y
|
|
|
|
;; Reset pointer to start of screen
|
|
lda HIBASE
|
|
sta current_screen_line_ptr+1
|
|
lda #0
|
|
sta current_screen_line_ptr+0
|
|
|
|
;; Add 40 for every line, or 80 if the lines are linked
|
|
ldx current_screen_y
|
|
*
|
|
;; 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 screen_line_link_table-1,x
|
|
bpl cslp_l1
|
|
ldy #80
|
|
cslp_l1:
|
|
;; Add computed line length to pointer value
|
|
tya
|
|
clc
|
|
adc current_screen_line_ptr+0
|
|
sta current_screen_line_ptr+0
|
|
lda current_screen_line_ptr+1
|
|
adc #0
|
|
sta current_screen_line_ptr+1
|
|
|
|
;; Loop back to next line
|
|
dex
|
|
jmp -
|
|
*
|
|
|
|
;; FALL THROUGH
|
|
|
|
update_colour_line_pointer:
|
|
;; Now setup pointer to colour RAM
|
|
lda current_screen_line_ptr+0
|
|
sta current_screen_line_colour_ptr+0
|
|
lda current_screen_line_ptr+1
|
|
sec
|
|
sbc HIBASE
|
|
clc
|
|
adc #>$d800
|
|
sta current_screen_line_colour_ptr+1
|
|
|
|
rts
|
|
|
|
|
|
retreat_screen_pointer_40_bytes:
|
|
lda current_screen_line_ptr+0
|
|
sec
|
|
sbc #<40
|
|
sta current_screen_line_ptr+0
|
|
lda current_screen_line_ptr+1
|
|
sbc #>40
|
|
sta current_screen_line_ptr+1
|
|
|
|
jmp update_colour_line_pointer
|
|
|
|
advance_screen_pointer_40_bytes:
|
|
lda current_screen_line_ptr+0
|
|
clc
|
|
adc #<40
|
|
sta current_screen_line_ptr+0
|
|
lda current_screen_line_ptr+1
|
|
adc #>40
|
|
sta current_screen_line_ptr+1
|
|
|
|
jmp update_colour_line_pointer
|
|
|
|
colour_codes:
|
|
;; CHR$ codes for the 16 colours
|
|
.byte 144,5,28,159,156,30,31,158
|
|
.byte 129,149,150,151,152,153,154,155
|