Skip to content

Commit f7f624f

Browse files
committed
Add PutTile.bas library
1 parent 2041022 commit f7f624f

1 file changed

Lines changed: 301 additions & 0 deletions

File tree

docs/library/puttile.md

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
#PutTile
2+
3+
# putTile.bas
4+
5+
This subroutine takes a 2X2 tile of data from the given address and copies
6+
it to the screen co-ordinates at (x, y) - x and y in character addresses, where 0 <= x <= 31 and 0 <= y < =23.
7+
8+
Note that this uses pushes and pops to move the data, using the fastest known data moving algorithm for the Z80.
9+
As a consequence, while active it uses ALL the registers, including alternates and IY and IX as well as the
10+
Stack Pointer SP. It is kind enough to put these back for the purposes of exiting the subroutine
11+
though - ZX BASIC uses that register quite extensively.
12+
13+
Also, interrupts are disabled while the copying is happening. Considering that the stack pointer
14+
is likely pointing either at the screen or the tile data, an interrupt would be disastrous.
15+
If interrupts were enabled when the SUB is called, it should re-enable them again on exit.
16+
17+
Note the data format is across the tile - 2 bytes for the top row, then 2 bytes for the second row...and
18+
so on until there are 2 bytes for the 16th row. Then two bytes for the top two attributes, and 2 for the bottom.
19+
It uses 36 bytes of data, starting at the address given.
20+
21+
22+
```
23+
' Routine to place a 16 pixel by 16 pixel "Tile" onto the screen at character position x,y from adddress given.
24+
' Data must be in the format of 16 bit rows, followed by attribute data.
25+
' (c) 2010 Britlion, donated to the ZX BASIC project.
26+
' Thanks to Boriel, LCD and Na_than for inspiration behind this.
27+
28+
' This routine could be used as the basis for a fast sprite system, provided all sprites can be in 4 character blocks.
29+
' It can also be used to clean up dirty background (erase sprites), or put backgrounds from tiled blocks onto a screen.
30+
31+
' Note the comments about Self Modifying code should be ignored. This has been updated with IX+n methods, which overall are faster than accessing and changing the code.
32+
' (They would have to be accessed to change the memory anyway - may as well just access them directly.)
33+
34+
SUB putTile(x as uByte, y as uByte, graphicsAddr as uInteger)
35+
36+
ASM
37+
JP pt_start
38+
39+
ptstackSave:
40+
defb 0,0
41+
42+
pt_start:
43+
ld a,i
44+
push af ; Save interrupt status.
45+
46+
; Routine to save the background to the buffer
47+
48+
DI ; we really, really, REALLY can NOT be having interrupts while the stack and IX and IY are pointed elsewhere.
49+
50+
PUSH IX
51+
PUSH IY
52+
;ld HL, 65535 ; Self modifying code should load this with the graphics address.
53+
LD D,(IX+9)
54+
LD E,(IX+8)
55+
EX DE,HL
56+
57+
;; Print sprites routine
58+
LD (ptstackSave), SP ; Save Stack Pointer
59+
60+
LD SP,HL ; now SP points at the start of the graphics.
61+
62+
; This function returns the address into HL of the screen address
63+
ld a,(IX+5) ; Load in x - note the Self Modifying value
64+
ld IYH, a ; save it
65+
ld l,a
66+
ld a,(IX+7) ; Load in y - note the Self Modifying value
67+
ld IYL, a ; save it
68+
ld d,a
69+
and 24
70+
add a,64
71+
ld h,a
72+
ld a,d
73+
and 7
74+
rrca
75+
rrca
76+
rrca
77+
or l
78+
add a,2 ; Need to be to the right so backwards writing pushes land properly.
79+
ld l,a
80+
81+
; SO now, HL -> Screen address, and SP -> Graphics. Time to start loading.
82+
83+
POP BC ; Row 0
84+
POP DE ; row 1
85+
EX AF,AF'
86+
POP AF ; row 2
87+
EX AF,AF'
88+
EXX
89+
POP BC ; row 3
90+
POP DE ; row 4
91+
POP HL ; row 5
92+
EXX
93+
94+
; All right. We're loaded. Time to dump!
95+
96+
LD IX,0
97+
ADD IX,SP ; Save our stack pointer into IX
98+
99+
LD SP,HL ; point at the screen.
100+
PUSH BC ; row 0
101+
102+
INC H
103+
LD SP,HL
104+
PUSH DE ; row 1
105+
106+
INC H
107+
LD SP,HL
108+
EX AF,AF'
109+
PUSH AF ; row 2
110+
111+
INC H
112+
LD SP,HL
113+
EXX
114+
PUSH BC ; row 3
115+
EXX
116+
117+
INC H
118+
LD SP,HL
119+
EXX
120+
PUSH DE ; row 4
121+
EXX
122+
123+
INC H
124+
LD SP,HL
125+
EXX
126+
PUSH HL ; ROW 5
127+
EXX
128+
129+
; We're empty. Time to load up again.
130+
131+
LD SP,IX
132+
POP BC ; ROW 6
133+
POP DE ; ROW 7
134+
EX AF,AF'
135+
POP AF ; ROW 8
136+
EX AF,AF'
137+
EXX
138+
POP BC ; ROW 9
139+
POP DE ; ROW 10
140+
POP HL ; ROW 11
141+
EXX
142+
143+
; and we're loaded up again! Time to dump this graphic on the screen.
144+
145+
LD IX,0
146+
ADD IX,SP ; save SP in IX
147+
148+
INC H
149+
LD SP,HL
150+
PUSH BC ; ROW 6
151+
152+
INC H
153+
LD SP,HL
154+
PUSH DE ; ROW 7
155+
156+
DEC HL
157+
DEC HL
158+
159+
; Aha. Snag. We're at the bottom of a character. What's the next address down?
160+
ld a,l
161+
and 224
162+
cp 224
163+
jp z,ptSameThird3
164+
165+
ptNextThird3:
166+
ld de,1760
167+
and a
168+
sbc hl,de
169+
jp ptAddrDone3
170+
171+
ptSameThird3:
172+
173+
ld de,32
174+
and a
175+
adc hl,de
176+
177+
ptAddrDone3:
178+
179+
INC HL
180+
INC HL
181+
182+
LD SP,HL
183+
EX AF,AF'
184+
PUSH AF ; ROW 8
185+
186+
INC H
187+
LD SP,HL
188+
EXX
189+
PUSH BC ; ROW 9
190+
EXX
191+
192+
INC H
193+
LD SP,HL
194+
EXX
195+
PUSH DE ; ROW 10
196+
EXX
197+
198+
INC H
199+
LD SP,HL
200+
EXX
201+
PUSH HL ; ROW 11
202+
EXX
203+
204+
; Okay. Registers empty. Reload time!
205+
LD SP,IX
206+
POP BC ; ROW 12
207+
POP DE ; ROW 13
208+
209+
EXX
210+
POP BC ; ROW 14
211+
POP DE ; ROW 15
212+
POP HL ; Top Attrs
213+
EXX
214+
215+
EX AF,AF'
216+
POP AF ; Bottom Attrs
217+
EX AF,AF'
218+
219+
; and the last dump to screen
220+
221+
INC H
222+
LD SP,HL
223+
PUSH BC
224+
225+
INC H
226+
LD SP,HL
227+
PUSH DE
228+
229+
INC H
230+
LD SP,HL
231+
EXX
232+
PUSH BC
233+
EXX
234+
235+
INC H
236+
LD SP,HL
237+
EXX
238+
PUSH DE
239+
EXX
240+
241+
; Pixels done. Just need to do the attributes.
242+
; So set HL to the attr address:
243+
244+
ld a,IYL ;ypos
245+
246+
rrca
247+
rrca
248+
rrca ; Multiply by 32
249+
ld l,a ; Pass to L
250+
and 3 ; Mask with 00000011
251+
add a,88 ; 88 * 256 = 22528 - start of attributes.
252+
ld h,a ; Put it in the High Byte
253+
ld a,l ; We get y value *32
254+
and 224 ; Mask with 11100000
255+
ld l,a ; Put it in L
256+
ld a,IYH ; xpos
257+
adc a,l ; Add it to the Low byte
258+
ld l,a ; Put it back in L, and we're done. HL=Address.
259+
INC HL ; we need to be to the right of the ATTR point as pushes write backwards.
260+
INC HL
261+
262+
; attr
263+
LD SP,HL
264+
EXX
265+
PUSH HL ; top row
266+
EXX
267+
268+
LD HL,34 ; we need to move down to the next row. We already backed up 2, so we add 34.
269+
ADD HL,SP
270+
LD SP,HL
271+
EX AF,AF' ; bottom row
272+
PUSH AF
273+
274+
ptNextSprite2:
275+
; done. Cleanup.
276+
LD SP,(ptstackSave) ; put our stack back together.
277+
278+
; done all 4 final clean up
279+
280+
POP IY
281+
POP IX
282+
283+
POP AF ; recover interrupt status
284+
JP PO, pt_nointerrupts
285+
EI ; Okay. We put everything back. If you need interrupts, you can go with em.
286+
287+
pt_nointerrupts:
288+
END ASM
289+
END SUB
290+
```
291+
292+
## Usage
293+
294+
Example:
295+
296+
```
297+
putTile (10,10,@sprite)
298+
```
299+
300+
Will copy a tile of data to print position 10,10 from address at label sprite.
301+

0 commit comments

Comments
 (0)