Jump to content
IGNORED

Tips on developing an Atari 2600 emulator?


Petruza

Recommended Posts

I know the most logical answer would be: "Don't. Stella already does it wonderfully".

But the thing is, I've started programming a NES emulator some years ago ( for a special valid reason* ) and it is now on an indefinite hiatus.

I've been reading about the VCS and think it's a simpler system than the NES, and programming an emulator for it would be a good

training for later making one for the NES and Commodore 64 which are my other goals.

 

I've already finished all the 6502 instructions, so I have part of the job done.

Although keeping the cpu in sync with the TIA and Bank switching are complex, the simplicity of the TIA vs. NES' video chip and the Atari's

CPU-programmer-driven interrupts vs. NES' interrupts, make it simpler to model.

 

TL;DR:

So, how the VCS works is fairly well covered by the programming tutorials out there, but I need some directions, if there are any, on

specific VCS emulator development, mainly cartridge ROM file formats description, and anything else I can't think of now.

 

 

*: Why make yet another emulator for an already emulated platform?

Well, I have two reasons, the first one is I wanted to keep my C++ skills in shape, after working for years on web development.

And the other is that I want to make emulators that don't just emulate the games exactly how they were, but that are capable

of modifying the the game's output at runtime, kind of what Pacifi3D did with Pacman.

I tried reading some emulator's source, but honestly I found them too cryptic because of low level C optimizations, and wanted

to live the experience of writing one from scratch anyway.

Edited by Petruza
Link to comment
Share on other sites

Rewrite the hotspots in Assembly instead of using C++ or Visual Basic; 98% of the hotspots are in less than 2% of the codebase so this isn't as daunting a task as it may appear :)

 

The Z26 emulator leverages this approach and thus can render the scrolling virtual worlds properly in all of my games like a real VCS instead of tearing apart like the default install of Stella on Windows.

Link to comment
Share on other sites

Well, Stella has the overall emulation covered.

 

There might still be some work left to do on improving or rewriting the TIA emulation in Stella. I'm sure Stephen would be ecstatic to get some help with that. I'm not a C/C+/C++/C# programmer, otherwise I'd help-- I've looked at the existing source and got lost pretty quickly, although that often happens when I look at other people's programs (or at my own from several years ago :P).

  • Like 1
Link to comment
Share on other sites

The key to any 6502 emu is getting it to do what the manuals don't tell you about, ie illegal instruction behaviour.

 

Much the same could be said for 2600 emulation. I think bank-select behaviour is the least of your problems. Given that TIA can produce different behaviour if certain registers are hit at different parts of the scanline and that existing long-lived emus like Stella still have plenty of inaccuracies is evidence of how hard it is to replicate the real thing.

Link to comment
Share on other sites

The key to any 6502 emu is getting it to do what the manuals don't tell you about, ie illegal instruction behaviour.

 

Much the same could be said for 2600 emulation. I think bank-select behaviour is the least of your problems. Given that TIA can produce different behaviour if certain registers are hit at different parts of the scanline and that existing long-lived emus like Stella still have plenty of inaccuracies is evidence of how hard it is to replicate the real thing.

 

By different behaviour you mean graphics-wise, right? or are there any other risks like desync'ing with the CPU, the HBlanks, etc?

Link to comment
Share on other sites

I mean mostly the graphics stuff, like different behaviour when certain registers are hit on the "wrong" cycles.

 

The HSync stuff... it's something that might never be emulated properly since the behaviour can be dependant on the TV in use. But there are "semi-legal" uses of hitting the sync registers like doing real interlaced video and the recently revealed fine-scrolling technique.

 

The way I see it, if you go to the trouble of making yet another emulator for a system, offer something not already there. Which means improve on what's out there in accuracy, interface or make the emulation available on a system where none already exists.

Link to comment
Share on other sites

I mean mostly the graphics stuff, like different behaviour when certain registers are hit on the "wrong" cycles.

For example the cycle when HMOVE is hit, as seen in this document at the bottom: http://www.qotile.net/minidig/docs/2600_advanced_prog_guide.txt

There are probably many more quircks, like repeating sprites by hitting certain registers.

 

It would be interesting if the TIA could be emulated at a lower level so the quirks are natural for the emulator (I assume Stella has this table too)

Link to comment
Share on other sites

You really should contact Stephen. If you are interested (and capable) a major overhaul of the TIA emulation should be the first thing on the list.

 

And yes, the Atari 2600 is definitely much more complex to emulate correctly than you might assume. Since all code is written extremely close to hardware, a lots of unexpected and undocumented tricks and tweaks have been found over the years. E.g. have a look at the starfield trick used in Cosmic Ark. Or the RESPx /NUSIZx tricks used in Meltdown.

Link to comment
Share on other sites

if you go to the trouble of making yet another emulator for a system, offer something not already there.

 

That's exactly why I want to make emulators, as I said:

 

I want to make emulators that don't just emulate the games exactly how they were, but that are capable of modifying the the game's output at runtime, kind of what Pacifi3D did with Pacman.

 

And I add: and not only modifying the output, maybe modifying the game internals also, or running two emulators simultaneously and linking them in some way so to let two persons play a game that was intended as single player only.

Edited by Petruza
Link to comment
Share on other sites

Problem is there are very few calls that could be considered high level constructs. No tile buffer like a Genesis or standard API like the N64. Since it's manually dragging the electron beam across the TV attempting to alter any of the graphic objects (ball, missiles, etc..) might not have the effect you anticipate.

Link to comment
Share on other sites

Ok, it's been well stablished that the Atari 2600 is not a simple system to emulate.

That aside, is there a specification of the bin and a26 ROM file formats?

 

Not trying to argue. Just bringing up the difference that might make enhancing the emulated games directly a pain. Any thoughts on the Android wrapper idea?

Link to comment
Share on other sites

Not trying to argue.

 

No please by all means do argue, I'm here to learn from more experienced people.

 

Any thoughts on the Android wrapper idea?

 

Well I've never done any Android development and am not interested in that for the moment.

Edited by Petruza
Link to comment
Share on other sites

Ok, I can see that DASM with option -f3 (not sure what the other output formats are, but it was like this on the tutorials) creates a .bin image that just has the raw code, no header.

It fills the gap between ORG $F000 and ORG $F100 but has no indication that the start of the code is at $F000

So I suppose the emulator assumes that the image should be loaded at $F000 ?

 

At least I tried the tutorials by Andrew Davie with DASM and Stella and it worked like this.

 

post-26193-0-42300500-1400601277_thumb.png

Edited by Petruza
Link to comment
Share on other sites

Ok, I can see that DASM with option -f3 (not sure what the other output formats are, but it was like this on the tutorials) creates a .bin image that just has the raw code, no header.

It fills the gap between ORG $F000 and ORG $F100 but has no indication that the start of the code is at $F000

So I suppose the emulator assumes that the image should be loaded at $F000 ?

 

At least I tried the tutorials by Andrew Davie with DASM and Stella and it worked like this.

 

The -f3 option creates a raw binary file without headers, as you've determined.

 

According to the DASM help document, the -f1 option adds a 2-byte header to indicate the lo/hi address of the origin, followed by the data.

 

The -f2 option will put one or more chunks of data in the output file, depending on the ORGs in the assembly code. Each chunk has two headers-- the first is the 2-byte lo/hi origin address and the second is a 2-byte lo/hi length-- followed by the data; then followed by the next chunk (address/length/data), then the next chunk, etc. The chunks don't need to be in order-- i.e., the ORG addresses don't need to be in ascending numerical order.

 

As far as I know, there are no Atari 2600 emulators that can load and run ROM files that were created with the -f1 or -f2 options, and I don't know that there would be any advantage to doing so, since the ROM data would need to be expanded out to be the proper size (4K or a multiple of 4K) and (if pertinent) rearranged so the banks are in the proper order.

 

The 2600's cartridge slot is fixed in the address space at $1000. However, since the 2600 uses a 6507 CPU, which has a reduced number of address pins (13 instead of 16), only 8K of memory can be addressed, and anything over 8K is seen as a "mirror" of the first 8K-- i.e., you can still use 16-bit addresses, but there are no address lines for the upper 3 bits of the address, so $2000-$3FFF is a mirror of $0000-$1FFF, $4000-$5FFF is a mirror, and so on. If you look at ROM file dumps of actual 2600 carts, you'll see that some programmers used $1000 for the cart's address, while others used $F000, or even other start addresses-- it can be $1000, $3000, $5000, $7000, $9000, $B000, $D000, or $F000. When bankswitching is used, it's common to give each 4K a different ORG address so it's easier for the programmer to tell from the address which bank is being addressed (although simply using a given address range doesn't cause bankswitching to occur). Since the 6502 has three jump vectors at $FFFA-$FFFB, $FFFC-$FFFD, and $FFFE-$FFFF, and since the last 6 bytes of a 2600's game ROM must contain those vectors (or at least the RESET vector), this implies that the 6507 sees the vectors as being at $FFFA-$FFFF, regardless of what the ORG address in the assembly file was, which is why some (or most) programmers like to use $F000 as the ORG address.

 

When a cart is bankswitched, the banks must be organized in the correct order in the ROM-- assuming the bankswitching uses 4K banks, each 4K block in the ROM will be assumed to be the first bank, second bank, etc. Each bank can use whatever address range the programmer feels like-- i.e., the addresses that appear in the code (for the JMPs and JSRs, or in the three 6502 vectors) will get "rendered down" to the $1000-$1FFF range anyway, since the three highest address bits don't have any corresponding address lines on the 6507. The 2600 powers up in a random state, so normally there's no way to be sure which bank will be in memory at power up, hence each 4K bank has its own set of vectors at the end which tell the 6507 where to start executing the ROM from-- if the bank doesn't contain the program's "real" start-up code, then that bank's start-up code must switch banks to where the "real" start-up code is. Note that some bankswitching methods use banks that are smaller than 4K (usually 1K or 2K), in which case the last bank is usually frozen (not bankable) such that it's always located at $1800-$1FFF (if 2K banks are used), or at $1C00-$1FFF (if 1K banks are used), etc.-- it depends on how many bank areas the method uses. In that case the program still needs to specifically switch to the desired bank in the bankable area(s), but only one set of vectors are needed (in the frozen bank) and only one start-up routine.

 

With a 2K cart, one of the cart's address pins is hardwired so that the 2K is seen as being at $F800-$FFFF (or $1800-$1FFF, $3800-$3FFF, etc.). In this case the uniquely-identifiable portion of the cart's address space is really $1000-$17FF and that address space is mirrored at $1800-$1FFF, $3000-$37FF, $3800-$3FFF, $5000-$57FF, $5800-$5FFF, etc.-- i.e., each 4K mirror is split into two 2K mirrors.

 

If you search for Kevin Horton, you can find some documentation he put together to describe almost all of the known bankswitching methods-- he had an older document, but within the last year or so he created a newer one to add information about most of the newer bankswitching methods.

 

Edit: Minor correction-- the 6502 LOOKS FOR three vectors at $FFFA-$FFFF (i.e., the vectors are of course in the program code, not in the 6502 itself).

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