Jump to content
IGNORED

Old Timer - New to 2600 Programming


jdrose

Recommended Posts

Hello,

 

I've recently become unemployed and have found myself without much money but with plenty of time. Been spending some of that time in thrift shops and discovered the 2600 in the form of a "Flashback 2" console. Way back in the day I did not have an Atari VCS 2600 system but many of my friends did. I recalled not being impressed with the machine at all. Especially after playing the uprights in arcades. The games on the VCS had terrible sound, Pacman flickered like mad and the graphics were blocky. Haven't given the system much thought in 33 years.

 

After discovering the "Flashback 2" and titles like Missile Command, Saboteur, Pitfall and Quadrun I am willing to give this little system a second chance. Properly programmed it is quite capable of producing good sound and graphics. And more importantly, good fun!

 

Since learning how the hardware is so limited I am even more impressed with the games: only 128 bytes of RAM, 4K of ROM, no OS/kernal graphics firmware, no video RAM, primitive drawing hardware, software must be raster timed, etc. My experience is programing the C64 and Atari 1040ST. The 2600 seems to be quite challenging. Looking forward to writing code for this machine.

 

I guess I will use DASM as it has headers specifically for the 2600. Kind of wild though. Been a long time since I used any command line operated software. Just getting DASM running will be a bit of a challenge for me. LOL!

 

 

I've read all the tutorials and documents I can find on programming the 2600 but I have a few questions that I could not find answers to:

 

* I am guessing the 128 bytes of RAM are mapped in Zero Page. What addressed RAM locations are available to the programmer?

 

* Is there enough room to write useful rewriteable code?

 

* When turned on will the 6507 sometimes randomly be in BCD mode? Should I always do a CLD to make sure it is in binary mode?

 

* Is the reset button a hard or soft reset? Does the hardware do a hard reset right after power up?

 

* What are "mirrored" addresses in the 2600 memory map? How are they used?

 

* Does DASM support undocumented, but often used, opcodes?

 

* On a stock VCS and 4K cartridge what is the address of the first opcode to be run on power up? I am guessing $E000.

 

* The VCS was introduced when all TVs were Cathode Ray Tube based. Any modification to code/timing needed to be made for

modern TVs with LCD, Plasma, LED, etc. displays?

 

* What make and model of PROM do you recommend for cartridges?

 

* How do you get the binary code from the PC to the 2600 for testing? PROM burner each time or perhaps some type of DIY serial device?

 

* Does anyone manufacture the handled cartridge cases, ala Air Raid, Enduro, anymore? Those are SO cool.

 

* Any public domain graphic driver subroutines that handle drawing and raster timing efficiently? Best to write them from scratch for the specific game?

 

* How much should a used 2600 VCS console sell for? Is it better to get the 7800? Any caveats to look out for when shopping for one?

 

Thank you.

 

--- JDR

Link to comment
Share on other sites

>I am guessing the 128 bytes of RAM are mapped in Zero Page. What addressed RAM locations are available to the programmer?

$80-$FF

 

>Is there enough room to write useful rewriteable code?

Well, there's 128 bytes.. Subtract maybe eight bytes for stack and overall state. One of my demos makes use of a ~100 B kernel where constants are modified during VBLANK.

 

>When turned on will the 6507 sometimes randomly be in BCD mode? Should I always do a CLD to make sure it is in binary mode?

I think so

 

>Is the reset button a hard or soft reset? Does the hardware do a hard reset right after power up?

Soft.

 

>What are "mirrored" addresses in the 2600 memory map? How are they used?

Certain adress pins are ignored in some cases. Usually you don't have to worry about it - just use whichever adress is OK.

 

>Does DASM support undocumented, but often used, opcodes?

Yes.

 

>On a stock VCS and 4K cartridge what is the address of the first opcode to be run on power up? I am guessing $E000.

Reset vector is at $1FFC (aka $FFFC)

 

>The VCS was introduced when all TVs were Cathode Ray Tube based. Any modification to code/timing needed to be made for modern TVs with LCD, Plasma, LED, etc. displays?

Nope, assuming said TV takes a normal PAL or NTSC RF signal.

 

>What make and model of PROM do you recommend for cartridges?

The cheapest? The machine runs at ~1 MHz, so speed is no issue.

 

>How do you get the binary code from the PC to the 2600 for testing? PROM burner each time or perhaps some type of DIY serial device?

Harmony cartridge

 

>Does anyone manufacture the handled cartridge cases, ala Air Raid, Enduro, anymore? Those are SO cool.

No idea

 

>Any public domain graphic driver subroutines that handle drawing and raster timing efficiently? Best to write them from scratch for the specific game?

You mean kernels? It's usually best to write them from scratch IMO.

 

>How much should a used 2600 VCS console sell for? Is it better to get the 7800? Any caveats to look out for when shopping for one?

Maybe $50-$70 USD?

Link to comment
Share on other sites

Thanks for the answers.

 

The Harmony cartridge seems to be a very efficient way to test binaries quickly on the actual hardware. Thanks for that tip.

 

+++

 

"Avoid deviating from the standard number of scanlines, that is 262 for NTSC and 312 for PAL."

 

That's succinct. That helps in easing my mind regarding various TVs. I'll be programming for NTSC.

 

+++

 

"Reset vector is at $1FFC (aka $FFFC)".

 

Is that an example of a mirrored address? Or are you saying that the reset vector at $1FFC is pointing to $FFFC?

(Sorry. Mirrored addresses are a new concept for me. Must have something to do with the way the 6507 addresses are mapped with only 13 pins.)

 

+++

 

"You mean kernels? It's usually best to write them from scratch IMO."

 

Sorry. Yes. Kernals. Thank you for the correct terminology.

Link to comment
Share on other sites

"Reset vector is at $1FFC (aka $FFFC)".

 

Is that an example of a mirrored address? Or are you saying that the reset vector at $1FFC is pointing to $FFFC?

(Sorry. Mirrored addresses are a new concept for me. Must have something to do with the way the 6507 addresses are mapped with only 13 pins.)

 

Yes, it's a mirrored address. And yes, lack of higher address pins is the reason for mirror addresses.

 

13 address pins means the address space you can access is 2^13, or 8k. In the VCS design, the first 4k of that address space is used for hardware registers (actually significantly less, but the rest of that 4k is wasted) and the second 4k is used for rom access.

 

On a 6502, when values higher than 8k are accessed the higher address pins would be brought into play. Since the 6507 lacks these higher address lines, accessing $3FFC, $5FFC, ..., $FFFC, looks the exact same (from a hardware perspective) as accessing $1FFC.

Link to comment
Share on other sites

* Any public domain graphic driver subroutines that handle drawing and raster timing efficiently? Best to write them from scratch for the specific game?

 

I use a set of macros (from other homebrewers) that takes care of all of the timeing needed for the videosignal (vblank, overscan area, etc.). Between these macros I put my own code.

 

My code could look like this:

 


MainLoop
START_OVERSCAN
include game_logic.h
WAIT_OVERSCAN
START_VBLANK

include screen_setup.h
WAIT_VBLANK

START_SCREEN
;
; scanlines of screen are drawn here.
;
WAIT_SCREEN
JMP  MainLoop	  ;Continue forever.

Link to comment
Share on other sites

* Is there enough room to write useful rewriteable code?

There are some bankswitching schemes that add extra RAM, which is contained in the cartridge. If you're running your code in an emulator (Stella being the one that's most frequently updated), you can use pretty much any of these bankswitching schemes. At least one type of extra RAM-- Atari's Superchip (a.k.a. SARA chip)-- doesn't support self-modifying code, but others do. And if your game is published on a Harmony cartridge, self-modifying code will work even with the Superchip bankswitching schemes. So this lets you save the zero-page RIOT RAM for variables that need to be written and read more quickly with zero-page addressing, and use the extra RAM for self-modifying code or other things (playfield RAM, player/missile RAM, etc.). But you need to keep in mind that nearly all bankswitching schemes with extra RAM use one set of addresses for writing to the RAM, and another set of addresses for reading from the RAM, since the cartridge slot has no R/W pin-- hence one of the address pins must be used for this purpose. The only exception I know of is the 4A50 bankswitching scheme, which uses "magic writes" to write or read the extra RAM using just one set of addresses.

 

* Is the reset button a hard or soft reset? Does the hardware do a hard reset right after power up?

Yes, the hardware (or the 6507 CPU) does a hard reset right after power up. But the reset button on the console doesn't actually do anything by itself-- it's just a button, and one of the bits in one of the RIOT (6532) chip's I/O registers will indicate whether or not the reset button is pressed. Your program can respond to the reset button in any way you wish-- reboot the program from the power-up vector, jump back to some routine that comes after the initial power-up routine, make the screen change color, play a sound, pause or unpause the game, etc. And if your program never checks the status of the reset button, pressing reset won't do anything at all. Of course, Atari's game design standards suggest that the reset button be programmed to reset the game, since that's what the button is called-- but you could program it to do something different if you want.

 

* What are "mirrored" addresses in the 2600 memory map? How are they used?

As already explained, the lack of address pins for A13, A14, and A15 mean that those bits of a 16-bit address are ignored, since the 6507 can't detect them, so $1xxx will address the same memory as $3xxx, $5xxx, $7xxx, $9xxx, $Bxxx, $Dxxx, and $Fxxx. But it's even more complicated than that, because the TIA chip and RIOT (6532) chip have fewer than 13 address pins-- the TIA chip has only 6 address pins, and the RIOT chip has only 7 address pins. Both the TIA chip and RIOT chip have multiple chip select lines that are connected to specific address pins on the 6507, so they show up in separate areas of memory from each other. Furthermore, the number of address pins that are actually used by the TIA chip and RIOT chip varies depending on the function. TIA read operations use only 4 address pins, whereas TIA write operations use 6 address pins, so that means the TIA read addresses are mirrored within the TIA write addresses (e.g., $0000 and $0010 are different write addresses yet are the same read address). And it's even worse with the RIOT chip. Normally, to keep things as simple as possible, the lowest possible addresses are used-- i.e., where any "don't care" bits are set to 0. But it's fairly common to use $F000 through $FFFF to address the cartridge memory (as opposed to $1000 through $1FFF), since the 6502 (on which the 6507 is based) uses $FFFA through $FFFF for interrupt vectors and the power-up (reset) vector, hence it makes sense to use those same addresses with the 6507 as well. On the other hand, it's useful to use different addresses for different banks if you're using bankswitching, such as $1000 through $1FFF for one bank, $3000 through $3FFF for another bank, and so on, to help you more easily identify which bank a particular routine is in. Also, some programmers use $0040 through $004D for the TIA read addresses, so they'll be distinct from the TIA write addresses. And some bankswitching schemes use accesses to $0000 through $003F to trigger bank switching, which necessitates "relocating" the TIA read and write addresses to $0040 through $007F.

 

* The VCS was introduced when all TVs were Cathode Ray Tube based. Any modification to code/timing needed to be made for

modern TVs with LCD, Plasma, LED, etc. displays?

No, but some hi-def TVs automatically interlace the screen display, even though the 2600 was constructed to draw a non-interlaced 262-line display. If you have a TV that does that, you can create a flickered display and it will automatically be displayed as a flicker-free interlaced picture-- although it will flicker on other TVs, so it isn't advisable to capitalize on that unless you're programming a game for your own use.

Link to comment
Share on other sites

I have a few more comments about using address mirrors for the TIA and RIOT addresses.

 

As I said, it's simplest to just stick to the lowest possible addresses, or where the "don't care" bits in the address are all set to 0-- except in cases where relocating the TIA addresses is necessary due to the bankswitching scheme. There are two main reasons for this: (1) It helps you maintain your sanity, which is always a good thing. And (2) it ensures that your code will use addresses that are easily recognized by other programmers if they're disassembling your ROM, assuming they don't have your source code to refer to. For example, "STA $00" would be readily recognized as "STA VSYNC," whereas "STA $40" is less obvious-- you have to think, "Oh, right, that's equivalent to STA $00 or STA VSYNC." True, $00 and $40 are pretty easy to spot as mirrors-- but quick, what does $76 correspond to, or $5D, or $6A? Furthermore, if you don't have the source code and you're searching the ROM for all occurrences of "STA VSYNC" (or hex "85 00"), it's a lot easier if only the "standard" addresses are being used.

 

However-- aside from the 3F and 3E bankswitching schemes-- there might be other occasions when it would be useful to use the mirrors, namely when a given register has multiple uses. For example, you might want to define $01 as VBLANK (as normal), but define $41 as either LATCH or DUMPI, since $01 controls VBLANK, latching I4 and I5, or dumping I0 through I3 to ground. Then you could use "STA VBLANK," "STA LATCH," or "STA DUMPI" depending on which function of $01 you want to use, and the machine code would reflect which function you're accessing. True, you could just as easily redefine $01 to be both LATCH and DUMPI in addition to VBLANK, and your assembly code would reflect which function you're accessing, but the machine code wouldn't (although it would be obvious from looking at which values were being written to $01).

 

I'm not necessarily advising anyone to do this, because the names of the TIA registers-- while not "set in stone"-- are taken from the "Stella Programmer's Guide," and as such have become standardized. Therefore it would be more confusing to veteran 2600 programmers if you decided to use non-standard names and addresses for the TIA registers. Still, it would be a legitimate way to capitalize on the address mirroring of the TIA registers.

 

Edit: I had meant to add that assigning different labels and addresses for different functions of the same register might be useful if you're disassembling a ROM. For example, it's normal to reuse a given RAM address for multiple purposes, since there's only so many bytes of RAM and it's often essential to reuse a given byte for multiple purposes-- or to use specific bits in the byte for different purposes. Anyone who tries disassembling a game ROM can be driven to drink trying to figure out what address $95 is being used for if the game reuses it for many different purposes. Unfortunately, there are no page-zero mirrors for the RAM-- $95 has to be $95, unless you want to use one of the mirrors on other pages, which would mean having to use absolute addressing for those mirrors instead of zero-page addressing. So it might be helpful to use mirrors of the TIA addresses to assign additional labels to them for specific functions, so you know that $01 and $41 are being used for two different things. Of course, the flaw in this argument is that we know what the TIA registers are used for, so there's really no benefit to doing this-- unlike with the RAM addresses, where the only way to determine what they're being used for is to look at which registers they're being moved to, such as "LDA $95" followed by "STA GRP0" would tell you that $95 is being used to store the graphics for player 0, and "LDA $95" followed by "STA COLUPF" would tell you that $95 is also being used at other times to store the color of the playfield. And if the disassembler is programmed to convert specific zero-page addresses to the standard TIA register names, then any non-standard addresses would not be converted automatically, necessitating the additional manual step of defining additional labels for whichever mirrors are being used-- not really a big deal, but it could be very annoying to veteran 2600 programmers disassembling your machine code!

Edited by SeaGtGruff
Link to comment
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.
Note: Your post will require moderator approval before it will be visible.

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...
  • Recently Browsing   0 members

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