Skip to content

Commit c577a01

Browse files
committed
Add PRINT64 library
1 parent 27a63fa commit c577a01

1 file changed

Lines changed: 322 additions & 0 deletions

File tree

docs/library/print64.bas.md

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
#Print64.bas
2+
3+
The 64 column printing routine allows text to be 4 pixels wide instead of 8.
4+
It is NOT proportional printing, but this is still useful for lining things up in columns.
5+
6+
This routine has been adopted as an included library - so you may include it with
7+
8+
```
9+
#include <print64.bas>
10+
```
11+
12+
##Usage
13+
14+
```
15+
printat64(y,x)
16+
```
17+
18+
Moves the print64 system's print cursor to row Y, column X. Note that `0 <= x <= 63` - that is the range of values
19+
for X can be up to 63. The range of values for Y is the normal 0-23.
20+
21+
* Note that the print64 system's cursor position is independent from that of the ZX Basic Print routine,
22+
or any other, such as the print42 system.
23+
24+
```
25+
printat64(STRING)
26+
```
27+
28+
29+
Prints the string to the screen at the current Print64 co-ordinates. It does so in the current permanent colours.
30+
31+
NOTE: The ZX Spectrum's attribute system is encoded into the hardware as a 32 character grid. Print64 does its best,
32+
but changing the paper/bright/flash colour from the background is likely to look imperfect as the attribute
33+
blocks cannot line up well with the pixel blocks.
34+
35+
##CODE
36+
* There is a version of this code included with the compiler
37+
(though the version listed here may or may not be more recent). Code converted to ZXBasic by Britlion,
38+
based on Andrew Owen's 64 Character code http://www.worldofspectrum.org/forums/showpost.php?p=167447&postcount=1
39+
40+
41+
```
42+
SUB printat64 (y as uByte, x as uByte)
43+
IF y<24 AND x<64 then
44+
POKE @p64coords,x
45+
POKE @p64coords+1,y
46+
ELSE
47+
asm
48+
rst 8 ; error "5 Out of screen"
49+
defb 4
50+
end asm
51+
END IF
52+
END SUB
53+
54+
55+
SUB print64 (characters$ as String)
56+
ASM
57+
58+
; This frankencode created by Paul Fisher, Andrew Owen, Chris Born and Einar Saukas
59+
; TODO:
60+
; * Inverse
61+
; * Bold (which will use a Second font)
62+
63+
LD L,(IX+4)
64+
LD H,(IX+5) ; Get String address of characters$ into HL.
65+
66+
; Load BC with length of string, and move HL to point to first character.
67+
ld c, (hl) ; 60020 78
68+
inc hl ; 60021 35
69+
ld b, (hl) ; 60022 70
70+
inc hl ; 60023 35
71+
72+
; Test string length. If Zero, exit.
73+
ld a, c ; 60024 121
74+
or b ; 60025 176
75+
jp z, p64_END ; 60026 200
76+
77+
examineChar:
78+
ld a, (hl) ; Grab the character
79+
cp 128 ; too high to print?
80+
jr nc, nextChar ; then we go to next.
81+
82+
newLine:
83+
cp 13 ; Is this a newline character? 60056 254 13
84+
jr nz, p64_isPrintable ; If not, hop to testing to see if we can print this 60058 32 13
85+
push hl
86+
push bc
87+
ld b,0
88+
ld hl, p64_coords ; Get coords 60060 237 91 68 235
89+
call BLp64_NEXT_ROW ; Go to next line. ; 60064 205 58 235
90+
pop bc
91+
pop hl
92+
93+
ld (p64_coords), de ; 60067 237 83 68 235
94+
jr nextChar ; 60071 24 11
95+
96+
p64_isPrintable:
97+
cp 31 ; Bigger than 31? 60073 254 31
98+
jr c, nextChar ; If not, get the next one. 60075 56 7
99+
100+
push hl ; Save position 60077 229
101+
push bc ; Save Count 60078 197
102+
call p64_PrintChar ; Call Print SubRoutine
103+
104+
105+
106+
pop bc ; Recover length count 60082 193
107+
pop hl ; Recover Position 60083 225
108+
109+
nextChar:
110+
inc hl ; Point to next character 60084 35
111+
dec bc ; Count off this character 60085 11
112+
ld a, b ; Did we run out? 60086 120
113+
or c ; 60087 177
114+
jr nz, examineChar ; If not, examine the next one 60088 32 193
115+
jp p64_END ; Otherwise hop to END. 60090 201
116+
117+
p64_PrintChar:
118+
; Arrives with A as a byte to print.
119+
ld hl,p64_coords
120+
push hl ; save COL address for later
121+
ld e, a ; store character value in E
122+
ld b,0
123+
ld c, (hl) ; store current column in BC
124+
125+
; Check if character font must be rotated, self-modifying the code accordingly
126+
127+
xor c ; compare BIT 0 from character value and column
128+
rra
129+
ld a, 256-(BLp64_END_LOOP-BLp64_SKIP_RLC) ; instruction DJNZ skipping rotation
130+
jr nc, BLp64_NOT_RLC ; decide based on BIT 0 comparison
131+
ld a, 256-(BLp64_END_LOOP-BLp64_INIT_RLC) ; instruction DJNZ using rotation
132+
133+
BLp64_NOT_RLC:
134+
ld (BLp64_END_LOOP - 1), a ; modify DJNZ instruction directly
135+
136+
; Check the half screen byte to be changed, self-modifying the code accordingly
137+
srl c ; check BIT 0 from current column
138+
ld a, %00001111 ; mask to change left half of the screen byte
139+
jr nc, BLp64_SCR_LEFT ; decide based on odd or even column
140+
cpl ; mask to change right half of the screen byte
141+
142+
BLp64_SCR_LEFT:
143+
ld (BLp64_SCR_MASK + 1), a ; modify screen mask value directly
144+
cpl
145+
ld (BLp64_FONT_MASK + 1), a ; modify font mask value directly
146+
147+
; Calculate location of the first byte to be changed on screen
148+
; The row value is a 5 bits value (0-23), here represented as %000RRrrr
149+
; The column value is a 6 bits value (0-63), here represented as %00CCCCCc
150+
; Formula: 0x4000 + ((row & 0x18) << 8) + ((row & 0x07) << 5) + (col >> 1)
151+
152+
inc hl ; now HL references ROW address
153+
ld a, (hl) ; now A = %000RRrrr
154+
call 0e9eh ; now HL = %010RR000rrr00000
155+
add hl, bc ; now HL = %010RR000rrrCCCCC
156+
ex de, hl ; now DE = %010RR000rrrCCCCC
157+
; and e=char -> l=char
158+
159+
; Calculate location of the character font data in p64_charset
160+
; Formula: p64_charset + 7 * INT ((char-32)/2) - 1
161+
162+
ld h, b ; now HL = char (because b=0)
163+
srl l ; now HL = INT (char/2)
164+
ld c, l ; now BC = INT (char/2)
165+
add hl, hl ; now HL = 2 * INT (char/2)
166+
add hl, hl ; now HL = 4 * INT (char/2)
167+
add hl, hl ; now HL = 8 * INT (char/2)
168+
sbc hl, bc ; now HL = 7 * INT (char/2)
169+
ld bc, p64_charset - 71h
170+
add hl, bc ; now HL = p64_charset + 7 * INT (char/2) - 0x71
171+
172+
173+
; Main loop to copy 8 font bytes into screen (1 blank + 7 from font data)
174+
xor a ; first font byte is always blank
175+
ld b, 8 ; execute loop 8 times
176+
177+
BLp64_INIT_RLC:
178+
rlca ; switch position between bits 0-3 and bits 4-7
179+
rlca
180+
rlca
181+
rlca
182+
183+
BLp64_SKIP_RLC:
184+
185+
; -----------------------------------------------------------------------------
186+
; STANDARD OR INVERSE
187+
;
188+
BLp64_INV_C: nop ; either 'NOP' or 'CPL' (modified)
189+
; -----------------------------------------------------------------------------
190+
191+
BLp64_FONT_MASK:
192+
and %11110000 ; mask half of the font byte
193+
ld c, a ; store half of the font byte in C
194+
ld a, (de) ; get screen byte
195+
196+
BLp64_SCR_MASK:
197+
and %00001111 ; mask half of the screen byte
198+
or c ; combine half screen and half font
199+
ld (de), a ; write result back to screen
200+
inc d ; next screen location
201+
inc hl ; next font data location
202+
ld a, (hl) ; store next font byte in A
203+
djnz BLp64_INIT_RLC ; repeat loop 8 times (this instruction gets modified)
204+
205+
BLp64_END_LOOP:
206+
; attributes
207+
ld de,(p64_coords) ; grab coords
208+
and a ; clear carry
209+
rr e ; divide x by 2 to get bytes instead of nybbles
210+
ld a, d ; Get Y coord
211+
sra a ;
212+
sra a ;
213+
sra a ; Multiply by 8 60155 203 47
214+
add a, 88 ; Add to attrbute base address
215+
ld h, a ; Put high byte value for attribute into H.
216+
ld a, d ; get y value again
217+
and 7 ; set within third
218+
rrca ;
219+
rrca ;
220+
rrca ;
221+
add a, e ; add in x value
222+
ld l, a ; Put low byte for attribute into l
223+
ld a, (23693) ; Get permanent Colours from System Variable
224+
ld (hl), a ; Write new attribute
225+
226+
pop hl ; restore AT_COL address
227+
inc (hl) ; next column
228+
bit 6, (hl) ; column lower than 64?
229+
ret z ; return if so
230+
231+
BLp64_NEXT_ROW:
232+
ld (hl), b ; reset AT_COL
233+
inc hl ; store AT_ROW address in HL
234+
inc (hl) ; next row
235+
ld a, (hl)
236+
cp 24 ; row lower than 23?
237+
ret c ; return if so
238+
ld (hl), b ; reset AT_ROW
239+
ret ; done!
240+
241+
242+
end asm
243+
p64coords:
244+
asm
245+
p64_coords:
246+
defb 0; X Coordinate store
247+
defb 0; Y Coordinate Store
248+
249+
p64_charset: ; 60230
250+
DEFB 2,2,2,2,0,2,0 ; Space !
251+
DEFB 80,82,7,2,7,2,0 ; " #
252+
DEFB 37,113,66,114,20,117,32 ; $ %
253+
DEFB 34,84,32,96,80,96,0 ; & '
254+
DEFB 36,66,66,66,66,36,0 ; ( )
255+
DEFB 0,82,34,119,34,82,0 ; * +
256+
DEFB 0,0,0,7,32,32,64 ; , -
257+
DEFB 1,1,2,2,100,100,0 ; . /
258+
DEFB 34,86,82,82,82,39,0 ; 0 1
259+
DEFB 34,85,18,33,69,114,0 ; 2 3
260+
DEFB 87,84,118,17,21,18,0 ; 4 5
261+
DEFB 55,65,97,82,84,36,0 ; 6 7
262+
DEFB 34,85,37,83,85,34,0 ; 8 9
263+
DEFB 0,2,32,0,34,2,4 ; : ;
264+
DEFB 0,16,39,64,39,16,0 ; < =
265+
DEFB 2,69,33,18,32,66,0 ; > ?
266+
DEFB 98,149,183,181,133,101,0 ; @ A
267+
DEFB 98,85,100,84,85,98,0 ; B C
268+
DEFB 103,84,86,84,84,103,0 ; D E
269+
DEFB 114,69,116,71,69,66,0 ; F G
270+
DEFB 87,82,114,82,82,87,0 ; H I
271+
DEFB 53,21,22,21,85,37,0 ; J K
272+
DEFB 69,71,71,69,69,117,0 ; L M
273+
DEFB 82,85,117,117,85,82,0 ; N O
274+
DEFB 98,85,85,103,71,67,0 ; P Q
275+
DEFB 98,85,82,97,85,82,0 ; R S
276+
DEFB 117,37,37,37,37,34,0 ; T U
277+
DEFB 85,85,85,87,39,37,0 ; V W
278+
DEFB 85,85,37,82,82,82,0 ; X Y
279+
DEFB 119,20,36,36,68,119,0 ; Z [
280+
DEFB 71,65,33,33,17,23,0 ; \ ]
281+
DEFB 32,112,32,32,32,47,0 ; ^ _
282+
DEFB 32,86,65,99,69,115,0 ; £ a
283+
DEFB 64,66,101,84,85,98,0 ; b c
284+
DEFB 16,18,53,86,84,35,0 ; d e
285+
DEFB 32,82,69,101,67,69,2 ; f g
286+
DEFB 66,64,102,82,82,87,0 ; h i
287+
DEFB 20,4,53,22,21,85,32 ; j k
288+
DEFB 64,69,71,71,85,37,0 ; l m
289+
DEFB 0,98,85,85,85,82,0 ; n o
290+
DEFB 0,99,85,85,99,65,65 ; p q
291+
DEFB 0,99,84,66,65,70,0 ; r s
292+
DEFB 64,117,69,69,85,34,0 ; t u
293+
DEFB 0,85,85,87,39,37,0 ; v w
294+
DEFB 0,85,85,35,81,85,2 ; x y
295+
DEFB 0,113,18,38,66,113,0 ; z {
296+
DEFB 32,36,34,35,34,36,0 ; | {
297+
DEFB 6,169,86,12,6,9,6 ; ~ (c)
298+
299+
p64_END:
300+
End Asm
301+
End Sub
302+
```
303+
304+
There's an example of usage here:
305+
306+
```
307+
REM Example
308+
309+
DIM n,x,y as uInteger
310+
CLS
311+
312+
FOR n=1 to 1000
313+
y=rnd*23
314+
x=rnd*62
315+
316+
ink rnd*8
317+
318+
printat64(y, x)
319+
print64 ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"(n MOD 26 TO n MOD 26))
320+
NEXT n
321+
END
322+
```

0 commit comments

Comments
 (0)