Jump to content
IGNORED

Session 13: Playfield Basics


Recommended Posts

Is there a way to get the TIA to end the horizontal blank a little early or late, to shift the playfield (or everything) 1 pixel left or right?  I want to scroll the playfield one pixel at a time.  Otherwise it will be very jerky (four-pixel jumps).

 

No. The finest playfield scroll possible is 4 colour clocks.

Cheers

A

Link to comment
Share on other sites

what will RSYNC (reset sync) do if called 3 colour clocks into a horizontal blank? skip that line?

 

RSYNC resets the TIA's internal horizontal position counter.

 

Now, if I assume this resets the counter back 0, the same point that WSYNC releases, this would be before the sync pulse. So hitting RSYNC during horizontal blank would probably generate a double sync pulse which would probably throw the TV for a loop, probably causing it to skip down to the next line or half line.

 

And even if the TV was able to sync properly, it also wouldn't change the object positions since the counters would still put it the same number of clocks after the end of the sync pulse.

Link to comment
Share on other sites

  • 4 months later...

I wrote to RSYNC 3 CPU cycles into a horizontal blank and this is what I got.

 

I took it a while to find the correct zero point again, so I decided to help it out by calling RSYNC again at the end of that line. It somewhat worked. Player 1 never got back on track, but that could be fixed. I am just trying to get the playfield into new positions.

post-4325-1082215180_thumb.jpg

post-4325-1082215181_thumb.jpg

Link to comment
Share on other sites

I wrote to RSYNC 3 CPU cycles into a horizontal blank and this is what I got.

 

I took it a while to find the correct zero point again, so I decided to help it out by calling RSYNC again at the end of that line.  It somewhat worked.  Player 1 never got back on track, but that could be fixed.  I am just trying to get the playfield into new positions.

 

Very interesting indeed. Keep up the experiments and let us know the results. I'd suggest you post this to the [stella] list, too :)

 

Cheers

A

Link to comment
Share on other sites

  • 6 years later...

I'm hoping that there are still some visiting this that can help me. I took Mr. Davie's playfield code and typed it in manually (instead of copy and paste) to try and understand Assembly and the 2600 as I went along. Upon compiling, DASM didn't return any errors. However, when I tried to run the program through Stella, I'm getting a lot of weird noises and no visuals. I'm going to post the code the way I typed it into Crimson here...

 

; 2600 For Newbies
; Session 13 - Playfields

processor 6502
include "vcs.h"
include "macro.h"

PATTERN = $80
TIMETOCHANGE = 20

SEG
ORG $F000

Reset

ldx #0
lda #0

Clear

sta 0,x
inx
bne Clear

lda #0
sta PATTERN
lda #$45
sta COLUPF
ldy #0

StartOfFrame

lda #0
sta VBLANK
lda #2
sta VSYNC
sta WSYNC
sta WSYNC
sta WSYNC
lda #0
sta VSYNC
ldx #0

VerticalBlank

sta WSYNC
inx
cpx #37
bne VerticalBlank
iny
cpy #TIMETOCHANGE
bne notyet
ldy	#0
inc PATTERN

notyet

lda PATTERN
sta PF1
ldx #0

Picture

stx COLUBK
sta WSYNC
inx
cpx #192
bne Picture
lda #%01000010
sta VBLANK
ldx #0

Overscan

sta WSYNC
inx
cpx #30
bne Overscan
jmp StartOfFrame

ORG $FFFA

InterruptVectors

.word Reset
.word Reset
.word Reset

END

 

On the DASM command line, all I did was type at the prompt: dasm playfield.asm -oplayfield. I'd really like to know what I'm doing wrong. In the code, I didn't use most of the remark statements has I was going to refer to the original if I needed to. Help anyone?

playfield.bin

Link to comment
Share on other sites

On the DASM command line, all I did was type at the prompt: dasm playfield.asm -oplayfield. I'd really like to know what I'm doing wrong. In the code, I didn't use most of the remark statements has I was going to refer to the original if I needed to. Help anyone?

When I copied and pasted your listing into Crimson Editor, then assembled it, it worked for me, so there's nothing wrong with the code. However...

 

(1) I had to add an "INCDIR" at the beginning to tell DASM where the include files are, because I happen to have them in a different folder than DASM and the program code. Make sure DASM knows where the "vsc.h" and "macro.h" files are. I assume you have them in the same folder as DASM, since you apparently didn't get any assembly errors about unknown label names, but this is something to keep in mind.

 

(2) I don't see a "-f3" parameter in your command line. Try this: dasm playfield.asm -f3 -oplayfield.bin

 

Michael

 

Edit: Correction, I just noticed that I was already using the "-I" switch in my command line to tell DASM where I have my include files, so I was able to take out the "INCDIR" line and assemble it just fine. Note that if you're using Crimson Editor, you can configure one User Tool to call DASM to assemble your programs, and another User Tool to call Stella to run them. That's a lot easier than typing in command lines. If you need help setting up User Tools in Crimson Editor, I'd be happy to assist you with it.

Link to comment
Share on other sites

I know I'm probably the only one that is following this right now as I'm a few years behind...but I did manage to figure out how to reverse the colors so that the background has the solid color while the bars have the rainbow colors. That one was easy...just switch the COLUBK and COLUPF commands around.

post-18904-128445260867_thumb.png

playfield.bin

Link to comment
Share on other sites

I would appreciate the help in setting up Crimson User Tools to do those tasks.

To set up a User Tool for assembling with DASM...

 

(1) Start Crimson Editor.

 

(2) Select "Tools" and "Conf. User Tools".

 

(3) Click on the entry you want to set up, presumably the first one that says "- Empty -" (which is probably already highlighted).

 

(4) Click in the "Menu Text:" field and enter whatever you want it to say on the menu-- e.g., "Assemble 6502 Program", or "Assemble with DASM", etc.

 

(5) Click in the "Command:" field and enter the name of the program you want to call (run) whenever you choose this tool, including its path if it isn't in the current folder. I have mine set up to say

 

C:\Atari2600\bB\dasm.exe

 

because I've put DASM in a folder named C:\Atari2600\bB on my computer.

 

(6) Click in the "Argument:" field and enter the *parameters* for the command line. I have mine set up to say

 

"$(FilePath)" -f3 -IIncludes -o"$(FilePath).bin" -l"$(FilePath).lst"

 

In order, these are

 

"$(FilePath)" -- $(FilePath) is Crimson Editor's name for the file that's displayed in the active tab, including its full path (e.g., C:\MyFolder\MyFile.asm). Putting it in quotes lets you include spaces in the path and/or filename without confusing DASM (e.g., "C:\My Folder\My File.asm").

 

-f3 -- tells DASM to output the assembled ROM image in the "raw" format, which is the format required for Atari 2600 ROM images.

 

-IIncludes -- tells DASM which folder the include files are in. This is optional, but is helpful if (like me) you prefer to create subfolders for organizing things. It can be a full path, including surrounding quotes if the path contains spaces in it, or it can be just a folder name if the indicated folder is a subfolder of the current folder.

 

-o"$(FilePath).bin" -- tells DASM what to call the output file. $(FilePath) is described above, but Crimson Editor has other options available (see below). If you use this just as I've shown here, assembling a file named "C:\My Folder\My File.asm" will produce a ROM image named "C:\My Folder\My File.asm.bin".

 

-l"$(FilePath).lst" -- tells DASM what to call the listing file. This is optional, and you might not need to look at the listing file, but I find it helpful to have the assembly listing available in case of bugs, because you can check the listing to see what machine code was generated, along with any error messages. If you use this just as I've shown, assembling a file named "C:\My Folder\My File.asm" will produce a listing named "C:\My Folder\My File.asm.lst".

 

(7) Click in the "Initial Dir:" field and enter the path for the folder you want to use as the "current" or "start in" directory when using this tool. I have mine set to say

 

C:\Atari200\bB

 

(8 ) You can click in the "Hot Key:" field and assign a hot key to this tool if you want.

 

(9) Check or uncheck the boxes for the options you want to use with this tool. For my DASM tool I have the following two boxes checked:

 

Capture output -- so you can see the messages that DASM produces when you run it.

 

Save before execute -- so that if you select this tool without remembering to save any changes first, the file in the active tab will be automatically saved before DASM assembles it.

 

(10) Click on the "Apply" button to save the setup for this tool before you set up another one.

 

 

 

To set up a User Tool for running the assembled program in the Stella emulator...

 

(1) Click on another entry that says "- Empty -". I'll just list what I put in the other fields, since the general procedure is already described above.

 

(2) "Menu Text:" -- Run Program in Stella

 

(3) "Command:" -- C:\Atari\2600\Emus\Stella\3.2.1\32-bit\stella.exe

 

(Your entry will probably look a lot simpler than mine!)

 

(4) "Argument:" -- "$(FilePath).bin"

 

(5) "Initial Dir:" -- C:\Atari\2600\Emus\Stella\3.2.1\32-bit

 

(6) "Hot Key:" -- None

 

(7) Checked options:

 

Close on exit

 

(8 ) Click "Apply", or else click "OK" if you're done setting up your User Tools.

 

 

 

Crimson Editor recognizes the following symbolic names for the file in the active tab:

 

$(FilePath) -- the file path, filename, and file extension.

 

$(FileDir) -- just the file path, *without* the filename and file extension.

 

$(FileName) -- just the filename and file extension, *without* the file path.

 

$(FileTitle) -- just the filename, *without* the file path and file extension.

 

You can combine these if you wish, although the only combination that's of much use is $(FileDir)\$(FileTitle), since that lets you get rid of the original file extension and tack on a different file extension (like ".bin").

 

For example, if the file in the active tab is called C:\My Folder\My File.asm, the various symbolic names would be as follows:

 

$(FilePath) -- C:\My Folder\My File.asm

 

$(FileDir) -- C:\My Folder

 

$(FileName) -- My File.asm

 

$(FileTitle) -- My File

 

$(FileDir)\$(FileTitle).bin -- C:\My Folder\My File.bin

 

$(FileDir)\$(FileTitle).lst -- C:\My Folder\My File.lst

 

 

 

Michael

Link to comment
Share on other sites

While we are on the playfield basics, am I understanding correctly that the 2600 can produce a 160x192 resolution? Am I also understanding correctly that in a single horizontal scanline, I can "control" what playfield pixel goes where by simply knowing where the beam is? Now...if that is the case...and I'm still getting confused on the playfield portion, what Assembly opcodes do I use to start and stop a playfield graphic position?

Link to comment
Share on other sites

While we are on the playfield basics, am I understanding correctly that the 2600 can produce a 160x192 resolution? Am I also understanding correctly that in a single horizontal scanline, I can "control" what playfield pixel goes where by simply knowing where the beam is? Now...if that is the case...and I'm still getting confused on the playfield portion, what Assembly opcodes do I use to start and stop a playfield graphic position?

The "160x192 resolution" is an idealized number that represents the total number of *positions* on the screen, as measured in color clocks and scan lines. (The 2600 can display more than 192 scan lines, but 192 is considered to be the "preferred" number of scan lines for an NTSC game, so we'll stick with that.) Since the playfield is the *only* graphical object on the 2600 that can span the full width of the screen (aside from the background), and playfield pixels are 4 color clocks wide, it's probably more accurate to say that the 2600 has a resolution of 40x192, but with sprites that can have a higher resolution than that. If you use the "score trick" to display 6 player sprites side-by-side (3 copies of player0, and 3 copies of player1), you can display a bitmap with a resolution of 48x192, where each pixel is 1 color clock wide. And if you spread out the copies of the players, and use 30Hz flickering, you can get a resolution of 96x192-- but it isn't a "solid" image, because each pixel will flicker. So even though it's usually stated that the 2600 has a "resolution" of 160x192, you can't actually display an image with that resolution on the screen (i.e., where each 160x192 position is individually addressable).

 

Also, you can't control where a playfield pixel goes on the screen-- the playfield pixels are at set positions, and all you can do is turn a particular playfield pixel on or off. There are only 3 playfield registers-- or to be more exact, 2.5 playfield registers, since one of them (PF0) is only half-size (4 bits or 4 pixels), and the other two are full-size (8 bits or 8 pixels). That gives you 20 playfield pixels that you can turn on or off (4+8+8=20). Since the screen is 40 playfield pixels wide, that means the 20 playfield pixels cover only one-half of the screen. The screen is divided into a left half and a right half, and the same playfield pixels that are drawn on the left half get reused to draw the right half. The left half is always drawn the same way-- PF0 (first 4 playfield pixels), PF1 (next 8 playfield pixels), and PF2 (next 8 playfield pixels). There are two different modes that determine how (or where) the playfield pixels will be displayed for the right half-- repeated mode, and reflected mode. In the repeated mode, the right half of the screen is drawn just like the left half-- PF0, PF1, and PF2. In the reflected mode, the right half of the screen is a mirror image of the left half-- PF2, PF1, and PF0, with the bits of the playfield registers displayed in the opposite order from normal.

 

To get an "asymmetrical" playfield-- where the left and right halves are completely different than each other (neither repeated nor reflected), you have to set the PF0, PF1, and PF2 registers for the left half of the screen, then change them midline before the right half of the screen is drawn. You still have to choose either repeated or reflected mode, and the mode you choose will affect the timing for when you can update each register midline. To set that register for the left half of the screen, you must do so between the time it's finished being drawn on the right half and the time it's starting to be drawn on the left half. And to set that register for the right half of the screen, you must do so between the time it's finished being drawn on the left half and the time it's starting to be drawn on the right half.

 

Updating PF0 (repeated mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|
|. . . . . . . . . . . . . . . . .A. . . .B. . . . . . . . . . . . . . . .C. . . .D. . . . . . . . . . . . . . . .|

For the left copy of PF0, set PF0 to the desired value between point D and point A.

For the right copy of PF0, set PF0 to the desired value between point B and point C.

 

Updating PF1 (repeated mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|
|. . . . . . . . . . . . . . . . . . . . .A. . . . . . . .B. . . . . . . . . . . .C. . . . . . . .D. . . . . . . .|

For the left copy of PF1, set PF1 to the desired value between point D and point A.

For the right copy of PF1, set PF1 to the desired value between point B and point C.

 

Updating PF2 (repeated mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|
D. . . . . . . . . . . . . . . . . . . . . . . . . . . . .A. . . . . . . .B. . . . . . . . . . . .C. . . . . . . .D

For the left copy of PF2, set PF2 to the desired value between point D and point A.

For the right copy of PF2, set PF2 to the desired value between point B and point C.

 

Updating PF0 (reflected mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. . . PF2 . . .|. . . PF1 . . .|. PF0 .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . .|
D. . . . . . . . . . . . . . . . .A. . . .B. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .C. . . .D

For the left copy of PF0, set PF0 to the desired value between point D and point A.

For the right copy of PF0, set PF0 to the desired value between point B and point C.

 

Updating PF1 (reflected mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. . . PF2 . . .|. . . PF1 . . .|. PF0 .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . .|
|. . . . . . . . . . . . . . . . . . . . .A. . . . . . . .B. . . . . . . . . . . . . . . .C. . . . . . . .D. . . .|

For the left copy of PF1, set PF1 to the desired value between point D and point A.

For the right copy of PF1, set PF1 to the desired value between point B and point C.

 

Updating PF2 (reflected mode):

|. . . . . . . . . . . . . . . . .|. . . . left half of the screen . . . .|. . . .right half of the screen . . . .|
|. horizontal blanking interval. .|. PF0 .|. . . PF1 . . .|. . . PF2 . . .|. . . PF2 . . .|. . . PF1 . . .|. PF0 .|
|. . . . . . . . . . . . . . . . .|. . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . . . . . .|. . . .|
|. . . . . . . . . . . . . . . . . . . . . . . . . . . . .A. . . . . . . .B. . . . . . . .C. . . . . . . . . . . .|

For the left copy of PF2, set PF2 to the desired value between point C and point A.

For the right copy of PF2, set PF2 to the desired value *exactly* at point B.

 

The repeated mode gives you the greatest leeway as far as when you can update each register midline, because with the reflected mode the timing for changing PF2 must be exact, since the left and right copies of PF2 are displayed side-by-side in the reflected mode. But even though the repeated mode is the most forgiving as far as the timing of the midline changes, many programs that draw an asymmetrical playfield use the reflected mode, because in that mode the PF0 register appears at the far left and far right sides of the screen, such that you can leave PF0 blank and just use PF1 and PF2 to get a 32x192 playfield if you want.

 

Michael

Link to comment
Share on other sites

There are ways to create the illusion that playfield pixels are being set or cleared on color-clock intervals, tho (such as masking over them using player sprites).

 

BTW the thread linked above details cycle time counts where it's safe to alter playfield registers for each mode...and a handy chart that combines all of this info.

Link to comment
Share on other sites

There are ways to create the illusion that playfield pixels are being set or cleared on color-clock intervals, tho (such as masking over them using player sprites).

True, and you can also turn a playfield pixel on or off *while* it's being drawn (if you couldn't spare a sprite to mask it)-- although you can only do that at intervals of 3 color clocks.

 

BTW the thread linked above details cycle time counts where it's safe to alter playfield registers for each mode...and a handy chart that combines all of this info.

I know. It *is* a handy chart. :) But one thing to be careful of is that the exact timing can vary from machine to machine (specifically on Gemini "clones"? I forget which machine it is). I made a chart that should work for either case (the standard timing or the very-slightly-delayed timing), and I posted it somewhere in the forums, but I'll have to dig around for it.

 

Michael

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...