Jump to content
IGNORED

Emulating the 2600


Recommended Posts

Hey,

Over the last few weeks I've been working on a 2600 emulator as a hobby project and I've had some issues understanding how certain things works.

In particular learning assembly and the 6502 is very challenging but I was wondering if anyone would be kind to help me in learning about the 2600 itself.

 

I'm currently trying to figure out how I would emulate the TIA, and my most recent issue relates to the way you use HMOVE/HMP0 registers to achieve smooth scrolling.

 

From what I understand, you use HMP0 as a relative offset to shift the pixels of the sprite to adjust for the 3-1 ratio of CPU - TIA clocks.

I found a TIA document online saying that you use the latter 4 bits of HMP0 to determine the offset from -7, + 8.

 

But what I don't understand is why you would need this kind of range when you only need to move the offset 3 pixels at a time.

 

I hope this was coherent, any advice is really appreciated.

Link to comment
Share on other sites

This is only true if you hit the exact cycle you needed when strobing the RESxx register to set the coarse position of the object. If you use a loop to delay until you reach the correct cycle, each loop iteration would take a minimum of 5 cycles, which requires the full 15 color clock range of the fine adjust range.

Link to comment
Share on other sites

I'm currently trying to figure out how I would emulate the TIA, and my most recent issue relates to the way you use HMOVE/HMP0 registers to achieve smooth scrolling.

 

One piece of advice that I can give is this: don't try to model your emulation after the "official" VCS programmer's guide, but instead try to understand how the chip's interconnected counters work to implement the described behaviour. In particular, Andrew Tower's TIA hardware notes (available i.e. here) are an excellent resource. Just understanding and sticking to them will get you about 95% along the way.

  • Like 2
Link to comment
Share on other sites

Oh, and trying to get the behaviour of reads from non-read location (i.e. TIA write-only registers) might save you a lot of headaches, too --- this is a very common programming error in VCS code, and not emulating it correctly will lead to all sorts of superficially mysterious issues with certain ROMs.

Link to comment
Share on other sites

  • 1 month later...

Hey, Sorry to ressurect and old thread

I've made a lot of progress on this project and I was hoping someone might be able to lend me some advice about managing the timings of the CPU / TIA a little as it's been difficult to get this right

My approach has just been to associate a CPU count with each opcode and then advance the TIA CLK 3x the length of the opcode.

The execution looks like

Check_Opcode()
PerformLogic()
AdvanceCLK(3 * LengthOfOpcode)
 ...

I was wondering... Is this naive? Do some ROMs rely on the 2 clocks in a STA before the storage actually completes in a graphics register?

 

It seems like every time I make a change to this timing some other binary starts misbehaving and I wonder if I'm fundamentally going about this incorrectly.

 

Thank you for reading <3

Link to comment
Share on other sites

I was wondering... Is this naive? Do some ROMs rely on the 2 clocks in a STA before the storage actually completes in a graphics register?

 

The 6502 is constructed to perform a read or write on every cycle; there is no cycle without a bus access (as long as RDY is asserted and the CPU is active). If you want 100% accuracy, you have to emulate the bus access pattern cycle-exact. A sensitive test case is Pole Position: the two borders of the road that meet at the horizon are positioned using two subsequent writes during the execution of a single opcode (a BRK according to this post on the Stella list). Failure to emulate this correctly will cause the road to be shifted or distorted.

 

That said, from my experience with 6502.ts, you can get 99% of the way by moving the side effects of the opcode to the last cycle of the instruction (for example, write memory in cycle 3 of a immediate STA). This is the difference between the "instruction exact" setting in Stellerator and the "cycle exact" setting I added last year. In fact. the only real-world example I know of that is broken with the "instruction exact" core *is* Pole Position :P

 

EDIT: What I forgot: there are various ROMs out there) that accidentally read from the floating bus (by targeting unmapped locations or interpreting bits that are not driven). Those have a tendency depend on the exact sequence of bus accesses of many opcodes, even if the precise timing is usually irrelevant.

Edited by DirtyHairy
Link to comment
Share on other sites

  • 2 weeks later...
  • 3 weeks later...

Hey,

 

I wanted to ask if anyone could help me with understanding WSYNC and other potential timing curveballs

 

I implemented timing as dirtyhairy described, most ROMs I've tested work almost perfectly but I'm running into a lot of cases of being off by one CPU cycle quite a lot.

 

I guess I wanted to ask if anyone knows of any curve balls I should be considering?

 

One thing I tested (and this could be false) is performing a WSYNC puts the beam at 6 CLK even when strobed with longer instructions (sta WSYNC,X) etc

 

I'll keep going over the code and testing with Stella but if anyone had any advice on what I should review :)

 

Also, for anyone who worked with a lot of 6502, does page crosses play into the timings a lot in time dependent sections of the code?

 

Again, I really appreciate the help. :)

Really enjoying my journey learning about this console !

Link to comment
Share on other sites

15 hours ago, DeadlyKitten36 said:

Also, for anyone who worked with a lot of 6502, does page crosses play into the timings a lot in time dependent sections of the code?

This part I can answer. There are a lot of instances where display kernel timing is very tight, and a difference of one cycle can throw things off (e.g. a 48-pixel routine). It is also not uncommon for loops in a display kernel to not use WSYNC at all in order to save those 3 cycles, in which case the cycle-counting in the routine needs to be precise.

Link to comment
Share on other sites

On 7/3/2019 at 1:15 AM, DeadlyKitten36 said:

I implemented timing as dirtyhairy described, most ROMs I've tested work almost perfectly but I'm running into a lot of cases of being off by one CPU cycle quite a lot.

 

I guess I wanted to ask if anyone knows of any curve balls I should be considering?

 

One thing I tested (and this could be false) is performing a WSYNC puts the beam at 6 CLK even when strobed with longer instructions (sta WSYNC,X) etc

I would assume that you still have one or two opcodes whose timing is off, and this causes the cycle shift you are observing. You can try to track them down by stepping the affected code in your debugger (provided you have already implemented one ;) ) and comparing the instruction timing to Stella instruction by instruction until you find the faulty opcode.

 

I am not sure whether I understand your question about WSYNC. Strobing WSYNC will pull the RDY line of the CPU low until the next HBLANK phase starts. Pulling RDY low will halt the CPU in the next read cycle. Unless you are close the the 76th cycle, the number of clocks that the strobing instruction requires to execute is irrelevant. The only possible twist concerns instructions with two consecutive write cycles (i.e. RMW instruction); as the CPU stops at the next read cycle, those will still cause the CPU to be suspend until the next HBLANK only (as opposed to skipping a fill line because of writing WSYNC twice).

 

  • Like 1
Link to comment
Share on other sites

Thank you both for the replies!

 

I have a basic debugger in and I've been stepping through ROMs side by side with stella.

I think part of my misunderstanding comes from the beginning of ROMs where intialization happens (CLEAN_START etc).. I think some problems could derive from the mirrored addresses (WSYNC being both 02 and 43 for example).

 

To try and find exactly where I fall out of sync with Stella I added a "frame count" & "cycle count" but I'm having problems with even that.

For example, here is the ROM for donkey kong, and I noticed Stella moves to "frame 2", on "scanline 50" the final BPL. Maybe someone here can help me understand this? ?

stella.png

Edited by DeadlyKitten36
Link to comment
Share on other sites

16 hours ago, DeadlyKitten36 said:

To try and find exactly where I fall out of sync with Stella I added a "frame count" & "cycle count" but I'm having problems with even that.

For example, here is the ROM for donkey kong, and I noticed Stella moves to "frame 2", on "scanline 50" the final BPL. Maybe someone here can help me understand this? ?

 

I think that you can safely ignore the frame count for now. There is no strict definition of the boundaries of frames for the 2600, especially during the initialization phase of a ROM where no valid TV signal is generated. Stella has a pretty elaborate algorithm for determining the boundaries between frames that is built to address many special cases, and I am not surprised that your counting differs. The cycle count that a section of code requires to execute is an exact number, though, and if you step instruction by instruction, you should be able to track down where your emulation gets it wrong.

Edited by DirtyHairy
Link to comment
Share on other sites

Hey, Just wanted to drop a message and say thank you again, this information was super helpful- Just trying to find some time to work on this stuff :)

 

So far I found I wasn't handling 73 cycle WSYNCs correctly, there were some page crosses I forgot to include also.

 

I will write back and let you guys know if I make progress :)

Link to comment
Share on other sites

  • 1 month later...

Hey, just wanted to make a final post here thanking everyone for the help again and giving a quick update

 

I'm probably going to come back to this at a later point when I've learned a little more about emulation and programming in general as I've been feel more and more out of my depth working on this.

 

If anyone is interested, I put up what I had so far on GitHub.

https://github.com/nd3644/e6502-vcs

 

It got as far running most of the examples from 8bitworkshop and partially runs a few official games but there are timing issues and some things missing in the TIA.

 

Again thank you for the advice, I hope to come back to this at a later point :)

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