git.y1.nz

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_bk_attributes.s

      1     .include    "global.s"
      2 
      3     .area   GBDKOVR (PAG, OVR)
      4     _set_bkg_attributes_nes16x16_PARM_3::   .ds 1
      5     _set_bkg_attributes_nes16x16_PARM_4::   .ds 1
      6     _set_bkg_attributes_nes16x16_PARM_5::   .ds 2
      7     .xpos:                                  .ds 1
      8     .ypos:                                  .ds 1
      9     .num_columns:                           .ds 1
     10     .num_rows:                              .ds 1
     11     .height_second_pass:                    .ds 1
     12     .height_first_pass:                     .ds 1
     13     .attribute_x_odd:                       .ds 1
     14     .starty_second_pass:                    .ds 1
     15     .x_bits:                                .ds 1
     16     .attribute_y_odd:                       .ds 1
     17     .attribute_num_columns_odd:             .ds 1
     18     .attribute_num_rows_odd:                .ds 1
     19 
     20     .area   _HOME
     21 
     22 .define .width  "_set_bkg_attributes_nes16x16_PARM_3"
     23 .define .height "_set_bkg_attributes_nes16x16_PARM_4"
     24 .define .src    "_set_bkg_attributes_nes16x16_PARM_5"
     25 
     26 .macro INC_X ?lbl
     27     ; Increment dst index
     28     inx
     29     txa
     30     bit *.x_bits
     31     bne lbl
     32     sec
     33     sbc #AT_SHADOW_WIDTH
     34     tax
     35 lbl:
     36     ; Increment src index
     37     iny
     38 .endm
     39 
     40 _set_bkg_attributes_nes16x16::
     41     pha
     42 .ifne NT_2H
     43     ; Two vertical nametables -> wrap around to next
     44     lda #0x10
     45 .else
     46     ; One vertical nametable -> wrap around to self
     47     lda #0x00
     48 .endif
     49     sta *.starty_second_pass
     50     txa
     51     ldy #(.DEVICE_SCREEN_HEIGHT/2)      ; Row end
     52     cmp #(.DEVICE_SCREEN_HEIGHT/2)
     53     bcc 1$
     54     sbc #(.DEVICE_SCREEN_HEIGHT/2)      ; Assumes carry set
     55 .ifne NT_2H
     56     ldy #0x00
     57     sty *.starty_second_pass
     58 .endif
     59     ldy #(2*.DEVICE_SCREEN_HEIGHT/2)    ; Row end
     60 1$:
     61     clc
     62     adc *.height
     63     cmp #17
     64     bcs .set_bkg_attributes_nes16x16_wrap_two_passes
     65     ; No wrap - just do single pass
     66     pla
     67     jmp _set_bkg_attributes_nes16x16_impl
     68 
     69 .set_bkg_attributes_nes16x16_wrap_two_passes:
     70     tya
     71     ; num_rows_first = MIN(row_end-y, h);
     72     sec
     73     sbc .identity,x
     74     cmp *.height
     75     bcc 1$
     76     lda *.height
     77 1$:
     78     sta *.height_first_pass
     79     lda *.height
     80     sec
     81     sbc *.height_first_pass
     82     sta *.height_second_pass
     83     ; First pass
     84     lda *.height_first_pass
     85     beq 11$
     86     sta *.height
     87     pla
     88     pha
     89     jsr _set_bkg_attributes_nes16x16_impl
     90 11$:
     91     ; Second pass
     92     lda *.height_second_pass
     93     beq 3$
     94     lsr *.height_first_pass
     95     sta *.height
     96     bcs 2$
     97     ; num_rows_first was even, so attribute data for second pass starts at expected address
     98     ; Start second pass at AT==16 (next attribute table)
     99     lda *.starty_second_pass
    100     tax
    101     pla
    102     jmp __set_bkg_attributes_nes16x16_impl_skip_y_adjustment
    103 2$:
    104     ; num_rows_first was odd, so attribute data for second pass is half-way through expected address
    105     ; Start second pass at AT y==15 to skip one half-row of attribute data (AT y==15 is always hidden)
    106     lda *.starty_second_pass
    107 .ifne NT_2H
    108     ; Two vertical nametables -> wrap around to last row of next nametable
    109     eor #0x1F
    110 .else
    111     ; One vertical nametable -> wrap around to last row of this nametable
    112     eor #0x0F
    113 .endif
    114     tax
    115     pla
    116     jmp __set_bkg_attributes_nes16x16_impl_skip_y_adjustment
    117 3$:
    118     pla
    119     rts
    120 
    121 _set_bkg_attributes_nes16x16_impl::
    122     ; Adjust Y-coordinate to skip last unused half-row of 8x8 attribute table
    123     cpx #(2*AT_HEIGHT-1)
    124     bcc 42$
    125     inx
    126 42$:
    127 __set_bkg_attributes_nes16x16_impl_skip_y_adjustment::
    128     stx *.ypos
    129     lsr                             ; Make xpos count 32x32 areas / full bytes
    130     ror *.attribute_x_odd           ; ...and potentially mark x as odd-numbered
    131     sta *.xpos
    132     lsr *.ypos                      ; Make ypos count 32x32 areas / full bytes
    133     ror *.attribute_y_odd           ; ...and potentially mark y as odd-numbered
    134     lda *.height
    135     lsr                             ; Make num_rows count 32x32 areas / full bytes
    136     ror *.attribute_num_rows_odd    ; ...and mark num_rows as odd-numbered
    137     sta *.num_rows
    138     lda #AT_SHADOW_WIDTH-1
    139     sta *.x_bits
    140     ;
    141     lda *.width
    142     lsr                             ; Make num_columns count 32x32 areas / full bytes
    143     ror *.attribute_num_columns_odd ; ...and mark num_columns as odd-numbered
    144     sta *.num_columns
    145     ;
    146     lda *.ypos
    147     asl
    148     asl
    149     asl
    150 .ifne NT_2W
    151     asl
    152 .endif
    153     ora *.xpos
    154     pha
    155     tax
    156     jsr .attribute_set_dirty
    157     pla
    158     tax
    159     ; Branch into distinct routines based on whether x / y are aligned
    160     ; (even or odd width / height are handled internally by these routines)
    161     bit *.attribute_y_odd
    162     bmi 4$
    163     ; Aligned Y
    164     bit *.attribute_x_odd
    165     bmi 2$
    166     ; Aligned Y, aligned X
    167     jmp aligned_xy
    168 2$:
    169     ; Aligned Y, unaligned X
    170     jmp unaligned_x
    171 4$:
    172     ; Unaligned Y
    173     bit *.attribute_x_odd
    174     bmi 5$
    175     ; Unaligned Y, aligned X
    176     jmp unaligned_y
    177 5$:
    178     ; Unaligned Y, aligned X
    179     jmp unaligned_xy
    180 
    181 ;
    182 ; Version for when x & y are both aligned to attribute byte-grid
    183 ;
    184 .macro ALIGNED_XY_RIGHT_EDGE at_mask at_mask_i ?lbl
    185     bit *.attribute_num_columns_odd
    186     bpl lbl
    187     lda _attribute_shadow,x
    188     and #at_mask_i
    189     sta *.tmp
    190     lda [*.src],y
    191     and #at_mask
    192     ora *.tmp
    193     sta _attribute_shadow,x
    194 lbl:
    195 .endm
    196 ;
    197 aligned_xy:
    198     lda *.num_rows
    199     beq aligned_xy_row_loop_end
    200 aligned_xy_row_loop:
    201     jsr .reset_x_coord
    202 aligned_xy_column_loop:
    203     lda [*.src],y
    204     sta _attribute_shadow,x
    205     INC_X
    206     cpy *.num_columns
    207     bne aligned_xy_column_loop
    208     ; If columns were odd, we have one more byte where only left part should be modified
    209     ALIGNED_XY_RIGHT_EDGE ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    210     jsr .inc_row
    211     bne aligned_xy_row_loop
    212 aligned_xy_row_loop_end:
    213     ; If rows were odd, we have one additional row where only top part should be modified
    214     bit *.attribute_num_rows_odd
    215     bpl 1$
    216     jsr .reset_x_coord
    217 2$:
    218     lda _attribute_shadow,x
    219     and #ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    220     sta *.tmp
    221     lda [*.src],y
    222     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    223     ora *.tmp
    224     sta _attribute_shadow,x
    225     INC_X
    226     cpy *.num_columns
    227     bne 2$
    228     ; If columns were odd, we have one more byte where only top corner should be modified
    229     ALIGNED_XY_RIGHT_EDGE ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    230 1$:
    231     rts
    232 
    233 ;
    234 ; Version for when x is misaligned with attribute byte-grid
    235 ;
    236 .define p       ".tmp+1"
    237 .macro UNALIGNED_X_RIGHT_EDGE at_mask at_mask_i ?lbl
    238     bit *.attribute_num_columns_odd
    239     bmi lbl
    240     lda _attribute_shadow,x
    241     and #at_mask_i
    242     sta *.tmp
    243     lda *p
    244     and #at_mask
    245     ora *.tmp
    246     sta _attribute_shadow,x
    247 lbl:
    248 .endm
    249 unaligned_x:
    250 ; Round num_columns
    251     lda *.attribute_num_columns_odd
    252     bpl 8$
    253     ; Odd columns get aligned at right edge - but we need to round num_rows upwards!
    254     inc *.num_columns
    255 8$:
    256     lda *.num_rows
    257     beq unaligned_x_row_loop_end
    258 unaligned_x_row_loop:
    259     jsr .reset_x_coord
    260     ; As we're writing output +1 X coordinate to the right, first byte in attribute shadow must be a read-modify-write
    261     ; Fill p with old values for TL / BL, to initialize it for subsequent code.
    262     lda _attribute_shadow,x
    263     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL
    264     sta *p
    265 unaligned_x_column_loop:
    266     lda [*.src],y
    267     ; Shift to move right one attribute coordinate, as x is unaligned
    268     ; Left half of src (top-left, bottom-left) goes into right half (top-right, bottom-right) of current byte...
    269     asl
    270     asl
    271     and #ATTRIBUTE_MASK_TR+ATTRIBUTE_MASK_BR
    272     ; ...and combined with p providing left half 
    273     ora *p
    274     sta _attribute_shadow,x
    275     ; While right half of src (top-right, bottom right) is saved in p for *next* byte as *left* half
    276     lda [*.src],y
    277     lsr
    278     lsr
    279     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL
    280     sta *p
    281     INC_X
    282     cpy *.num_columns
    283     bne unaligned_x_column_loop
    284     ; If columns were NOT odd, we have one more byte where only left part should be modified
    285     UNALIGNED_X_RIGHT_EDGE ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    286     jsr .inc_row
    287     bne unaligned_x_row_loop
    288 unaligned_x_row_loop_end:
    289     ; If rows were odd, we have one additional row where only top part should be modified
    290     bit *.attribute_num_rows_odd
    291     bpl 5$
    292     jsr .reset_x_coord
    293     ; As we're writing output +1 X coordinate to the right, first byte in attribute shadow must be a read-modify-write
    294     ; Fill p with old values for TL / BL / BR, to initialize it for subsequent code.
    295     lda _attribute_shadow,x
    296     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    297     sta *p
    298 2$:
    299     lda [*.src],y
    300     ; Shift to move right one attribute coordinate, as x is unaligned
    301     ; Left half of src (top-left, bottom-left) goes into right half (top-right) of current byte...
    302     asl
    303     asl
    304     and #ATTRIBUTE_MASK_TR
    305     ; ...and combined with p providing left half 
    306     ora *p
    307     sta _attribute_shadow,x
    308     ; While right half of src (top-right, bottom left, bottom right) is saved in p for *next* byte as *left* half
    309     lda [*.src],y
    310     lsr
    311     lsr
    312     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    313     sta *p
    314     INC_X
    315     cpy *.num_columns
    316     bne 2$
    317     ; If columns were odd, we have one more byte where only top-left corner should be modified
    318     UNALIGNED_X_RIGHT_EDGE ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    319 5$:
    320     rts
    321 
    322 ;
    323 ; Version for when y is misaligned with attribute byte-grid
    324 ;
    325 .macro UNALIGNED_Y_RIGHT_EDGE at_mask at_mask_i ?lbl
    326     bit *.attribute_num_columns_odd
    327     bpl lbl
    328     lda _attribute_shadow,x
    329     and #at_mask_i
    330     sta *.tmp
    331     lda [*.src],y
    332     asl
    333     asl
    334     asl
    335     asl
    336     and #ATTRIBUTE_MASK_BL
    337     ora *.tmp
    338     ora *pRow,y
    339     and #at_mask
    340     sta _attribute_shadow,x
    341     lda [*.src],y
    342     lsr
    343     lsr
    344     lsr
    345     lsr
    346     and #ATTRIBUTE_MASK_TL
    347     sta *pRow,y
    348 lbl:
    349 .endm
    350 unaligned_y:
    351 .define pRow    "REGTEMP"
    352 ; Round num_rows
    353     lda *.attribute_num_rows_odd
    354     bpl 9$
    355     ; Odd rows get aligned at bottom - but we need to round num_rows upwards!
    356     inc *.num_rows
    357 9$:
    358     ; Even rows means additional row needed, but don't round num_rows upwards.
    359 ; As we're writing output +1 Y coordinate down, first row in attribute shadow must be a read-modify-write
    360 ; Fill pRow with old values for TL / TR, to initialize it for subsequent code.
    361     jsr .reset_x_coord
    362 unaligned_y_row_init_loop:
    363     lda _attribute_shadow,x
    364     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    365     sta *pRow,y
    366     INC_X
    367     cpy *.num_columns
    368     bne unaligned_y_row_init_loop
    369     lda *.num_rows
    370     beq unaligned_y_row_loop_end
    371 unaligned_y_row_loop:
    372     jsr .reset_x_coord
    373 unaligned_y_column_loop:
    374     lda [*.src],y
    375     ; Shift to move down one attribute coordinate, as y is unaligned
    376     ; Top-part goes into bottom part of current row...
    377     asl
    378     asl
    379     asl
    380     asl
    381     and #ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    382     ora *pRow,y
    383     sta _attribute_shadow,x
    384     ; ...and bottom part is saved as top part for *next* row
    385     lda [*.src],y
    386     lsr
    387     lsr
    388     lsr
    389     lsr
    390     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    391     sta *pRow,y
    392     ;
    393     INC_X
    394     cpy *.num_columns
    395     bne unaligned_y_column_loop
    396     ; If columns were odd, we have one more byte where only left part should be modified
    397     UNALIGNED_Y_RIGHT_EDGE ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    398     jsr .inc_row
    399     bne unaligned_y_row_loop
    400 unaligned_y_row_loop_end:
    401     ; If rows were NOT odd, we have one additional row where only top part should be modified
    402     ; pRow should be used as source data
    403     bit *.attribute_num_rows_odd
    404     bmi 1$
    405     jsr .reset_x_coord
    406 2$:
    407     lda _attribute_shadow,x
    408     and #ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    409     sta *.tmp
    410     lda *pRow,y
    411     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    412     ora *.tmp
    413     sta _attribute_shadow,x
    414     INC_X
    415     cpy *.num_columns
    416     bne 2$
    417     ; If columns were odd, we have one more byte where only top-left corner should be modified
    418     UNALIGNED_Y_RIGHT_EDGE ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    419 1$:
    420     rts
    421 
    422 ;
    423 ; Version for when x & y are both misaligned with attribute byte-grid
    424 ;
    425 .macro UNALIGNED_XY_RIGHT_EDGE at_mask at_mask_i ?lbl
    426     bit *.attribute_num_columns_odd
    427     bmi lbl
    428     lda _attribute_shadow,x
    429     and #at_mask_i
    430     sta *.tmp
    431     ; top-left taken from previous row...
    432     lda *pRow,y
    433     and #ATTRIBUTE_MASK_TL
    434     ora *.tmp
    435     ; ...and bottom-left taken from previous *byte*
    436     sta *.tmp
    437     lda *p
    438     asl
    439     asl
    440     and #ATTRIBUTE_MASK_BL
    441     ora *.tmp
    442     and #at_mask
    443     sta _attribute_shadow,x
    444     ; ...finally, save *bottom-left in previous byte moved to top-left*
    445     lda *p
    446     lsr
    447     lsr
    448     lsr
    449     lsr
    450     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    451     sta *pRow,y      ; previous row now correctly setup to contain everything in top-left
    452 lbl:
    453 .endm
    454 unaligned_xy:
    455 ; Round num_columns
    456     lda *.attribute_num_columns_odd
    457     bpl 8$
    458     ; Odd columns get aligned at right edge - but we need to round num_rows upwards!
    459     inc *.num_columns
    460 8$:
    461     ; Even columns means additional byte needed, but don't round num_columns upwards.
    462 ; Round num_rows
    463     lda *.attribute_num_rows_odd
    464     bpl 9$
    465     ; Odd rows get aligned at bottom - but we need to round num_rows upwards!
    466     inc *.num_rows
    467 9$:
    468     ; Even rows means additional row needed, but don't round num_rows upwards.
    469 ; As we're writing output +1 Y coordinate down, first row in attribute shadow must be a read-modify-write
    470 ; Fill pRow with old values for TL / TR, to initialize it for subsequent code. Shift them in X by +1
    471     jsr .reset_x_coord
    472     lda _attribute_shadow,x
    473     and #ATTRIBUTE_MASK_BL
    474     sta *p
    475 unaligned_xy_row_init_loop:
    476     lda _attribute_shadow,x
    477     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    478     sta *pRow,y
    479     INC_X
    480     cpy *.num_columns
    481     bne unaligned_xy_row_init_loop
    482     lda *.num_rows
    483     beq unaligned_xy_row_loop_end
    484 unaligned_xy_row_loop:
    485     jsr .reset_x_coord
    486 unaligned_xy_column_loop:
    487     lda [*.src],y
    488     ; Shift to move down one attribute coordinate, and right one attribute coordinate, as x and y are both unaligned
    489     ; Top-left goes into bottom-right of current row...
    490     asl
    491     asl
    492     asl
    493     asl
    494     asl
    495     asl
    496     ;and #ATTRIBUTE_MASK_BR
    497     ; ...with top-left / top-right taken from previous row
    498     ora *pRow,y
    499     ; ...and bottom-left taken from previous *byte*
    500     sta *.tmp
    501     lda *p
    502     asl
    503     asl
    504     and #ATTRIBUTE_MASK_BL
    505     ora *.tmp
    506     sta _attribute_shadow,x
    507     ; ...finally, bottom-left part is saved for *next* row, but moved to top right and combined with *bottom-left in previous byte moved to top-left*
    508     lda [*.src],y
    509     lsr
    510     lsr
    511     and #ATTRIBUTE_MASK_TR
    512     sta *.tmp
    513     lda *p
    514     lsr
    515     lsr
    516     lsr
    517     lsr
    518     and #ATTRIBUTE_MASK_TL
    519     ora *.tmp
    520     sta *pRow,y      ; previous row now correctly setup to contain everything in top-left + rop-right
    521     ; ...and don't forget to save top-right of this byte as new previous byte
    522     lda [*.src],y
    523     sta *p
    524     ;
    525     INC_X
    526     cpy *.num_columns
    527     bne unaligned_xy_column_loop
    528     ; If columns were NOT odd, we have one more byte where only left part should be modified
    529     UNALIGNED_XY_RIGHT_EDGE ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    530     jsr .inc_row
    531     bne unaligned_xy_row_loop
    532 unaligned_xy_row_loop_end:
    533     ; If rows were NOT odd, we have one additional row where only top part should be modified
    534     ; pRow should be used as source data - it has already been pre-shifted correctly
    535     bit *.attribute_num_rows_odd
    536     bmi 1$
    537     jsr .reset_x_coord
    538 2$:
    539     lda _attribute_shadow,x
    540     and #ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR
    541     sta *.tmp
    542     lda *pRow,y
    543     and #ATTRIBUTE_MASK_TL+ATTRIBUTE_MASK_TR
    544     ora *.tmp
    545     sta _attribute_shadow,x
    546     INC_X
    547     cpy *.num_columns
    548     bne 2$
    549     ; If columns were NOT odd, we have one more byte where only top-left corner should be modified
    550     UNALIGNED_XY_RIGHT_EDGE ATTRIBUTE_MASK_TL, ATTRIBUTE_MASK_BL+ATTRIBUTE_MASK_BR+ATTRIBUTE_MASK_TR
    551 1$:
    552     rts
    553 
    554 .attribute_set_dirty:
    555     ; A = min(AT_HEIGHT-1, .num_rows + .attribute_num_rows_odd) << 3
    556     lda *.attribute_num_rows_odd
    557     cmp #0x80
    558     lda *.num_rows
    559     adc #0
    560     cmp #AT_HEIGHT-1
    561     bcc 1$
    562     lda #AT_HEIGHT-1
    563 1$:
    564     sta *.tmp
    565     ; Y = A | ypos
    566     lda *.ypos
    567 .ifne NT_2H
    568     and #AT_HEIGHT-1
    569     ; Special-case: if we are at last half-row, then ypos actually applies to *next* nametable
    570     ; So treat it as row == 0 for next nametable
    571     cmp #AT_HEIGHT-1
    572     bcc 2$
    573     bit *.attribute_y_odd
    574     bpl 2$
    575     txa
    576     adc #AT_SHADOW_WIDTH
    577     and #(AT_SHADOW_WIDTH*AT_SHADOW_HEIGHT-1)
    578     tax
    579     lda #0
    580 2$:
    581 .endif
    582     asl
    583     asl
    584     asl
    585     ora *.tmp
    586     tay
    587 .ifdef NES_TILEMAP_S
    588     lda .row_dirty_table,y
    589     ora *_attribute_row_dirty
    590     sta *_attribute_row_dirty
    591 .endif
    592 .ifdef NES_TILEMAP_H
    593     ldx #0
    594     jsr .mark_left_and_right_at_dirty
    595 .endif
    596 .ifdef NES_TILEMAP_V
    597     cpx #(AT_SHADOW_WIDTH*AT_SHADOW_HEIGHT/2)
    598     lda #0
    599     rol
    600     tax
    601     lda .row_dirty_table,y
    602     ora *_attribute_row_dirty,x
    603     sta *_attribute_row_dirty,x
    604 .endif
    605 .ifdef NES_TILEMAP_F
    606     cpx #(AT_SHADOW_WIDTH*AT_SHADOW_HEIGHT/2)
    607     lda #0
    608     rol
    609     asl
    610     tax
    611     jsr .mark_left_and_right_at_dirty
    612 .endif
    613     rts
    614 
    615 .ifne NT_2W
    616 ;
    617 ; Marks left and right attribute table dirty, depending on MSB of xpos and width of attributes to write
    618 ;
    619 ; Input: X =      0 for NES_TILEMAP_H
    620 ;            0 or 2 for NES_TILEMAP_F, indexing dirty flags for top/bottom attribute tables
    621 ;
    622 .mark_left_and_right_at_dirty:
    623     .define .flip_xpos_msb      "DPTR"
    624     .define .x_wrapped_around   "DPTR+1"
    625     lda #AT_WIDTH
    626     sta *.flip_xpos_msb
    627     ; Store wrapped-around flag to same bit as xpos MSB (AT_WIDTH)
    628     lda *.xpos
    629     sec     ; +1 to account for rounding odd coordinates upwards
    630     adc *.num_columns
    631     eor *.xpos
    632     and #AT_WIDTH
    633     sta *.x_wrapped_around
    634     ; First loop iteration:  Mark left AT dirty if xpos < AT_WIDTH or wrap-around occurred
    635     ; Second loop iteration: Mark right AT dirty if xpos >= AT_WIDTH or wrap-around occurred
    636 9$:
    637     lda *.xpos
    638     eor *.flip_xpos_msb
    639     ora *.x_wrapped_around
    640     and #AT_WIDTH
    641     beq 10$
    642     lda .row_dirty_table,y
    643     ora *_attribute_row_dirty,x
    644     sta *_attribute_row_dirty,x
    645 10$:
    646     inx
    647     lda *.flip_xpos_msb
    648     eor #AT_WIDTH
    649     sta *.flip_xpos_msb
    650     beq 9$
    651     rts
    652 .endif
    653 
    654 .reset_x_coord:
    655     ldy #0
    656     txa
    657     and #((AT_SHADOW_HEIGHT - 1) * AT_SHADOW_WIDTH)
    658     ora *.xpos
    659     tax
    660     rts
    661 
    662 .inc_row:
    663     ; src += num_columns
    664     lda *.src
    665     clc
    666     adc *.num_columns
    667     sta *.src
    668     lda *.src+1
    669     adc #0
    670     sta *.src+1
    671     ; Increment Y-coordinate of attribute shadow index
    672     txa
    673     adc #AT_SHADOW_WIDTH
    674     and #(AT_SHADOW_WIDTH*AT_SHADOW_HEIGHT-1)
    675     tax
    676     ; Decrement num_rows for caller loop
    677     dec *.num_rows
    678     rts
    679 
    680 ;
    681 ; Provides a quick table lookup to set _attribute_row_dirty based on num_rows / ypos
    682 ;
    683 ; Indexing: 00YYYNNN
    684 ;
    685 ; Where:
    686 ;   Y = Starting byte row in attribute table
    687 ;   N = Number of byte rows in attribute table -1 (including additional row if needed)
    688 ;
    689 .row_dirty_table:
    690 ; Y = 0
    691 .db 0b00000001
    692 .db 0b00000011
    693 .db 0b00000111
    694 .db 0b00001111
    695 .db 0b00011111
    696 .db 0b00111111
    697 .db 0b01111111
    698 .db 0b11111111
    699 ; Y = 1
    700 .db 0b00000010
    701 .db 0b00000110
    702 .db 0b00001110
    703 .db 0b00011110
    704 .db 0b00111110
    705 .db 0b01111110
    706 .db 0b11111110
    707 .db 0b11111111
    708 ; Y = 2
    709 .db 0b00000100
    710 .db 0b00001100
    711 .db 0b00011100
    712 .db 0b00111100
    713 .db 0b01111100
    714 .db 0b11111100
    715 .db 0b11111101
    716 .db 0b11111111
    717 ; Y = 3
    718 .db 0b00001000
    719 .db 0b00011000
    720 .db 0b00111000
    721 .db 0b01111000
    722 .db 0b11111000
    723 .db 0b11111001
    724 .db 0b11111011
    725 .db 0b11111111
    726 ; Y = 4
    727 .db 0b00010000
    728 .db 0b00110000
    729 .db 0b01110000
    730 .db 0b11110000
    731 .db 0b11110001
    732 .db 0b11110011
    733 .db 0b11110111
    734 .db 0b11111111
    735 ; Y = 5
    736 .db 0b00100000
    737 .db 0b01100000
    738 .db 0b11100000
    739 .db 0b11100001
    740 .db 0b11100011
    741 .db 0b11100111
    742 .db 0b11101111
    743 .db 0b11111111
    744 ; Y = 6
    745 .db 0b01000000
    746 .db 0b11000000
    747 .db 0b11000001
    748 .db 0b11000011
    749 .db 0b11000111
    750 .db 0b11001111
    751 .db 0b11011111
    752 .db 0b11111111
    753 ; Y = 7
    754 .db 0b10000000
    755 .db 0b10000001
    756 .db 0b10000011
    757 .db 0b10000111
    758 .db 0b10001111
    759 .db 0b10011111
    760 .db 0b10111111
    761 .db 0b11111111

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.