Posts: 805
Threads: 135
Joined: Apr 2009
Reputation:
5
Code: SUB FZXPrintAt(Y as uByte, X as uByte, printData as String)
DIM FZXi as uInteger=0
PRINT INK 0;FZXi: PAUSE 0
FZXPrintAChar(22) 'at
PRINT INK 1;FZXi: PAUSE 0
FZXPrintAChar(Y)
PRINT INK 2;FZXi: PAUSE 0
FZXPrintAChar(X)
PRINT INK 3;FZXi: PAUSE 0
PRINT LEN printData
FOR FZXi=0 to LEN printData-1
PRINT INK 4;FZXi: PAUSE 0
FZXPrintAChar(CODE printData(FZXi))
PRINT INK 5;FZXi: PAUSE 0
NEXT FZXi
END SUB
The first 3 calls to FZXPrintAChar work perfectly. Then we get to the loop part. It prints out 0 for FZXi and then prints the first letter of the string. Next time around the loop, FZXi becomes 33633!
But I'm not sure where?
Should I assume FZXPrintAChar does some stack corruption? This is just FZX from Einar Saukas (and friends) - and seems to work perfectly when called to print a single character. Even multiple times. But when looping, strange things happen.
The odd thing is it just seems to happen once. If I change the code to FZXPrintAChar(65) - it happily prints out letter A's in sequence beautifully. Except the first time through the loop, FZXi is set to 33633. It then proceeds to count upwards through 33634 33635 etc, as you'd expect for a loop variable.
Investigating as I type:
If I set the variable type to be a uByte, it gets set to 131 in the loop. (Which makes some sense, as the high byte of 33633 is 131 ) - but it isn't reset each time to 131, but is allowed to count upwards.
2 AM.
Time to quit for the night. Code dumped to <deleted> for the moment. - I fully accept the issue might be with the assembly module from someone else I've used!
EDIT: I think I see it. It's using IX in the routine. That will have to be changed!
Posts: 805
Threads: 135
Joined: Apr 2009
Reputation:
5
First Third pass, if you'd like to do testing:
(you'll also need an FXZ font; incbin at @FONT in asm context)
Code: SUB FZXSetFont (FontAddress as uInteger)
POKE UINTEGER @FZXFontPointer+1,FontAddress
RETURN
END SUB
SUB FZXPrintAt(Y as uByte, X as uByte, printData as String)
DIM FZXi as uByte=0
FZXPrintAChar(22) 'at
FZXPrintAChar(Y)
FZXPrintAChar(X)
IF LEN printData > 0 THEN
FOR FZXi=0 to LEN printData-1
FZXPrintAChar(CODE printData(FZXi))
NEXT FZXi
END IF
END SUB
SUB FZXPrint(printData as String)
DIM FZXi as uInteger
IF LEN printData > 0 THEN
FOR FZXi=0 to LEN printData-1
FZXPrintAChar(CODE printData(FZXi))
NEXT FZXi
END IF
END SUB
SUB FASTCALL FZXPrintAChar (character as uByte)
ASM
PUSH IX
CALL FZX_START
POP IX
RET
; -----------------------------------------------------------------------------
; 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
FZX_START:
ld hl, FZX_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
END ASM
FZXFontPointer:
ASM
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, FZX_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, (FZX_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, FZX_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
FZX_P_FLAG:
defb 0
FZX_P_COL:
defb MARGIN
FZX_P_LIN:
defb 191
FZX_END:
; -----------------------------------------------------------------------------
END ASM
END SUB
|