Jump to content
Sign in to follow this  
its-a-feature

Could someone explain how to edit PF0-2 mid scanline?

Recommended Posts

Hi, so I'm just getting into 6502 assembly programming, and I'm having a hard time figuring out how to edit PF1 mid scanline so that I can make an asymmetrical playfield.

I was wondering if anybody could explain it to me, with code examples if possible.

 

Also I'm on PAL, so I have 242 screenlines instead of 192.

Share this post


Link to post
Share on other sites

In a nutshell, you need to count cycles for your scanlines, and write to the registers at the right time.  For the left half of the playfield, you write to the playfield registers before they are displayed on the screen.  For the right half of the screen, you write to each of these registers again after the left portion of that playfield register has finished displaying, and before the right half has begun displaying. This timing chart is invaluable for determining when to perform these playfield register writes.

 

For example, for PF0, for the left half of the playfield, you will want to complete the first write to this register by cycle 22.  For the second write, you will want to complete the write between cycle 28 (when the left half of PF0 has been drawn) and cycle 49 (when the right half of PF0 starts to display).

 

TIA-timing.thumb.png.0a17460dd4a1411b1d16cba679b3919d.png

  • Like 1

Share this post


Link to post
Share on other sites
30 minutes ago, Karl G said:

In a nutshell, you need to count cycles for your scanlines, and write to the registers at the right time.  For the left half of the playfield, you write to the playfield registers before they are displayed on the screen.  For the right half of the screen, you write to each of these registers again after the left portion of that playfield register has finished displaying, and before the right half has begun displaying. This timing chart is invaluable for determining when to perform these playfield register writes.

 

For example, for PF0, for the left half of the playfield, you will want to complete the first write to this register by cycle 22.  For the second write, you will want to complete the write between cycle 28 (when the left half of PF0 has been drawn) and cycle 49 (when the right half of PF0 starts to display).

 

TIA-timing.thumb.png.0a17460dd4a1411b1d16cba679b3919d.png

Okay I tried to take that and implement it, but it's still not working... Is there something I'm missing?

Here's my code...

Kernel
 ldx #242
 lda #$55
 sta COLUPF

LOOP
 cpx #49
 bcs SKIP
 
 lda #%00100000
 sta PF0

SKIP
 sta WSYNC

 dex
 bne LOOP
 rts

 

Share this post


Link to post
Share on other sites
Posted (edited)

Mind that you'll have to (a) write the first value/pattern of PF0 on the start of each scanline for the left side, then wait for PF0 having been actually displayed and then set the new value – and this for each line. Start counting your cycles at WSYNC.

 

E.g.,

 

sta WSYNC ;strobe WSYNC to be woke up at start of next scanline

lda #%00010000 ;[3 cycles]
sta PF0        ;[3 cycles, now at 6]

lda #%01110000 ;[3 cycles, now at 9]
sta PF1        ;[3 cycles, now at 12]

lda #%11111100 ;[3 cycles, now at 15]
sta PF2        ;[3 cycles, now at 18]

lda #00010000  ;[3 cycles, now at 21] load right-side PF0

;now wait until PF0 has been displayed
;scanline display starts at the end of cycle 23
;+ 4 fat pixels = 4 * 4 / 3 (pixels per CPU cycle) = 5.333
;so we'll have to wait at least until cycle #28 has passed.
;on the other hand, we should be done before cycle #49,
;when PF0 is used by the TIA again for the right side.

nop ;[2 cycles, now at 23]
nop ;[2 cycles, now at 25]
nop ;[2 cycles, now at 27]

;mind that the value will be actually set only at the end of
;the last cycle of the STA instruction, so we're good to go

sta PF0 ;[3 cycles, now at 30]

; now wait for PF1 (compare the chart)
; and for PF2 ...

 

Edited by NoLand
  • Like 1

Share this post


Link to post
Share on other sites
10 minutes ago, NoLand said:

Mind that you'll have to (a) write the first value/pattern of PF0 on the start of each scanline for the left side, then wait for PF0 having been actually displayed and then set the new value – and this for each line. Start counting your cycles at WSYNC.

 

E.g.,

 

sta WSYNC ;strobe WSYNC to be woke up at start of next scanline

lda #%00010000 ;[3 cycles]
sta PF0        ;[3 cycles, now at 6]

lda #%01110000 ;[3 cycles, now at 9]
sta PF1        ;[3 cycles, now at 12]

lda #%11111100 ;[3 cycles, now at 15]
sta PF2        ;[3 cycles, now at 18]

lda #00010000  ;[3 cycles, now at 21] load right-side PF0

;now wait until PF0 has been displayed
;scanline display starts at the end of cycle 23
;+ 4 fat pixels = 4 * 4 / 3 (pixels per CPU cycle) = 5.333
;so we'll have to wait at least until cycle #28 has passed.
;on the other hand, we should be done before cycle #49,
;when PF0 is used by the TIA again for the right side.

nop ;[2 cycles, now at 23]
nop ;[2 cycles, now at 25]
nop ;[2 cycles, now at 27]

;mind that the value will be actually set only at the end of
;the last cycle of the STA instruction, so we're good to go

sta PF0 ;[3 cycles, now at 30]

; now wait for PF1 (compare the chart)
; and for PF2 ...

 

That makes sense, and it works now... thank you!

Share this post


Link to post
Share on other sites
Posted (edited)

Mind that using a mirrored playfield setup (as opposed to a repeated one) will give you some extra time for the last two PF-registers.

(Repeated: 4 + 8 + 8 + 4 + 8 + 8 vs. mirrored: 4 + 8 + 8 + 8 + 8 + 4. Meaning, there are 5 extra cycles for setting the last two PF values, in this case PF1 and PF0.)

Edited by NoLand
  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, its-a-feature said:

I'm having a hard time figuring out how to edit PF1 mid scanline so that I can make an asymmetrical playfield.

 

While you now have this working, Step 3 - Score & Timer display of my Collect Tutorial may add more insight. The tutorial covers the creation of a 2K game from start to end.  

 

The comments of each Step often go into more detail on how things work, such as Step 4's comments with additional information on how the player (sprite) drawing works.

  • Like 1

Share this post


Link to post
Share on other sites

Just starting out?  Here's a snippet from my cheatsheet with essential stuff from the internets.  Probably want to copy and paste it somewhere.  If you stick with the VCS long enough, you'll eventually need all of it.

 

I don't remember where the playfield chart came from.  (Sorry.)  It must be from the old mailing list.  Credit to Omegamatrix for the division routines and Brad Mott for the motion information.

 

 

0 inclusive (0-75) table

Asymmetrical Playfield, Repeated Graphics (PF0-PF1-PF2-PF0-PF1-PF2):

==============================================
| Playfield Register |  Earliest  |  Latest  |
==============================================
|  Left copy of PF0  | Cycle 52 * | Cycle 20 |
|  Left copy of PF1  | Cycle 63 * | Cycle 26 |
|  Left copy of PF2  | Cycle 74 * | Cycle 36 |
| Right copy of PF0  | Cycle 26   | Cycle 47 |
| Right copy of PF1  | Cycle 36   | Cycle 52 |
| Right copy of PF2  | Cycle 47   | Cycle 63 |
==============================================

Asymmetrical Playfield, Reflected Graphics (PF0-PF1-PF2-PF2-PF1-PF0):

==============================================
| Playfield Register |  Earliest  |  Latest  |
==============================================
|  Left copy of PF0  | Cycle 74 * | Cycle 20 |
|  Left copy of PF1  | Cycle 68 * | Cycle 26 |
|  Left copy of PF2  | Cycle 58 * | Cycle 36 |
| Right copy of PF2  | Cycle 47   | Cycle 47 |
| Right copy of PF1  | Cycle 36   | Cycle 58 |
| Right copy of PF0  | Cycle 26   | Cycle 68 |
==============================================


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

     HMPx values
     0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f     
Cyc
10   0  -1  -2  -2  -2  -2  -2  -2   8   7   6   5   4   3   2   1  ** HBLANK
11   0  -1  -1  -1  -1  -1  -1  -1   8   7   6   5   4   3   2   1     HBLANK
12   0   0   0   0   0   0   0   0   8   7   6   5   4   3   2   1     HBLANK
13   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1     HBLANK
14   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1  ** HBLANK
15   2   2   2   2   2   2   2   2   8   7   6   5   4   3   2   2     HBLANK
16   3   3   3   3   3   3   3   3   8   7   6   5   4   3   3   3     HBLANK
17   4   4   4   4   4   4   4   4   8   7   6   5   4   4   4   4     HBLANK
18   4   4   4   4   4   4   4   4   8   7   6   5   4   4   4   4  ** HBLANK
19   5   5   5   5   5   5   5   5   8   7   6   5   5   5   5   5     HBLANK
20   6   6   6   6   6   6   6   6   8   7   6   6   6   6   6   6     HBLANK
21   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0     
22   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0     
 .
 .
53   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0     
54   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0     
55   0   0   0   0   0   0   0  -1   0   0   0   0   0   0   0   0     
56   0   0   0   0   0   0  -1  -2   0   0   0   0   0   0   0   0     
57   0   0   0   0   0  -1  -2  -3   0   0   0   0   0   0   0   0     
58   0   0   0   0   0  -1  -2  -3   0   0   0   0   0   0   0   0   **
59   0   0   0   0  -1  -2  -3  -4   0   0   0   0   0   0   0   0  
60   0   0   0  -1  -2  -3  -4  -5   0   0   0   0   0   0   0   0
61   0   0  -1  -2  -3  -4  -5  -6   0   0   0   0   0   0   0   0
62   0   0  -1  -2  -3  -4  -5  -6   0   0   0   0   0   0   0   0  **
63   0  -1  -2  -3  -4  -5  -6  -7   0   0   0   0   0   0   0   0
64  -1  -2  -3  -4  -5  -6  -7  -8   0   0   0   0   0   0   0   0
65  -2  -3  -4  -5  -6  -7  -8  -9   0   0   0   0   0   0   0  -1
66  -2  -3  -4  -5  -6  -7  -8  -9   0   0   0   0   0   0   0  -1  **
67  -3  -4  -5  -6  -7  -8  -9 -10   0   0   0   0   0   0  -1  -2 
68  -4  -5  -6  -7  -8  -9 -10 -11   0   0   0   0   0  -1  -2  -3
69  -5  -6  -7  -8  -9 -10 -11 -12   0   0   0   0  -1  -2  -3  -4
70  -5  -6  -7  -8  -9 -10 -11 -12   0   0   0   0  -1  -2  -3  -4  **
71  -6  -7  -8  -9 -10 -11 -12 -13   0   0   0  -1  -2  -3  -4  -5
72  -7  -8  -9 -10 -11 -12 -13 -14   0   0  -1  -2  -3  -4  -5  -6 
73  -8  -9 -10 -11 -12 -13 -14 -15   0  -1  -2  -3  -4  -5  -6  -7
74  -8  -9 -10 -11 -12 -13 -14 -15   0  -1  -2  -3  -4  -5  -6  -7  **
75   0  -1  -2  -3  -4  -5  -6  -7   8   7   6   5   4   3   2   1     HBLANK
76   0  -1  -2  -3  -4  -5  -6  -7   8   7   6   5   4   3   2   1     HBLANK
77   0  -1  -2  -3  -4  -5  -6  -7   8   7   6   5   4   3   2   1     HBLANK
78   0  -1  -2  -3  -4  -5  -6  -7   8   7   6   5   4   3   2   1     HBLANK
79   0  -1  -2  -3  -4  -5  -6  -7   8   7   6   5   4   3   2   1     HBLANK
80   0  -1  -2  -3  -4  -5  -6  -6   8   7   6   5   4   3   2   1     HBLANK
81   0  -1  -2  -3  -4  -5  -5  -5   8   7   6   5   4   3   2   1     HBLANK
82   0  -1  -2  -3  -4  -5  -5  -5   8   7   6   5   4   3   2   1  ** HBLANK
83   0  -1  -2  -3  -4  -4  -4  -4   8   7   6   5   4   3   2   1     HBLANK
84   0  -1  -2  -3  -3  -3  -3  -3   8   7   6   5   4   3   2   1     HBLANK
85   0  -1  -2  -2  -2  -2  -2  -2   8   7   6   5   4   3   2   1     HBLANK
86   0  -1  -2  -2  -2  -2  -2  -2   8   7   6   5   4   3   2   1  ** HBLANK
87   0  -1  -1  -1  -1  -1  -1  -1   8   7   6   5   4   3   2   1     HBLANK
88   0   0   0   0   0   0   0   0   8   7   6   5   4   3   2   1     HBLANK
89   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1     HBLANK
90   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1  ** HBLANK
91   2   2   2   2   2   2   2   2   8   7   6   5   4   3   2   2     HBLANK
92   3   3   3   3   3   3   3   3   8   7   6   5   4   3   3   3     HBLANK
93   4   4   4   4   4   4   4   4   8   7   6   5   4   4   4   4     HBLANK

Notice that 10 + 76 = 86 and the table is repeating...

10   0  -1  -2  -2  -2  -2  -2  -2   8   7   6   5   4   3   2   1  ** HBLANK
11   0  -1  -1  -1  -1  -1  -1  -1   8   7   6   5   4   3   2   1     HBLANK
12   0   0   0   0   0   0   0   0   8   7   6   5   4   3   2   1     HBLANK
13   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1     HBLANK
14   1   1   1   1   1   1   1   1   8   7   6   5   4   3   2   1  ** HBLANK
15   2   2   2   2   2   2   2   2   8   7   6   5   4   3   2   2     HBLANK
16   3   3   3   3   3   3   3   3   8   7   6   5   4   3   3   3     HBLANK
17   4   4   4   4   4   4   4   4   8   7   6   5   4   4   4   4     HBLANK

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Unsigned Integer Division Routines
; by Omegamatrix


;Divide by 2
;1 byte, 2 cycles
  lsr


;Divide by 3
;18 bytes, 30 cycles
  sta  temp
  lsr
  adc  #21
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr


;Divide by 4
;2 bytes, 4 cycles
  lsr
  lsr


;Divide by 5
;18 bytes, 30 cycles
  sta  temp
  lsr
  adc  #13
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr


;Divide by 6
;17 bytes, 30 cycles
  lsr
  sta  temp
  lsr
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr


;Divide by 7 (From December '84 Apple Assembly Line)
;15 bytes, 27 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr


;Divide by 8
;3 bytes, 6 cycles
  lsr
  lsr
  lsr


;Divide by 9
;17 bytes, 30 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 10
;17 bytes, 30 cycles
  lsr
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr


;Divide by 11
;20 bytes, 35 cycles
  sta  temp
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 12
;17 bytes, 30 cycles
  lsr
  lsr
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr


; Divide by 13
; 21 bytes, 37 cycles
  sta  temp
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  clc
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 14
;1/14 = 1/7 * 1/2
;16 bytes, 29 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 15
;14 bytes, 24 cycles
  sta  temp
  lsr
  adc  #4
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 16
;4 bytes, 8 cycles
  lsr
  lsr
  lsr
  lsr


;Divide by 17
;18 bytes, 30 cycles
  sta  temp
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  adc  #0
  lsr
  lsr
  lsr
  lsr


;Divide by 18 = 1/9 * 1/2
;18 bytes, 32 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 19
;17 bytes, 30 cycles
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 20
;18 bytes, 32 cycles
  lsr
  lsr
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr


;Divide by 21
;20 bytes, 36 cycles
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 22
;21 bytes, 34 cycles
   lsr
   cmp  #33
   adc  #0
   sta  temp
   lsr
   adc  temp
   ror
   adc  temp
   ror
   lsr
   adc  temp
   ror
   lsr
   lsr
   lsr


;Divide by 23
;19 bytes, 34 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 24
;15 bytes, 27 cycles
   lsr
   lsr
   lsr
   sta   temp
   lsr
   lsr
   adc   temp
   ror
   lsr
   adc   temp
   ror
   lsr


;Divide by 25
;16 bytes, 29 cycles
  sta  temp
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 26
;21 bytes, 37 cycles
  lsr
  sta  temp
  lsr
  adc  temp
  ror
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr


;Divide by 27
;15 bytes, 27 cycles
  sta  temp
  lsr
  adc  temp
  ror
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 28
;14 bytes, 24 cycles
  lsr
  lsr
  sta  temp
  lsr
  adc  #2
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr


;Divide by 29
;20 bytes, 36 cycles
  sta  temp
  lsr
  lsr
  adc  temp
  ror
  adc  temp
  ror
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 30
;14 bytes, 26 cycles
  sta  temp
  lsr
  lsr
  lsr
  lsr
  sec
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 31
;14 bytes, 26 cycles
  sta  temp
  lsr
  lsr
  lsr
  lsr
  lsr
  adc  temp
  ror
  lsr
  lsr
  lsr
  lsr


;Divide by 32
  lsr
  lsr
  lsr
  lsr
  lsr

 

Share this post


Link to post
Share on other sites
18 hours ago, orange808 said:

 

Asymmetrical Playfield, Reflected Graphics (PF0-PF1-PF2-PF2-PF1-PF0):

==============================================
| Playfield Register |  Earliest  |  Latest  |
==============================================
|  Left copy of PF0  | Cycle 74 * | Cycle 20 |
|  Left copy of PF1  | Cycle 68 * | Cycle 26 |
|  Left copy of PF2  | Cycle 58 * | Cycle 36 |
| Right copy of PF2  | Cycle 47   | Cycle 47 |
| Right copy of PF1  | Cycle 36   | Cycle 58 |
| Right copy of PF0  | Cycle 26   | Cycle 68 |
==============================================

 

In Stay Frosty 2 I used an asymmetrical Playfield with Reflected Graphics. The right copy of PF2 had to be updated at cycle 48.

 

.platformLoop
        lda (FrostyImagePtr+.SEC*2),y ; 5  64
        and (FrostyMaskPtr+.SEC*2),y  ; 5  69
        sta WSYNC                     ; 3  72
        sta GRP0                      ; 3
        lda (FrostyColorPtr+.SEC*2),y ; 5   8
        sta COLUP0                    ; 3  11
        ldx Platforms+.SEC*4-4        ; 3  14
        stx PF1                       ; 3  17
        ldx Platforms+.SEC*4-4+1      ; 3  20
        stx PF2                       ; 3  23
        ldx Platforms+.SEC*4-4+2      ; 3  26
        jsr SLEEP12
        SLEEP 5                       ;17  43
        dey                           ; 2  45
        stx PF2                       ; 3  48 <- must be at 48
        ldx Platforms+.SEC*4-4+3      ; 3  51
        stx PF1                       ; 3  54
        cpy #2                        ; 2  56
        bcs .platformLoop             ; 3  59

 

 

Just confirmed it via Stella:

 

1867505566_ScreenShot2020-05-30at10_40_31AM.thumb.png.7461cc6e945f5d4e2433e2c7133e74ae.png

 

Share this post


Link to post
Share on other sites

Pretty sure there's a note that it's 0-75 (zero inclusive) table.  :)

 

Tomato, tomato.  It's the same cycle.

 

Share this post


Link to post
Share on other sites

Huh, when counting from 0, I end up at cycle 48 for doing the update to PF2 (reflected playfield).  How are you counting your cycles to end up at 47?

 

Actually... nevermind... it's the whole inclusive bit.  You must be a mathematician.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...