|
| 1 | +'----------------------------------------------------------------------------- |
| 2 | +' FZX driver - Copyright (c) 2013 Einar Saukas |
| 3 | +' FZX format - Copyright (c) 2013 Andrew Owen |
| 4 | +' Ported to ZX Basic by Paul Fisher (@Britlion) |
| 5 | +' ----------------------------------------------------------------------------- |
| 6 | + |
| 7 | + |
| 8 | +#ifndef __PRINTFZX__ |
| 9 | +#define __PRINTFZX__ |
| 10 | + |
| 11 | +#pragma push(case_insensitive) |
| 12 | +#pragma case_insensitive = TRUE |
| 13 | + |
| 14 | + |
| 15 | +sub fastcall printFzxSetFontAddr(addr as Uinteger) |
| 16 | + ASM |
| 17 | + ld (__PRINTFZX_FONT_ADDR), hl |
| 18 | + END ASM |
| 19 | +end sub |
| 20 | + |
| 21 | + |
| 22 | +sub fastcall printFzxSetMargin(margin as ubyte) |
| 23 | + ASM |
| 24 | + ld (__PRINTFZX_MARGIN), a |
| 25 | + END ASM |
| 26 | +end sub |
| 27 | + |
| 28 | + |
| 29 | +sub fastcall printFzxAt(row as Ubyte, col as Ubyte) |
| 30 | + ASM |
| 31 | + push af |
| 32 | + ld a, 22 |
| 33 | + call _printFzxChar |
| 34 | + pop af |
| 35 | + call _printFzxChar |
| 36 | + pop hl |
| 37 | + ex (sp), hl |
| 38 | + ld a, h |
| 39 | + jp _printFzxChar |
| 40 | + END ASM |
| 41 | + DIM dummy as Uinteger = @printFzxChar |
| 42 | +end sub |
| 43 | + |
| 44 | + |
| 45 | +sub printFzxStr(s as String) |
| 46 | + ASM |
| 47 | + PROC |
| 48 | + |
| 49 | + LOCAL EXIT |
| 50 | + LOCAL LOOP |
| 51 | + |
| 52 | + ld l, (ix + 4) |
| 53 | + ld h, (ix + 5) |
| 54 | + ld a, h |
| 55 | + or l |
| 56 | + jr z, EXIT |
| 57 | + ld c, (hl) |
| 58 | + inc hl |
| 59 | + ld b, (hl) |
| 60 | + |
| 61 | +LOOP: |
| 62 | + ld a, b |
| 63 | + or c |
| 64 | + jr z, EXIT |
| 65 | + inc hl |
| 66 | + dec bc |
| 67 | + ld a, (hl) |
| 68 | + push hl |
| 69 | + push bc |
| 70 | + call _printFzxChar |
| 71 | + pop bc |
| 72 | + pop hl |
| 73 | + jr LOOP |
| 74 | + |
| 75 | +EXIT: |
| 76 | + ENDP |
| 77 | + END ASM |
| 78 | +end sub |
| 79 | + |
| 80 | + |
| 81 | +sub fastcall printFzxChar(char as ubyte) |
| 82 | + ASM |
| 83 | +; ----------------------------------------------------------------------------- |
| 84 | +; FZX driver - Copyright (c) 2013 Einar Saukas |
| 85 | +; FZX format - Copyright (c) 2013 Andrew Owen |
| 86 | +; ----------------------------------------------------------------------------- |
| 87 | + PROC |
| 88 | + LOCAL GET_LIN |
| 89 | + LOCAL GET_COL |
| 90 | + LOCAL CHK_AT |
| 91 | + LOCAL CHK_CR |
| 92 | + LOCAL CHK_CHAR |
| 93 | + LOCAL UNDEF_CHAR |
| 94 | + LOCAL PRINT_CHAR |
| 95 | + LOCAL NARROW_CHAR |
| 96 | + LOCAL ON_SCREEN |
| 97 | + LOCAL MAIN_LOOP |
| 98 | + LOCAL SMC |
| 99 | + LOCAL ROTATE_PIXELS |
| 100 | + LOCAL NO_ROTATE |
| 101 | + LOCAL CHK_LOOP |
| 102 | + LOCAL WIDTH1 |
| 103 | + LOCAL NEWLINE |
| 104 | + LOCAL EXIT |
| 105 | + |
| 106 | + LOCAL P_FLAG |
| 107 | + LOCAL P_COL |
| 108 | + LOCAL P_LIN |
| 109 | + |
| 110 | + LOCAL MARGIN |
| 111 | +MARGIN EQU 0 ; left margin (in pixels) |
| 112 | + |
| 113 | +__PRINTFZX_FONT_ADDR EQU CHK_CR + 5 |
| 114 | +__PRINTFZX_MARGIN EQU NEWLINE + 1 |
| 115 | + |
| 116 | + |
| 117 | +; ----------------------------------------------------------------------------- |
| 118 | +; ENTRY POINT #2 - PROPORTIONAL PRINT ROUTINE |
| 119 | +; ----------------------------------------------------------------------------- |
| 120 | + ld hl, P_FLAG ; initial address of local variables |
| 121 | + dec (hl) ; check P_FLAG value by decrementing it |
| 122 | + jp m, CHK_AT ; expecting a regular character? |
| 123 | + jr z, GET_COL ; expecting the AT column? |
| 124 | +GET_LIN: |
| 125 | + cpl |
| 126 | + add a, 192 ; now A = 191 - char |
| 127 | + inc hl |
| 128 | +GET_COL: |
| 129 | + inc hl |
| 130 | + ld (hl), a |
| 131 | + ret |
| 132 | +CHK_AT: |
| 133 | + cp 22 ; specified keyword 'AT'? |
| 134 | + jr nz, CHK_CR |
| 135 | + ld (hl), 2 ; change P_FLAG to expect line value next time |
| 136 | + ret |
| 137 | +CHK_CR: |
| 138 | + push ix |
| 139 | + inc (hl) ; increment P_FLAG to restore previous value |
| 140 | + inc hl |
| 141 | + ld bc, 0 ; Points to FONT ADDRESS |
| 142 | + push bc |
| 143 | + pop ix |
| 144 | + cp 13 |
| 145 | + jp z, NEWLINE |
| 146 | +CHK_CHAR: |
| 147 | + dec a ; now A = char - 1 |
| 148 | + cp (ix+2) ; compare with lastchar |
| 149 | + jr nc, UNDEF_CHAR |
| 150 | + sub 31 ; now A = char - 32 |
| 151 | + jr nc, PRINT_CHAR |
| 152 | +UNDEF_CHAR: |
| 153 | + ld a, '?'-32 ; print '?' instead of invalid character |
| 154 | +PRINT_CHAR: |
| 155 | + inc a ; now A = char - 31 |
| 156 | + ld l, a |
| 157 | + ld h, 0 |
| 158 | + ld d, h |
| 159 | + ld e, l |
| 160 | + add hl, hl |
| 161 | + add hl, de ; now HL = (char - 31) * 3 |
| 162 | + add hl, bc ; now HL references offset/kern in char table |
| 163 | + ld e, (hl) |
| 164 | + inc hl |
| 165 | + ld a, (hl) |
| 166 | + and 63 |
| 167 | + ld d, a ; now DE = offset |
| 168 | + |
| 169 | + xor (hl) |
| 170 | + rlca |
| 171 | + rlca |
| 172 | + ld c, a ; now C = kern |
| 173 | + |
| 174 | + push hl |
| 175 | + add hl, de |
| 176 | + dec hl ; now HL = char definition address |
| 177 | + ex (sp), hl ; now HL references offset/kern in char table |
| 178 | + inc hl ; now HL references shift/width in char table |
| 179 | + xor a |
| 180 | + rld ; now A = char shift |
| 181 | + push af |
| 182 | + rld ; now A = (width - 1) |
| 183 | + ld (WIDTH1+1), a |
| 184 | + cp 8 ; check if char width is larger than 8 bits |
| 185 | + rld ; restore char shift/width |
| 186 | + |
| 187 | + ld de, $000e ; same as "LD C,0" |
| 188 | + jr c, NARROW_CHAR |
| 189 | + ld de, $234e ; same as "LD C,(HL)" and "INC HL" |
| 190 | +NARROW_CHAR: |
| 191 | + ld (SMC), de ; self-modify code to handle narrow/large chars |
| 192 | + |
| 193 | + inc hl ; now HL references next char offset |
| 194 | + ld a, (hl) ; now A = LSB of next char offset |
| 195 | + add a, l |
| 196 | + ld e, a ; now E = LSB of next char definition address |
| 197 | + |
| 198 | + ld hl, P_COL |
| 199 | + ld a, (hl) |
| 200 | + sub c ; move left number of pixels specified by kern |
| 201 | + jr nc, ON_SCREEN ; stop moving if it would fall outside screen |
| 202 | + xor a |
| 203 | +ON_SCREEN: |
| 204 | + ld (hl), a |
| 205 | + |
| 206 | + ld a, (WIDTH1+1) ; now A = (width - 1) |
| 207 | + add a, (hl) ; now A = (width - 1) + column |
| 208 | + call c, NEWLINE ; if char width won't fit then move to new line |
| 209 | + |
| 210 | + ld bc, (P_COL) |
| 211 | + ld a, 1 |
| 212 | + sub (ix+0) ; now A = 1 - height |
| 213 | + add a, b ; now A = P_LIN - height + 1 |
| 214 | + jp nc, $0c86 ; call routine REPORT-5 ("Out of screen") |
| 215 | + |
| 216 | + pop af ; now A = shift |
| 217 | + |
| 218 | + add a, 191 ; range 0-191 |
| 219 | + call $22aa + 2 ; call PIXEL-ADD + 2 to calculate screen address |
| 220 | + ex af, af' |
| 221 | + ; now A' = (col % 8) |
| 222 | + jr CHK_LOOP |
| 223 | + |
| 224 | +MAIN_LOOP: |
| 225 | + ld d, (hl) ; now D = 1st byte from char definition grid |
| 226 | + inc hl ; next character definition |
| 227 | +SMC: |
| 228 | + ld c, (hl) ; now C = 2nd byte from char definition or zero |
| 229 | + inc hl ; (either "LD C,0" or "LD C,(HL)" + "INC HL") |
| 230 | + xor a ; now A = zero (since there's no 3rd byte) |
| 231 | + ex (sp), hl ; now HL = screen address |
| 232 | + |
| 233 | + ex af, af' |
| 234 | + ; now A = (col % 8), A' = 0 |
| 235 | + jr z, NO_ROTATE |
| 236 | + ld b, a ; now B = (col % 8) |
| 237 | + ex af, af' |
| 238 | + ; now A = 0, A' = (col % 8) |
| 239 | +ROTATE_PIXELS: |
| 240 | + srl d ; rotate right char definition grid in D,C,A |
| 241 | + rr c |
| 242 | + rra |
| 243 | + djnz ROTATE_PIXELS |
| 244 | + |
| 245 | +NO_ROTATE: |
| 246 | + inc l |
| 247 | + inc l |
| 248 | + or (hl) |
| 249 | + ld (hl), a ; put A on screen |
| 250 | + dec l |
| 251 | + ld a, c |
| 252 | + or (hl) |
| 253 | + ld (hl), a ; put C on screen |
| 254 | + dec l |
| 255 | + ld a, d |
| 256 | + or (hl) |
| 257 | + ld (hl), a ; put D on screen |
| 258 | + |
| 259 | + inc h ; move screen address by 1 pixel down |
| 260 | + ld a, h |
| 261 | + and 7 |
| 262 | + jr nz, CHK_LOOP |
| 263 | + ld a, l |
| 264 | + sub -32 |
| 265 | + ld l, a |
| 266 | + sbc a, a |
| 267 | + and -8 |
| 268 | + add a, h |
| 269 | + ld h, a |
| 270 | +CHK_LOOP: |
| 271 | + ex (sp), hl ; now HL = char definition address |
| 272 | + ld a, l |
| 273 | + cp e ; check if reached next char definition address |
| 274 | + jr nz, MAIN_LOOP ; loop otherwise |
| 275 | + |
| 276 | + pop hl ; discard screen address from stack |
| 277 | + ld hl, P_COL |
| 278 | + ld a, (hl) ; now A = column |
| 279 | +WIDTH1: |
| 280 | + add a, 0 ; now A = column + (width - 1) |
| 281 | + scf |
| 282 | + adc a, (ix+1) ; now A = column + width + tracking |
| 283 | + jr nc, EXIT ; if didn't fall outside the screen then exit |
| 284 | +NEWLINE: |
| 285 | + ld (hl), MARGIN ; move to initial column at left margin |
| 286 | + inc hl |
| 287 | + ld a, (hl) ; now A = line |
| 288 | + sub (ix+0) ; now A = line - height |
| 289 | +EXIT: |
| 290 | + ld (hl), a ; move down a few pixels specified by height |
| 291 | + pop ix |
| 292 | + ret |
| 293 | + |
| 294 | +P_FLAG: |
| 295 | + defb 0 |
| 296 | +P_COL: |
| 297 | + defb MARGIN |
| 298 | +P_LIN: |
| 299 | + defb 191 |
| 300 | + ENDP |
| 301 | +; ----------------------------------------------------------------------------- |
| 302 | + END ASM |
| 303 | +end sub |
| 304 | + |
| 305 | +#pragma pop(case_insensitive) |
| 306 | + |
| 307 | +#endif |
0 commit comments