Jump to content
IGNORED

To Roll or not to Roll?


Recommended Posts

The attached ROM (a dead simple variation of How to Draw a Playfield) behaves perfectly in Stella, but it mysteriously rolls like mad on my CRT (how about your's?). ? And if I add one simple NOP (set STOP_ROLL to 1 in the source code), the rolling stops. :? 

 

The code has no branches, only loops which are executed exactly the same each frame. Therefore the timing seems 100% constant. There are also no WSYNCs which are on the edge. 

 

So there must be some difference between Stella and real hardware which is new to (at least) me. Or a stupid mistake. :) 

 

Can you help me here and find the reason?

Test_Roll_01.bin Test_Roll_01.asm

Link to comment
Share on other sites

I just tried the test program out on my NTSC standard CRT TV (circa 1997) and it doesn't roll there.  But of course that doesn't mean much as TVs are generally designed to be as tolerant as possible.

 

The only thing I can think of is the Overscan timer is expiring too close to the end of a line.  Sometimes it hits before and sometimes it hits after causing an occasional extra scanline. 

 

So you may have found an edge case in which Stella (maybe the RIOT emulation) might be slightly off from real hardware.

Link to comment
Share on other sites

Hi Thomas,

 

On 3/8/2020 at 11:55 AM, Thomas Jentzsch said:

But since it so far only rolls on my TV, I start to wonder if that's the problem.

This is strange. BTW, is this the same VCS and TV you used to test SWOOPS!? I remember you reporting a similar issue on [stella] that I believe we never diagnosed completely. (Without looking it up) I believe we thought it had to do with activity during VSYNC or not disabling the TIA. I see you are disabling the TIA in this code though. This is very strange.

Link to comment
Share on other sites

SWOOPS! did not enable VBlank. This worked as long as the background was black, but when it was flickering the screen started rolling on some TVs. I double checked this for the test ROM and VBlank is definitely enabled. 

 

BTW: Does it roll for you?

Link to comment
Share on other sites

Hi Thomas,

 

I noticed a similar coding in Astroblast.

 

In the TimerWait routine there is a NOP instruction after the read to T1024T expires. This is located as locations $F453 - $F460. Since your display rolls in your example without your NOP; try modifying the Astroblast code by removing the NOP at $F458 and see if the screen rolls for you.

Link to comment
Share on other sites

That was my vague idea too. Thanks for confirming. But it could as well be the PAL console instead.

 

Anyway, I would like to understand what exactly triggers the problem. The code is dead simple, so there must be something quite fundamental wrong. Either in my code (likely) or in our understanding of the 2600.

Link to comment
Share on other sites

Just to be clear, are you guys using the PAL version or the or the PAL60 version?

 

There are a whole pile of systematic tests we could do to box the problem into a smaller area. Honestly, it really seems like the timer is not behaving as expected but we should rule out things that should have no effect first. This is easier done by someone who could build the problem source and test on a TV that is known to be rolling.

 

Using the version of the rom that rolls, consider these initial tests:

 

Note each item is to be tested is independent of each other, with no cascading changes:

- Put some some NOP's at the beginning of the rom before START, to effective shift all of the addresses.

- Change the RORG addresses.

- Use alternative addresses for TIM64T and INTIM. There is actually a lot of different registers that could be tested like the edge detection, but ideally do one at a time. That thread overall is very informative as well as this document for the timer.

- Start replacing sections of the code with WSYNC's instead of using the timer, to isolate VBLANK and OVERSCAN reading of INTIM.

- Build a new test rom that is stable (with the fix, or a bunch of WSYNC's). Make a new timer routine in the middle of the kernel that changes the background color, and when it is done reset the background color. Use some PF blocks to see if where the timer runs out is the same on your TV as Stella.

 

 

 

It would be nice to push this into a smaller place so that we can figure it out.

 

 

 

Link to comment
Share on other sites

I am only using and providing the 60Hz version.

 

I already tested many of these, plus many more like changing the initial timer values. Currently it seems that a large T1024T might be part of the problem. But that might be completely wrong. 

 

Over the weekend I will do more testing.

 

 

Edited by Thomas Jentzsch
Link to comment
Share on other sites

42 minutes ago, Thomas Jentzsch said:

Currently it seems that a large T1024T might be part of the problem.

There's another test ROM floating around (in one of the Stella issues) that displays incorrect values for T1024T too.  We never did figure out why.  Perhaps this is related??

Link to comment
Share on other sites

  • 3 weeks later...

I confirm that it rolls on my PAL CRT too.
 
I hooked up a cheap logic analizer to my vader console to see what's happening.

I slightly modified the test rom: I set COLUBK to $02 for the entire display, and used the playfield for the white bar at the top. In this way I can see when the video is blanked (during HBLANK and VBLANK periods) by monitoring the "LUM0" pin of the TIA. (PAL TIA lacks the "BLANK" pin that you can find on the NTSC version).

 

So it turns out that the "ROLL" rom (without the extra "nop") outputs 238 scanlines instead of 262. In particular, the VBLANK area after the three VSYNC lines is only 6 scanlines instead of 30. All the other values are the same:

no roll:


vsync		3
vblank		30 
display 	205
overscan	24
--------------------
total		262


roll:

vsync		3
vblank		6	<=========
display		205
overscan	24
---------------------
total		238

 

Here are a couple of pitures showing the signals: the large area where LUM0 pin is low is when VBLANK is set in the TIA (that corresponds to the Overscan + Vertical Sync + Vertical Blank)
In the corresponding area of the CSYNC pin you can clearly see the three scanlines where VSYNC is set. Note how the Vertical blank area between the end of VSYNC and the start of the display (LUM0) is much shorter in the "ROLL" rom.

 

"NO ROLL":

noroll.thumb.png.d516279c4c0c5513a7f0e3c616e2e014.png

 

 

"ROLL"

roll.thumb.png.15f897a4e151196b47b18b36e920f578.png

 

 

Test_Roll_02.zip

 

Edited by alex_79
  • Like 5
Link to comment
Share on other sites

Some other things to try...

 

Is there any change if you use bpl for the INTIM test, rather than bne? test hypothesis: INTIM is briefly returning zero incorrectly.

 

Is there any change If you write the overscan value to TIM64T twice? test hypothesis: TIM64T is failing to be correctly updated.

 

On that second test, some elaboration is probably needed; in my own experiments, double-writes seem to resolve RIOT timer update issues on the 7800 when it's running at 7800 mode speed. (RIOT timers are known to be unreliable in this mode.) Since this fix may be specific to 7800 mode, continued bad timing with double-writes doesn't disprove this hypothesis, but if the bad timing goes away, it would strengthen the hypothesis. If bad timing does go away, I think you'd want to retest with either write replaced to another destination, to confirm it didn't go away due to simple timing change. 

  • Like 1
Link to comment
Share on other sites

5 hours ago, RevEng said:

Is there any change if you use bpl for the INTIM test, rather than bne? test hypothesis: INTIM is briefly returning zero incorrectly.

No change, it still rolls

5 hours ago, RevEng said:

Is there any change If you write the overscan value to TIM64T twice? test hypothesis: TIM64T is failing to be correctly updated.

Tried with double writes and then replacing one of the two with a write to SWCHA:

 

TIM64T twice:    stable

TIM64T SWCHA:     rolls

SWCHA TIM64T:    stable

 

Test_Roll_write_TIM64T_twice.binTest_Roll_write_TIM64T_SWCHA.binTest_Roll_write_SWCHA_TIM64T.binTest_Roll_bpl.bin

 

 

So it seems that the fail to update TIM64T depends on the specific timing of the write.


I also tried again the previous rom (bne for INTIM test, single write to TIM64T), by using the "enable interrupt" addresses for writes to TIM64T ($029e) e read from INTIM ($028c) and connected the logic analyzer also to the RIOT IRQ pin (which isn't connected to anything in the VCS) and to the RDY pin of the TIA (which help identifying when WSYNC is strobed).


I tested both the "ROLL" and "NO ROLL" (with extra "nop") versions:

 

In both roms, the interrupt is set slightly before the start of VSYNC (which indicates that the Timer wraps around from 0 to $FF and starts counting down at 1 clock decrement).
In the pictures below, I circled in yellow the write access to TIM64T.
Note that while in the "NO ROLL" rom, the interrupt is immediately reset after that write, it stays set in the "ROLL" one.

Test_Roll_Timer_int_ROLL.binTest_Roll_Timer_int_NO_ROLL.binTest_Roll_Timer_int.asm

 

NO ROLL:

test04_NO_ROLL.thumb.png.8b120d22b3e001e71ec8019e54f34215.png

detail:

test04_NO_ROLL_detail.thumb.png.d6369a54e7eabdbb7bde81b55adc36a5.png

 

 

ROLL:

test04_ROLL.thumb.png.212790ab471144989769392018bee310.png

detail:

test04_ROLL_detail.thumb.png.e04404354db86a5cf2401c4f05f4e00b.png

 

I attach here the samples from the logic analyzer. They can be opened with the "Pulseview" software, and exported in various formats.

Test_Timer_int_roll.srTest_Timer_int_noroll.sr

 

The signals I used are the following (TIA is the PAL version)

TIA pin 11    TIA CLK
TIA pin 4    CPU CLK
TIA pin 2    CSYNC
TIA pin 7    LUM0
TIA pin 5    LUM1
RIOT pin 25    RIOT IRQ
RIOT pin 35    R/W
TIA pin 3    RDY

 

  • Like 3
Link to comment
Share on other sites

According to the Stella debugger, right before the write to TIM64T at $f02e, the INTIM value is "03", and the interrupt flag in TIMINT is set, so it's counting at 1 clock increment. The write takes 4 cycles.

debugger.thumb.png.2d32e6329eb989b300c99ccf548a925d.png

 

I think that this write that happens while the timer wraps around with the interrupt set is the cause of the strange behaviour.

 

What happens normally when the interrupt is set, and the timer counts down at a 1 clock increment if there are no read or writes to the timer and it wraps around again to $FF? Is the interrupt cleared and the timer resumes counting at the divider that was set before, or it stays set and the timer keeps counting at 1 clock rate?

 

 

 

  • Like 2
Link to comment
Share on other sites

42 minutes ago, alex_79 said:

I think that this write that happens while the timer wraps around with the interrupt set is the cause of the strange behaviour.

Hm, that seems to make sense. But then, why did this not happen more frequently before? The pattern (wait for timer, vertical sync, start new timer) is pretty common.

 

42 minutes ago, alex_79 said:

What happens normally when the interrupt is set, and the timer counts down at a 1 clock increment if there are no read or writes to the timer and it wraps around again to $FF? Is the interrupt cleared and the timer resumes counting at the divider that was set before, or it stays set and the timer keeps counting at 1 clock rate?

No clue. I could only lookup what Stella is doing. And that might be wrong.

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