Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve TIA WSYNC emulation #42

Closed
sa666666 opened this issue Dec 19, 2016 · 13 comments
Closed

Improve TIA WSYNC emulation #42

sa666666 opened this issue Dec 19, 2016 · 13 comments
Assignees

Comments

@sa666666
Copy link
Member

The attached test ROM illustrates how it can tell if it was run on an emulator or a real console. Obviously, the emulator should identify as a real console too.
emubug.zip

@sa666666 sa666666 added the bug label Dec 19, 2016
@thrust26
Copy link
Member

Old core says 2600. :)

@sa666666
Copy link
Member Author

sa666666 commented Dec 19, 2016

This is fixed in a6bc247.

I actually knew how to fix this bug when I created the issue, but I wanted it documented here anyway. It was actually fixed in the old core in 2006 (!), documented below:

Update of /cvsroot/stella/stella/src/emucore
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv25358

Modified Files:
TIA.cxx
Log Message:
Added a flag to the 6502 code to track if the last memory access was a
read or not. Also modified the TIA code so that if the last access
wasn't a read then it does not do a WSYNC operation. This allows the
emubug.bin ROM to execute and report "2600" instead of "EMU".

Index: TIA.cxx

RCS file: /cvsroot/stella/stella/src/emucore/TIA.cxx,v
retrieving revision 1.68
retrieving revision 1.69
diff -C2 -d -r1.68 -r1.69
*** TIA.cxx 12 Aug 2006 02:42:09 -0000 1.68
--- TIA.cxx 31 Aug 2006 02:31:28 -0000 1.69


*** 2212,2217 ****
case 0x02: // Wait for leading edge of HBLANK
{
! // Tell the cpu to waste the necessary amount of time
! waitHorizontalSync();
break;
}
--- 2212,2227 ----
case 0x02: // Wait for leading edge of HBLANK
{
! // It appears that the 6507 only halts during a read cycle so
! // we test here for follow-on writes which should be ignored as
! // far as halting the processor is concerned.
! //
! // TODO - 08-30-2006: This halting isn't correct since it's
! // still halting on the original write. The 6507 emulation
! // should be expanded to include a READY line.
! if(mySystem->m6502().lastAccessWasRead())
! {
! // Tell the cpu to waste the necessary amount of time
! waitHorizontalSync();
! }
break;
}

@DirtyHairy
Copy link
Member

DirtyHairy commented Dec 19, 2016

2006 --- an anagram of 2600 😏 I am well aware of the issue; however, I fail to see how this fix gets closer to accurately emulating it. Afaik, what happens on WSYNC is that the TIA pulls low RDY which will cause the CPU to halt on the next read cycle. However, this change (as well as the implementation in the old core) checks whether the previous cycle was a read cycle. In addition, it will skip WSYNC alltogether, while the real thing should continue executing just until it hits a read cycle.

@sa666666
Copy link
Member Author

sa666666 commented Dec 19, 2016

By all means, please feel free to change it to more accurately emulate what's going on. The implementation in the old core 'fixes' the ROM in question, but it's probably only a superficial change.

I assume you did this differently in 6502.ts; how did you fix the issue there?

@DirtyHairy
Copy link
Member

DirtyHairy commented Dec 19, 2016

I didn't fix it at all 😃 In 6502.ts, CPU emulation is currently not sophisticated enough to do anything like this. In particular, all reads required for decoding the instruction happen in the first cycle, and all reads and writes required by the instruction itself happen in the last cycle (this is the reason while Pole Position is glitched in 6502.ts). As the CPU in 6502.ts is dispatched cycle by cycle, properly emulating memory access patterns would require turning every instruction into a state machine. Doing this would make the implementation of this particular edge case trivial, but the required changes are pretty invasive.

I am not sure about Stella; the fact that dispatch is driven by the CPU makes emulating memory access patterns much easier. I think one way to correctly implement RDY behavior would be to signal the TIA on each read access. WSYNC could then raise an internal flag, and the necessery advance of the system clock could happen on the next read signal. I might take a stab at implementing this at some point.

However, I guess I would first have to design a valid testcase that fails on the current implementation and validate this on real hardware. The most obvious idea is hitting WSYNC with a RMW instruction. A naive implementation like 6502.ts will then skip two lines. Your fix is already better as it will only wait on the first write. Still, there should be a difference of two in the color clock at which the next instruction is executed, and this should be visible when doing a RESx.

@sa666666
Copy link
Member Author

sa666666 commented Jan 15, 2017

Since this isn't really fixed but only worked around, we should reopen the bug. I also included the original report from sourceforge above, since the Stella sourceforge page will be disappearing eventually.

@sa666666 sa666666 reopened this Jan 15, 2017
@sa666666 sa666666 changed the title emubug.bin identifies as an emulator instead of an actual console Improve TIA WSYNC emulation Mar 4, 2017
@KarolS
Copy link

KarolS commented May 11, 2017

Isn't it the same mechanism VIC-II uses to stop 6510 in Commodore 64? Maybe a look into how C64 emulators do it would help.

@sa666666
Copy link
Member Author

Yes, that's a good idea. The main problem now is lack of time; I hope to revisit this soon.

@DirtyHairy
Copy link
Member

@sa666666 if you like I can take over this, I think I have a pretty solid idea of how to test and implement proper RDY handling 😏

@sa666666
Copy link
Member Author

Yes, of course if you have time and are willing, I won't complain 😄 I'm working on the PAL colour-loss now, and how to have it ready in the next day or so. Also I plan to do a new release by the end of the month. So feel free to work on any issue you like before then.

@DirtyHairy
Copy link
Member

DirtyHairy commented May 12, 2017

New release sounds good, I guess we are closing in on 5.0 final 😄 I am currently still trying to get meaningful profiling data out of Stella. After that, I'll be looking at RDY.

@KarolS I don't know the details of the C64, but I guess that's true. Afaik every 6502 based system that implements DMA uses this mechanims to make the 6502 temporarily relinquish the bus.

@DirtyHairy
Copy link
Member

This testcase probes for proper emulation of the CPU RDY line. You can switch the testcase between PAL and NTSC with the color switc. On Stella, the result looks like this:

rdy

Observe the "nose" in the middle of the white bar --- this is due to the aforementioned difference in the color clock when stopping the TIA on the first write fof a RMW instruction (INC in this case) instead of stopping at the next read cycle. On real hardware, there is no "nose", just a smooth white rectangle.

Other emulators that don't try to account for proper RDY behavior at all show a series of black stripes instead of the "nose" (javatari, MESS). 6502.ts is special: it displays properly, but this is not because of proper RDY emulation, but rather because it doesn't emulate the first spurious write in a RMW instruction at all (that's 6502ts/6502.ts#51) 😏

Next step: fix it.

@DirtyHairy
Copy link
Member

Correct screenshot:

rdy_1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants