Jump to content

Photo

Session 18: Asymmetrical Playfields - Part 2


25 replies to this topic

#1 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • 1,782 posts
  • Dr.Boo
  • Location:Tasmania

Posted Fri Jun 27, 2003 8:34 AM

The following diagram shows the timing relationship between the TIA, the 6502, and playfield pixels. Further, it shows the times at which it is safe to write the playfield registers for both left and right-sides of the screen.

Attached Thumbnails

  • 2600timing2.png


#2 rixard OFFLINE  

rixard

    Combat Commando

  • 8 posts
  • Location:Sweden

Posted Fri Jun 27, 2003 9:44 AM

I have been reading these lessons for a couple of days now. I'm starting to learn a few things here... a few things there :) It's so great you're doing this.

Why not eventually show how to move sprites, how to implement simple routines (enemies moving towards the player, collision checks) or more simply... show how to make a simple game and explain everything.Step by step :)

#3 Pitfall Harry OFFLINE  

Pitfall Harry

    Stargunner

  • 1,993 posts
  • Location:Glendora, CA

Posted Fri Jun 27, 2003 9:56 AM

The graphic certainly lives up to its namesake. It truly is an "Incredibly Good Timing Diagram."

The only thing I'd add to the diagram is an annotation or a footnote stating that a write to the WSYNC register halts the microprocessor until the TIA gets to time zero, the start of the Horizontal Blanking period. I was confused over this "obvious" fact for the longest time, thinking the microprocessor resumed execution immediately AFTER the 68 color clocks of Horizontal Blanking.

Ben

#4 Happy_Dude OFFLINE  

Happy_Dude

    River Patroller

  • 4,212 posts
  • Forum Slacker
  • Location:Sydney, Australia

Posted Fri Jun 27, 2003 10:05 AM

The graphic certainly lives up to its namesake. It truly is an "Incredibly Good Timing Diagram."

The only thing I'd add to the diagram is an annotation or a footnote stating that a write to the WSYNC register halts the microprocessor until the TIA gets to time zero, the start of the Horizontal Blanking period.  I was confused over this "obvious" fact for the longest time, thinking the microprocessor resumed execution immediately AFTER the 68 color clocks of Horizontal Blanking.

Ben

Thanks :) I was just about to ask that one :D

#5 Emehr OFFLINE  

Emehr

    River Patroller

  • 4,189 posts
  • Happiness is... a chomping Pac-Man!
  • Location:An obscure body in the SK system

Posted Fri Jun 27, 2003 2:04 PM

Excellent diagram. Now I have something to compare to my sketches! Keep up the great work, Andrew. I'm lovin' this tutorial and have been following it closely.

Right now I have an animated sprite that can run around the screen. When he gets above the "horizon" his sprite goes into jump mode, although you can still move him around like he were walking...sort of a Crouching Tiger, Hidden Dragon thing. :)

Thanks!
Jason Rein

#6 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,782 posts
  • Dr.Boo
  • Location:Tasmania

Posted Fri Jun 27, 2003 4:22 PM

Why not eventually show how to move sprites, how to implement simple routines (enemies moving towards the player, collision checks) or more simply... show how to make a simple game and explain everything.Step by step :)


Patience, young Jedi master! All things will be revealed to those who seek the way.

#7 Sheldon Sims OFFLINE  

Sheldon Sims

    Chopper Commander

  • 112 posts
  • Location:San Fernando, Trinidad, West Indies

Posted Fri Jun 27, 2003 10:59 PM

I am also enjoying this tutorial. You are doing a great job on it. I am spending most of my time away from work following this tutorial. I can't get away from it. It is challenging, yet fun. Keep up the good work. 8)

#8 rixard OFFLINE  

rixard

    Combat Commando

  • 8 posts
  • Location:Sweden

Posted Sat Jun 28, 2003 9:44 AM

I shall wait master ;)

I'm thinking of converting a little game I wrote in BASIC to the Atari 2600. The game was called NEOBYKE and was based on the lightcycles in the movie TRON. So I'm trying to learn 6502(6507) assembly to get the job done :) In a way it's much more fun program for a console like the 2600. I mean, anyone can write a game for the PC but it'll just drown with 1000s of other similar games. And besides, the 2600 is quite a beast and being able to tame it... well then I suppose you COULD call yourself a jedi master ;)

Keep up the good work.

#9 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,782 posts
  • Dr.Boo
  • Location:Tasmania

Posted Tue Jul 1, 2003 7:17 AM

Thomas Jentzsch has pointed out that there is a mimimum delay before a change to a TIA playfield register becomes visible. He suggests ~2 TIA clocks.

When one considers that a 6502 instruction may take anywhere from 2 cycles (=6 TIA colour clocks) to 7 cycles, it is apparent that any particular 6502 instruction "occupies" a fairly wide slice of TIA time during its execution. All instructions require a fetch of the opcode (=6502 instruction) from memory, the decoding and execution of that instruction, and sometimes a write of data back to memory.

These stages of 'execution' of an instruction happen at various times during the time taken to execute the entire instruction. For example, the first cycle of the total instruction time might be allocated to retrieving the opcode from ROM. The second might be allocated to decoding and executing some of the instruction. Truth be told, I'm not really sure what happens when - it will differ for each of the instructions and addressing (=access to memory) modes.

The point is, though, that when we write to the TIA playfield registers (or any other register for that matter), one may have to make allowances for the fact that although you may start an instruction on a particular TIA / 6502 clock cycle, the actual write to the TIA memory/register will most definitely not happen until 2 or more cycles later - and that depends on the addressing mode. We will cover addressing modes later - but basically they deal with ways of accessing memory (eg: directly, indirectly via pointers, via a list (indexec), etc).

The timing diagram above should be considered to indicate the time at which TIA playfield registers must be updated by, for correct playfield data to be displayed.

Another issue altogether - and one I simply don't know the answer to right now - is *EXACTLY* what happens when you write to a playfield register when that playfield register is currently being displayed. I am not sure exactly what timing constraints determine which pixel is displayed in which situation - the old or the new. Thomas has also indicated that there are some reports of consoles behaving differently when you get into this sort of extreme 'pushing the envelope' timing, too.

#10 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • 22,775 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Tue Jul 1, 2003 9:07 AM

I am sure the emulator programmers know the exact answers.

Eckhard?

#11 Eckhard Stolberg OFFLINE  

Eckhard Stolberg

    Dragonstomper

  • 957 posts
  • Location:Germany

Posted Tue Jul 1, 2003 2:02 PM

On the Atari VCS you can't change the state of a playfield pixel while it is being processed. So, for example, you could write the data for the right copy of PF2 while the last pixel of the left copy PF2 is still being displayed. This pixel will stay on or off, even if the new value is the opposite of it's current state.

You can however change the colour of a playfield pixel while it is diplayed. The colour information is evaluated ion a TIA-pixel by TIA-pixel basis. So if you wrote to COLUPF in such a way that the write finishes halfway though a playfield pixel, then it's first two TIA-pixels will have the old colour and it's last two TIA-pixels will have the new colour.

I have heard reports that the Coleco expansion module behaves a bit differently when rewriting playfield registers, but I don't know the exact timing either.


Ciao, Eckhard Stolberg

#12 SmileyDude OFFLINE  

SmileyDude

    Moonsweeper

  • 262 posts
  • 6502 Hacker
  • Location:Wilmington, MA

Posted Tue Jul 1, 2003 5:59 PM

So, from what Eckhard is saying, it sounds as if the TIA latches the value of the PFx register when it starts drawing, and uses that value, even if the original value changes. Does that sound right?

BTW, I've been working off the assumption that as long as the instruction finishes on or before the cycle on the chart, that should be fine. For example, PF0 finishes at 6502 cycle 28, so as long as my STA PF0 finishes at cycle 28 or later, it should be fine. But, I've been waiting for the TIA to finish drawing a particular portion of the playfield (i.e, I'm stuffing the values into the registers as early as I possibly can, and I'm just waiting for the register to be free again), so my assumptions may be completely wrong. And considering what Eckard said, it might not matter anyway :)

So, does anyone know for certain how the timing works for these fringe cases? If I reverse my example above, if I have a STA PF1 that takes 3 cycles, and I start it on 6502 cycle 25, since it finished on cycle 28, will that display properly? Logically, it should work since the instruction is finished at cycle 28, and the TIA shouldn't be drawing until when cycle 29 begins...

#13 SmileyDude OFFLINE  

SmileyDude

    Moonsweeper

  • 262 posts
  • 6502 Hacker
  • Location:Wilmington, MA

Posted Tue Jul 1, 2003 6:03 PM

Dang it -- I just re-read Eckards post... the TIA appears to be latching a single pixel, not the entire value of PFx, right? That actually makes more sense when I look at it :)

#14 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Tue Jul 1, 2003 9:00 PM

As our knowledge of playfield manipulation increases, so does the desire to create more complex backgrounds. What are the best tools to design playfields? I think someone mentioned not so long ago the use of an Excel spreadsheet as a huge grid map. If there is any experienced homebrewer out there reading this: what have worked best for you?

#15 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,782 posts
  • Dr.Boo
  • Location:Tasmania

Posted Tue Jul 1, 2003 9:06 PM

As our knowledge of playfield manipulation increases, so does the desire to create more complex backgrounds. What are the best tools to design playfields? I think someone mentioned not so long ago the use of an Excel spreadsheet as a huge grid map. If there is any experienced homebrewer out there reading this: what have worked best for you?



I draw my stuff in a paint program, save it out as a 40 x 192 pixel file (or whatever depth you like) and run it through a tool written for the purpose. This tool creates tables of data which can be simply copied to the screen as required. I'm happy to share it - but it's not that tricky to write your own.

#16 Eckhard Stolberg OFFLINE  

Eckhard Stolberg

    Dragonstomper

  • 957 posts
  • Location:Germany

Posted Wed Jul 2, 2003 1:40 PM

Dang it -- I just re-read Eckards post... the TIA appears to be latching a single pixel, not the entire value of PFx, right?  That actually makes more sense when I look at it :)


This is correct. If you change a playfield register while the third playfield pixel is currently being displayed, then the first three playfield pixels will be taken from the old value in the playfield register, and the last five playfield pixels will be taken from the new value.


Ciao, Eckhard Stolberg

#17 EricBall OFFLINE  

EricBall

    Dragonstomper

  • 793 posts
  • Location:Markham, Ontario, Canada

Posted Thu Jul 3, 2003 10:00 AM

This is correct. If you change a playfield register while the third playfield pixel is currently being displayed, then the first three playfield pixels will be taken from the old value in the playfield register, and the last five playfield pixels will be taken from the new value.


Which TIA cycle does the 6507 write cycle "complete" on? The last third, I think, right?

#18 Eckhard Stolberg OFFLINE  

Eckhard Stolberg

    Dragonstomper

  • 957 posts
  • Location:Germany

Posted Thu Jul 3, 2003 1:36 PM

I'm not quite sure if I understand your question correctly. Is it about the relation between the TIA clock and the processor clock?

There are three TIA cycles for every CPU cycle. The CPU dosn't do anything between the cycles it gets clocked with, so CPU write cycles (like all other CPU cycles too) happen on every third TIA cycle. If you'd do something like:

sta WSYNC

nop

nop

nop

nop

nop

nop

nop

nop

nop

nop

sta COLUBK

then the background colour would change after the first TIA pixel has already been drawn, because the STA COLUBK would finisch it's write cycle at CPU cycle 23 (which is TIA cycle 69, which is one TIA cycle after the horizontal blank period).


Ciao, Eckhard Stolberg

#19 EricBall OFFLINE  

EricBall

    Dragonstomper

  • 793 posts
  • Location:Markham, Ontario, Canada

Posted Sat Jul 5, 2003 9:42 AM

then the background colour would change after the first TIA pixel has already been drawn, because the STA COLUBK would finisch it's write cycle at CPU cycle 23 (which is TIA cycle 69, which is one TIA cycle after the horizontal blank period).

Thanks, that was the info I was looking for.

#20 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Mon Jul 7, 2003 11:59 AM

The assymmetric chart has been extremely helpful to me. I first read about the timing quirk in "How to draw an assymetrical playfield" source sample at The Dig but never fully understood it until now. Here is the stuff I did: Sample1.zip is a mockup of the Donkey Kong stage. Sample2.zip is the Atari Age banner, 2600 style :)

For the last one I changed the PF color once per frame right before the text logo for a simple color cycling effect. While doing this I found myself thinking where to "put it". I needed 9 free cpu cycles that wouldn't interfere with the PF writing code. After some trial and error I put it somewhere at beginning of the scan loop.

1) Is it possible to create the data tables in a separate text file and have it inserted into our program as an 'include "mypfdata.h"'?
2) I used PF data tables to draw my assymetrical playfields. The data is for every scanline in the visible kernel. The drawings I did have empty spaces at the top and bottom. This translates into a lot of zero byte entries, that takes valuable ROM space. I could shave off those data lines and adjust the kernel code accordingly. Is there is another way?

Attached Thumbnails

  • sample1.jpg
  • sample2.jpg

Attached Files



#21 Christopher Tumber OFFLINE  

Christopher Tumber

    Chopper Commander

  • 147 posts
  • Location:Toronto

Posted Mon Jul 7, 2003 1:38 PM

1) Is it possible to create the data tables in a separate text file and have it inserted into out program as an 'include "mypfdata.h"'?


Yes. That's really all the line:

include vcs.h

does.

2) I used PF data tables to draw my assymetrical playfields. The data is for every scanline in the visible kernel. The drawings I did have empty spaces at the top and bottom. This translates into a lot of zero byte entries, that takes valuable ROM space. I could shave off those data lines and adjust the kernel code accordingly. Is there is another way?


Yes, there's always another way.

Here are a couple suggestions...

If the blank lines are a known constant, then at the top and bottom of the screen (ie: Before and after you actually start drawing) you can add something like:


   lda #10

nextblank:

   sta WSYNC

   dex

   bpl nextblank


where #10 is the number of blank lines you need.

If the number of blank lines is not constant (ie: You're writing a general purpose screen display routine that could display any of several different "bitmaps") then you can turn taht #10 into a variable.

Or, you could include it all in your graphics data like:


   ldy GraphicsData ;Get number of blank lines at top

nextblankline1:

   sta WSYNC

   dey

   bne nextblankline1



   ldx #0;Index of graphics data



   ldy GraphicsData+1

nextdrawline:

   sta WSYNC

   lda GraphicsData1,x

   sta PF0

   lda GraphicsData2,x

   sta PF1

   lda GraphicsData3,x

   sta PF2

   nop

  ;Some NOPs in here, I'm not going to cycle count

   nop

   lda GraphicsData4,x

   sta PF0

   lda GraphicsData5,x

   sta PF1

   lda GraphicsData6,x

   sta PF2

   inx

   dey

   bne nextdrawline



   ldy GraphicsData+2 ;Get number of blank lines at bottom

nextblankline2:

   sta WSYNC

   dey

   bne nextblankline2



GraphicsData: .byte 20;10 blank lines at top

                      .byte 150;150 lines of graphics

                      .byte 22;22 blank lines at bottom

GraphicsData1: .byte ;150 bytes of data for left PF0

GraphicsData2: .byte ;150 bytes of data for left PF1

GraphicsData3: .byte ;150 bytes of data for left PF2

GraphicsData4: .byte ;150 bytes of data for right PF0

GraphicsData5: .byte ;150 bytes of data for right PF1

GraphicsData6: .byte ;150 bytes of data for right PF2



You can further abstract that by using indexed indirect addressing: lda (),y but that should wait until Andrew explains the more advanced addressing modes...


Chris...

#22 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Mon Jul 7, 2003 10:15 PM

When I place the include command (for PF data) at the beginning of the asm file, right after the macro.h and vcs.h includes, dasm gives me errors. If I put it where the data tables would usually be (before the org $fffa) it works fine though. Why doesn't dasm allows this?

Here is a quote of the dasm results:

9 references to unknown symbols.
7 events requiring another assembler pass.
- Expression in mnemonic not resolved.
- Obscure reason - to be documented :)

--- Unresolved Symbol List
NO_ILLEGAL_OPCODES       0000 ????         (R )
PFData0A                 10000 ????         (R )
PFData0B                 100a7 ????         (R )
PFData1A                 10037 ????         (R )
PFData1B                 100df ????         (R )
PFData2A                 1006f ????         (R )
PFData2B                 10117 ????         (R )
--- 7 Unresolved Symbols



#23 Christopher Tumber OFFLINE  

Christopher Tumber

    Chopper Commander

  • 147 posts
  • Location:Toronto

Posted Mon Jul 7, 2003 11:30 PM

When I place the include command (for PF data) at the beginning of the asm file, right after the macro.h and vcs.h includes, dasm gives me errors.


Yes, because the assembler tries put the included file right where you have the INCLUDE command which in this case is before all the rest of your code. And given it's probably before any ORG statements this is a real problem! (The assembler doesn't know where to put the PFData tables). An include file consisting entirely of label definitions and/or macros is the only include file you're going to put at the very top with VCS.H and MACROS.H. Labels and macros don't really care because they aren't "anchored" to any specific place in ROM. However any code or data must be put in a specific ROM location.

In other words,


   include File1

   include File2

   include File3


Will give you a completely different result than:


   include File3

   include File2

   include File1


Just like:

  lda #$10

  sta $80

Is completely different from:

  sta $80

  lda #$10



All the INCLUDE command does is drop the included file directly in that spot. If you put everything back into one file like it was originally, would it make a difference if you moved all those PFData tables to the very start of your code? That's what you did by putting the include up there.


If you have to, think of an include file as a super label. So just as:

   TMP EQU $80

   LDA TEMP

is really just:

   LDA $80

because the label TEMP gets replaced by the $80. So too your INCLUDE statement gets replaced, right there, with the contents of the included file.


Chris...

#24 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Tue Jul 8, 2003 12:06 AM

Very interesting. I was thinking about it in C terms, where the includes are always declared at the start of your code, but this is obviously not the case. Thanks for the help! :)

#25 Cybergoth OFFLINE  

Cybergoth

    Quadrunner

  • 8,826 posts
  • This is Sparta!
  • Location:Bavaria

Posted Tue Jul 8, 2003 1:35 AM

Hi there!

Very interesting. I was thinking about it in C terms, where the includes are always declared at the start of your code, but this is obviously not the case. Thanks for the help! :)


Actually in C it works exactly the same. :)

Greetings,
Manuel




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users