| Code: ; ----------------------------------------------------------------------------- ; FZX driver - Copyright (c) 2013 Einar Saukas ; -----------------------------------------------------------------------------
org 65000 ; driver address
FONT EQU 60000 ; font address
MARGIN EQU 0 ; left margin (in pixels)
STR_NUM EQU 4 ; stream #4
; ----------------------------------------------------------------------------- ; CREATE CHANNEL AND ATTACH STREAM
DRIVER: ld hl, ($5c53) ; store system variable PROG in HL dec hl ld bc, 5 ; allocate 5 bytes for channel below BASIC area push bc call $1655 ; call routine MAKE-ROOM pop bc ld hl, CH_DATA + 4 lddr ; copy CH_DATA to new channel space ld hl, ($5c4f) ; store system variable CHANS in HL ex de, hl inc hl inc hl ; now HL = allocated address + 1 sbc hl, de ; calculate offset between start of channels ; area and start of the new channel space ; (notice the carry flag was already cleared ; from executing CALL $1655 earlier) ld (STR_OFF), hl ; attach stream by storing channel address ; offset in streams table ret
STR_OFF EQU $5c10+((STR_NUM+3)*2) ; address of channel offset in streams table
CH_DATA: defw START ; address of the PRINT # routine defw $15c4 ; address of the INPUT # routine defb 'S' ; channel type 'S'
; ----------------------------------------------------------------------------- ; PROPORTIONAL PRINT ROUTINE
START: ld hl, P_FLAG ; initial address of local variables dec (hl) ; check P_FLAG value by decrementing it jp m, CHK_AT ; expecting a regular character? jr z, GET_COL ; expecting the AT column? GET_LIN: cpl add a, 192 ; now A = 191 - char inc hl GET_COL: inc hl ld (hl), a ret CHK_AT: cp 22 ; specified keyword 'AT'? jr nz, CHK_CR ld (hl), 2 ; change P_FLAG to expect line value next time ret CHK_CR: inc (hl) ; increment P_FLAG to restore previous value inc hl ld bc, FONT push bc pop ix cp 13 jp z, NEWLINE CHK_CHAR: dec a ; now A = char - 1 cp (ix+2) ; compare with lastchar jr nc, UNDEF_CHAR sub 31 ; now A = char - 32 jr nc, PRINT_CHAR UNDEF_CHAR: ld a, '?'-32 ; print '?' instead of invalid character PRINT_CHAR: inc a ; now A = char - 31 ld l, a ld h, 0 ld d, h ld e, l add hl, hl add hl, de ; now HL = (char - 31) * 3 add hl, bc ; now HL references offset/kern in char table ld e, (hl) inc hl ld a, (hl) and 63 ld d, a ; now DE = offset
xor (hl) rlca rlca ld c, a ; now C = kern
push hl add hl, de dec hl ; now HL = char definition address ex (sp), hl ; now HL references offset/kern in char table inc hl ; now HL references shift/width in char table xor a rld ; now A = char shift push af rld ; now A = (width - 1) ld (WIDTH1+1), a cp 8 ; check if char width is larger than 8 bits rld ; restore char shift/width
ld de, $000e ; same as "LD C,0" jr c, NARROW_CHAR ld de, $234e ; same as "LD C,(HL)" and "INC HL" NARROW_CHAR: ld (SMC), de ; self-modify code to handle narrow/large chars
inc hl ; now HL references next char offset ld a, (hl) ; now A = LSB of next char offset add a, l ld e, a ; now E = LSB of next char definition address
ld hl, P_COL ld a, (hl) sub c ; move left number of pixels specified by kern jr nc, ON_SCREEN ; stop moving if it would fall outside screen xor a ON_SCREEN: ld (hl), a
ld a, (WIDTH1+1) ; now A = (width - 1) add a, (hl) ; now A = (width - 1) + column call c, NEWLINE ; if char width won't fit then move to new line
ld bc, (P_COL) ld a, 1 sub (ix+0) ; now A = 1 - height add a, b ; now A = P_LIN - height + 1 jp nc, $0c86 ; call routine REPORT-5 ("Out of screen")
pop af ; now A = shift
add a, 191 ; range 0-191 call $22aa + 2 ; call PIXEL-ADD + 2 to calculate screen address ex af, af' ; now A' = (col % 8) jr CHK_LOOP
MAIN_LOOP: ld d, (hl) ; now D = 1st byte from char definition grid inc hl ; next character definition SMC: ld c, (hl) ; now C = 2nd byte from char definition or zero inc hl ; (either "LD C,0" or "LD C,(HL)" + "INC HL") xor a ; now A = zero (since there's no 3rd byte) ex (sp), hl ; now HL = screen address
ex af, af' ; now A = (col % 8), A' = 0 jr z, NO_ROTATE ld b, a ; now B = (col % 8) ex af, af' ; now A = 0, A' = (col % 8) ROTATE_PIXELS: srl d ; rotate right char definition grid in D,C,A rr c rra djnz ROTATE_PIXELS NO_ROTATE: inc l inc l or (hl) ld (hl), a ; put A on screen dec l ld a, c or (hl) ld (hl), a ; put C on screen dec l ld a, d or (hl) ld (hl), a ; put D on screen
inc h ; move screen address by 1 pixel down ld a, h and 7 jr nz, CHK_LOOP ld a, l add a, 32 ld l, a jr c, CHK_LOOP ld a, h sub 8 ld h, a CHK_LOOP: ex (sp), hl ; now HL = char definition address ld a, l cp e ; check if reached next char definition address jr nz, MAIN_LOOP ; loop otherwise
pop hl ; discard screen address from stack ld hl, P_COL ld a, (hl) ; now A = column WIDTH1: add a, 0 ; now A = column + (width - 1) scf adc a, (ix+1) ; now A = column + width + tracking jr nc, EXIT ; if didn't fall outside the screen then exit NEWLINE: ld (hl), MARGIN ; move to initial column at left margin inc hl ld a, (hl) ; now A = line sub (ix+0) ; now A = line - height EXIT: ld (hl), a ; move down a few pixels specified by height ret
P_FLAG: defb 0 P_COL: defb MARGIN P_LIN: defb 191
; -----------------------------------------------------------------------------
| |