Files
open-roms/c64/basic/print_packed_message.s
T

229 lines
3.7 KiB
ArmAsm

;; This routine prints messages that have been packed
;; using the make_error_tables program.
;; The general idea is to save space in the ROM.
;; The output of make_error_tables is written to packed_messages.s, and
;; contains the following:
;;
;; packed_message_words - List of nybl packed words.
;; packed_message_tokens - List of tokens that get joined to make messages
;; packed_message_chars - List of characters in messages sorted by frequency.
print_packed_message:
;; X = message number
lda #$ff
ldy #$ff
packed_message_search:
iny
cpx #$00
beq found_message_in_token_stream
lda packed_message_tokens,y
cmp #$ff
bne +
dex
*
cpy #$ff
bne packed_message_search
;; Could not find message
sec
rts
found_message_in_token_stream:
;; Now print each word in the message
tya
pha
lda packed_message_tokens,y
cmp #$ff
beq +
jsr print_packed_word
lda #$20
jsr JCHROUT
pla
tay
iny
bne found_message_in_token_stream
*
pla
;; Rub out space at the end
lda #$14
jsr JCHROUT
rts
print_packed_word:
;; A = the word to print
tax
;; Setup pointer to packed words
lda #<packed_message_words
sta temp_string_ptr+0
lda #>packed_message_words
sta temp_string_ptr+1
;; Find the word in the list
ldy #$ff
packed_word_search:
iny
cpx #$00
beq found_packed_word
;; $x0 is an end of work marker
lda (temp_string_ptr),y
and #$0f
cmp #$00
bne +
dex
*
;; $FE $xx is an end of work marker
lda (temp_string_ptr),y
cmp #$fe
bne +
dex
iny ; skip next byte
*
cmp #$ff
bne +
iny ; skip next byte
*
;; Advance to next page if required
cpy #$ff
bne packed_word_search
inc temp_string_ptr+1
jmp packed_word_search
found_packed_word:
;; Get pointer to start of packed word
;; Make sure we don't wrap on a page boundary
tya
clc
adc temp_string_ptr+0
sta temp_string_ptr+0
lda temp_string_ptr+1
adc #$00
sta temp_string_ptr+1
print_packed_string:
ldy #$ff
next_packed_word_char:
;; Y = offset into packed word data - 1
iny
;; Check for end of word
lda (temp_string_ptr),y
cmp #$00
beq end_of_packed_word
cmp #$fe
beq last_literal
cmp #$ff
beq next_is_literal_char
and #$f0
beq end_of_packed_word
;; Check if it is an uncommon char
lda (temp_string_ptr),y
and #$f0
cmp #$f0
beq is_uncommon_char
;; Is not an uncommon char, so get char of upper nybl
lda (temp_string_ptr),y
;; Put high nybl into low bits of X
lsr
lsr
lsr
lsr
tax
;; Save Y so it doesn't get clobbered by CHROUT
tya
pha
;; X=1-14 = first 14 chars, so subtract one
lda packed_message_chars-1,x
jsr JCHROUT
;; See if there is a char in the low nybl to print
pla
tay
lda (temp_string_ptr),y
and #$0f
beq end_of_packed_word
cmp #$0f
beq no_lo_nybl_char
has_lo_nybl_char:
;; We need to print the low nybl char as well
tax
tya
pha
;; Skip lower nybls of $F or $0 in nybl packed
;; bytes, as these do not encode characters
cpx #$f
beq +
has_nybl:
cpx #0
beq +
;; X=1-14 = first 14 chars, so subtract one
lda packed_message_chars-1,x
jsr JCHROUT
*
pla
tay
;; FALL THROUGH
no_lo_nybl_char:
;; If current byte has $0F in low nybl, then the next
;; byte is a whole byte.
lda (temp_string_ptr),y
and #$0f
cmp #$0f
beq next_is_literal_char
ready_for_next_char:
cpy #$ff
bne next_packed_word_char
end_of_packed_word:
;; Hit end of packed data
rts
last_literal:
jsr unpack_literal_char
rts
next_is_literal_char:
jsr unpack_literal_char
jmp ready_for_next_char
unpack_literal_char:
;; Output the literal char, and ready for next char
iny
tya
pha
lda (temp_string_ptr),y
jsr JCHROUT
pla
tay
rts
is_uncommon_char:
;; Lower nybl has offset into low-frequency part of the table
lda (temp_string_ptr),y
and #$0f
clc
adc #14
;; We need to print the low nybl char as well
tax
tya
pha
jmp has_nybl