gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/libc/targets/mos6502/nes/set_tile_submap_attributes.s
1 .include "global.s"
2
3 .area GBDKOVR (PAG, OVR)
4 _set_bkg_submap_attributes_nes16x16_PARM_3::
5 _set_win_submap_attributes_nes16x16_PARM_3:: .ds 1
6 _set_bkg_submap_attributes_nes16x16_PARM_4::
7 _set_win_submap_attributes_nes16x16_PARM_4:: .ds 1
8 _set_bkg_submap_attributes_nes16x16_PARM_5::
9 _set_win_submap_attributes_nes16x16_PARM_5:: .ds 2
10 _set_bkg_submap_attributes_nes16x16_PARM_6::
11 _set_win_submap_attributes_nes16x16_PARM_6:: .ds 1
12 .xpos: .ds 1
13 .ypos: .ds 1
14 .num_rows: .ds 1
15 .src_tiles: .ds 2
16 .x_odd: .ds 1
17 .y_odd: .ds 1
18 .num_columns: .ds 1
19 .attribute_mask_map: .ds 1
20 .attribute_mask_shadow: .ds 1
21
22 .area _HOME
23
24 .macro COORDS_TO_IDX
25 pha
26 ; ypos bit 2-0 -> bit 5-3
27 lda *.ypos
28 and #AT_SHADOW_HEIGHT-1
29 .ifne NT_2W
30 asl
31 .endif
32 asl
33 asl
34 asl
35 sta *.tmp+2
36 ; xpos bit 2-0 -> bit 2-0
37 lda *.xpos
38 and #AT_SHADOW_WIDTH-1
39 ora *.tmp+2
40 tax
41 pla
42 .endm
43
44 .macro INC_ROW_SRC
45 ; .src_tiles += width
46 lda *.map_width
47 clc
48 adc *.src_tiles
49 sta *.src_tiles
50 lda #0
51 adc *.src_tiles+1
52 sta *.src_tiles+1
53 .endm
54
55 .macro INC_Y_WITH_WRAP
56 lda *.ypos
57 clc
58 adc #1
59 and #AT_SHADOW_HEIGHT-1
60 sta *.ypos
61 INC_ROW_SRC
62 .endm
63
64 .macro SET_DIRTY_ROW ?lbl
65 lda *.xpos
66 and #AT_SHADOW_WIDTH-1
67 tax
68 lda #0
69 ldy *.ypos
70 .ifne NT_2H
71 cpy #ATTRIBUTE_PACKED_HEIGHT
72 rol
73 .endif
74 .ifne NT_2W
75 cpx #ATTRIBUTE_PACKED_WIDTH
76 rol
77 .endif
78 .ifdef NES_WINDOW_LAYER
79 bit *__current_vram_cfg_write
80 bpl lbl
81 eor #(2*NUM_NT)
82 lbl:
83 .endif
84 tax
85 lda .bitmask_table,y
86 ora _attribute_row_dirty,x
87 sta _attribute_row_dirty,x
88 .ifne NT_2W
89 txa
90 eor #0x1
91 tax
92 lda .bitmask_table,y
93 ora _attribute_row_dirty,x
94 sta _attribute_row_dirty,x
95 .endif
96 .endm
97
98 .macro SET_DIRTY_COLUMN ?lbl
99 lda *.xpos
100 and #AT_SHADOW_WIDTH-1
101 tay
102 lda #0
103 ldx *.ypos
104 .ifne NT_2H
105 cpx #ATTRIBUTE_PACKED_HEIGHT
106 rol
107 .endif
108 .ifne NT_2W
109 cpy #ATTRIBUTE_PACKED_WIDTH
110 rol
111 .endif
112 .ifdef NES_WINDOW_LAYER
113 bit *__current_vram_cfg_write
114 bpl lbl
115 eor #(2*NUM_NT)
116 lbl:
117 .endif
118 tax
119 lda .bitmask_table,y
120 ora _attribute_column_dirty,x
121 sta _attribute_column_dirty,x
122 .ifne NT_2H
123 txa
124 eor #(1 << NT_2W)
125 tax
126 lda .bitmask_table,y
127 ora _attribute_column_dirty,x
128 sta _attribute_column_dirty,x
129 .endif
130 .endm
131
132 .ifdef NES_WINDOW_LAYER
133 _set_win_submap_attributes_nes16x16::
134 lda *__current_vram_cfg_write
135 pha
136 ora #MAPPER_CFG_NT_MASK
137 sta *__current_vram_cfg_write
138 jsr _set_bkg_submap_attributes_nes16x16
139 pla
140 sta *__current_vram_cfg_write
141 rts
142 .endif
143
144 _set_bkg_submap_attributes_nes16x16::
145 .define .width "_set_bkg_submap_attributes_nes16x16_PARM_3"
146 .define .height "_set_bkg_submap_attributes_nes16x16_PARM_4"
147 .define .tiles "_set_bkg_submap_attributes_nes16x16_PARM_5"
148 .define .map_width "_set_bkg_submap_attributes_nes16x16_PARM_6"
149 lsr
150 sta *.xpos
151 ror *.x_odd
152 ; Attribute map stores 8 rows of bytes with 2x2 attributes in each byte continuously.
153 ; -> 16 rows of attributes
154 ; But for alignment reasons, the last row only stores 2x1 (bottom-left / bottom-right unused)
155 ; This extra row must be skipped to remap input y position into a new attribute table Y position
156 ; Rather than using a division to compensate, we use the following rules:
157 ; Y = y / 16
158 ; For each AT n already covered vertically:
159 ; - increase Y by +1
160 ; - also increase Y by +1 to skip 1 row of 16x16 attributes (occurs 1 coordinate earlier each AT)
161 ; Or in code:
162 ; n = y >> 4
163 ; Y = y + n + (y & 0xF >= 15 - n) ? 1 : 0
164 txa
165 lsr
166 lsr
167 lsr
168 lsr
169 sta *.tmp
170 eor #0xF
171 sta *.tmp+1
172 txa
173 and #0xF
174 cmp *.tmp+1
175 txa
176 adc *.tmp
177 ;
178 lsr
179 sta *.ypos
180 ror *.y_odd
181 lda *.tiles
182 sta *.src_tiles
183 lda *.tiles+1
184 sta *.src_tiles+1
185 lda *.map_width
186 lsr
187 adc #0 ; Fix problem with skewed offset when original tilemap is not a multiple-of-two
188 sta *.map_width
189 ldx *.ypos
190 jsr __muluchar
191 clc
192 adc *.src_tiles
193 sta *.src_tiles
194 txa
195 adc *.src_tiles+1
196 sta *.src_tiles+1
197 ; ypos %= ATTRIBUTE_PACKED_HEIGHT
198 lda *.ypos
199 and #AT_SHADOW_HEIGHT-1
200 sta *.ypos
201 ; Prefer vertical stripes if height > width
202 lda *.height
203 cmp *.width
204 bcc _set_bkg_submap_attributes_horizontalStripes
205 beq _set_bkg_submap_attributes_horizontalStripes
206 jmp _set_bkg_submap_attributes_verticalStripes
207 _set_bkg_submap_attributes_horizontalStripes:
208 lda *.height
209 sta *.num_rows
210 _set_bkg_submap_attributes_horizontalStripes_rowLoop:
211 SET_DIRTY_ROW
212 lda *.xpos
213 pha
214 jsr .process_row
215 pla
216 sta *.xpos
217 jsr .inc_row
218 dec *.num_rows
219 bne _set_bkg_submap_attributes_horizontalStripes_rowLoop
220 rts
221
222 _set_bkg_submap_attributes_verticalStripes:
223 jsr .inc_height_if_wrap
224 lda *.width
225 sta *.num_columns
226 _set_bkg_submap_attributes_verticalStripes_columnLoop:
227 SET_DIRTY_COLUMN
228 ldy *.xpos
229 lda *.ypos
230 pha
231 lda *.src_tiles
232 pha
233 lda *.src_tiles+1
234 pha
235 jsr .process_column
236 pla
237 sta *.src_tiles+1
238 pla
239 sta *.src_tiles
240 pla
241 sta *.ypos
242 ; Increment X (only if odd/even bit flipped to 0)
243 lda *.x_odd
244 eor #0x80
245 sta *.x_odd
246 bmi 1$
247 inc *.xpos
248 1$:
249 dec *.num_columns
250 bne _set_bkg_submap_attributes_verticalStripes_columnLoop
251 rts
252
253 .inc_row:
254 lda *.ypos
255 cmp #ATTRIBUTE_PACKED_HEIGHT-1
256 beq 2$
257 lda *.y_odd
258 eor #0x80
259 sta *.y_odd
260 bmi 1$
261 lda *.ypos
262 clc
263 adc #1
264 and #ATTRIBUTE_PACKED_HEIGHT-1
265 sta *.ypos
266 bpl .inc_row_src
267 1$:
268 rts
269 2$:
270 ; Skip last 16x16 row of attribute table (empty due to alignment)
271 lda #ATTRIBUTE_PACKED_HEIGHT
272 sta *.ypos
273 .inc_row_src:
274 INC_ROW_SRC
275 rts
276
277 .process_row:
278 ; Write only top part of row
279 lda #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
280 bit *.y_odd
281 bpl 1$
282 ; Shift mask to write only bottom part of row
283 asl
284 asl
285 asl
286 asl
287 1$:
288 sta *.attribute_mask_map
289 ; Invert mask
290 eor #0xFF
291 sta *.attribute_mask_shadow
292 ;
293 ; width even, x even -> No pre-loop, no post-loop
294 ; -> num_columns = w/2, pre = 0, post = 0
295 ; width even, x odd -> Pre-loop writing right half, post-loop writing left half
296 ; -> num_columns = w/2-1, pre = 1, post = 1
297 ; width odd, x even -> No Pre-loop, post-loop writing left half
298 ; -> num_columns = w/2, pre = 0, post = 1
299 ; width odd, x odd -> Pre-loop writing right half,no post-loop
300 ; -> num_columns = w/2, pre = 1, post = 0
301 ; width 1, x even -> Pre-loop only. (special case)
302 ; -> num_columns = w/2, pre = 1, post = 0
303 ;
304 ; +-----+-----+-----+
305 ; | X\W | 0 | 1 |
306 ; +-----+-----+-----+
307 ; | 0 | 0/0 | 0/1 |
308 ; +-----+-----+-----+
309 ; | 1 | 1/1 | 1/0 |
310 ; +-----+-----+-----+
311 ;
312 ; pre? = x_odd
313 ; post? = x_odd XOR width_odd
314 lda *.width
315 lsr
316 sta *.num_columns
317 ldy *.xpos
318 bit *.x_odd
319 bpl 2$
320 ; Do a partial update of only TR+BR for the first byte
321 lda *.attribute_mask_map
322 and #ATTRIBUTE_MASK_TR+ATTRIBUTE_MASK_BR
323 pha
324 and [*.src_tiles],y
325 iny
326 sta *.tmp
327 pla
328 eor #0xFF
329 jsr .write_to_shadow
330 inc *.xpos
331 ;;;
332 lda *.width
333 lsr
334 bcs 2$
335 ;;;
336 dec *.num_columns
337 2$:
338 lda *.num_columns
339 beq .column_loop_done
340
341 .column_loop:
342 lda [*.src_tiles],y
343 iny
344 and *.attribute_mask_map
345 sta *.tmp
346 lda *.attribute_mask_shadow
347 jsr .write_to_shadow
348 inc *.xpos
349 dec *.num_columns
350 bne .column_loop
351 ;
352 .column_loop_done:
353 lda *.width
354 lsr
355 ror
356 eor *.x_odd
357 bpl 1$
358 ; We have one remaining half-column (16 pixels wide)
359 ; Do a partial update of only TL+BL for the last column
360 lda *.attribute_mask_map
361 and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL
362 pha
363 and [*.src_tiles],y
364 iny
365 sta *.tmp
366 pla
367 eor #0xFF
368 jsr .write_to_shadow
369 1$:
370 rts
371
372 .inc_height_if_wrap:
373 ; Aligned AT handling: if ypos will wrap from 14 -> 0, then height should be += 1
374 lda *.y_odd
375 cmp #0x80
376 lda *.ypos
377 rol
378 tax
379 clc
380 adc *.height
381 cmp #ATTRIBUTE_HEIGHT
382 bcc 3$
383 inc *.height
384 3$:
385 txa
386 lsr
387 sta *.ypos
388 ror *.y_odd
389 rts
390
391 .process_column:
392 ; Write only left part of column
393 lda #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL
394 bit *.x_odd
395 bpl 1$
396 ; Shift mask to write only right part of column
397 asl
398 asl
399 1$:
400 sta *.attribute_mask_map
401 ; Invert mask
402 eor #0xFF
403 sta *.attribute_mask_shadow
404 lda *.height
405 lsr
406 sta *.num_rows
407 bit *.y_odd
408 bpl 2$
409 ; Do a partial update of only BL+BR for the first byte
410 lda *.attribute_mask_map
411 and #ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
412 pha
413 and [*.src_tiles],y
414 sta *.tmp
415 pla
416 eor #0xFF
417 jsr .write_to_shadow
418 INC_Y_WITH_WRAP
419 ;;;
420 lda *.height
421 lsr
422 bcs 2$
423 ;;;
424 dec *.num_rows
425 2$:
426 lda *.num_rows
427 beq .row_loop_done
428
429 .row_loop:
430 lda [*.src_tiles],y
431 and *.attribute_mask_map
432 sta *.tmp
433 lda *.attribute_mask_shadow
434 jsr .write_to_shadow
435 inc *.ypos
436 INC_ROW_SRC
437 dec *.num_rows
438 bne .row_loop
439 ;
440 .row_loop_done:
441 lda *.height
442 lsr
443 ror
444 eor *.y_odd
445 bpl 1$
446 ; We have one remaining half-row (16 pixels tall)
447 ; Do a partial update of only TL+TR for the last byte
448 lda *.attribute_mask_map
449 and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
450 pha
451 and [*.src_tiles],y
452 sta *.tmp
453 pla
454 eor #0xFF
455 jsr .write_to_shadow
456 1$:
457 rts
458
459 .write_to_shadow:
460 COORDS_TO_IDX
461 .ifdef NES_WINDOW_LAYER
462 bit *__current_vram_cfg_write
463 bmi 1$
464 .endif
465 and _attribute_shadow,x
466 ora *.tmp
467 sta _attribute_shadow,x
468 rts
469 ; Window version
470 .ifdef NES_WINDOW_LAYER
471 1$:
472 and _attribute_shadow_win,x
473 ora *.tmp
474 sta _attribute_shadow_win,x
475 rts
476 .endif
477
478 .bitmask_table:
479 .db 0b00000001
480 .db 0b00000010
481 .db 0b00000100
482 .db 0b00001000
483 .db 0b00010000
484 .db 0b00100000
485 .db 0b01000000
486 .db 0b10000000
487 ;
488 .db 0b00000001
489 .db 0b00000010
490 .db 0b00000100
491 .db 0b00001000
492 .db 0b00010000
493 .db 0b00100000
494 .db 0b01000000
495 .db 0b10000000
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.