Jump to content
IGNORED

To Roll or not to Roll?


Recommended Posts

45 minutes ago, Thomas Jentzsch said:

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

Good point. Maybe the chance for the write to happen at the exact cycle are low. Or, simply, the problem is elsewhere.

 


I just tried to write a value to TIM64T and enabling the RIOT interrupt, and then keep the cpu in an infinite loop without ever reading back the timer.

I connected the logic analyzer to the RIOT IRQ pin and it just stays low. So the interrupt flag doesn't get cleared on subsequent wraparounds and I guess the divide ratio stays at 1 clock.

And that's how Stella behaves too.

 

I'm out of ideas...

 

Link to comment
Share on other sites

My NTSC console+CRT doesn't roll for either "roll" or "non roll" versions of the program, but the "roll" version does look quite different - the bar normally displayed at the top of the screen is mostly hidden off the top of my screen. So this issue does indeed affect NTSC consoles, in my case a 7800. The screen just doesn't roll as readily here.

 

If I load INTIM immediately after the TIM64T write in the overscan routine, and later display it's value in PF1, the value displayed is 27. This output is identical in Stella and real hardware, and is one down from the value we wrote in TIM64T (28) which is reasonable.

 

If I load INTIM immediately after the TIM64T write in the vertical blank routine, and later display it's value in PF1, the value displayed is 32. This disagrees with Stella (36) and is implausibly far from the value written in TIM64T. (36)  

 

  • Like 2
Link to comment
Share on other sites

Hah, pretty sure I have it. I added a NOP between the vblank TIM64T write and my load of INTIM, and the returned value changed to 30. (2 less than the result without the NOP delay.) Then I put 2 NOPs between the TIM64T write and INTIM read, and the returned value became 28.

 

It seems that if you happen to update TIM64T (and presumably the other resolutions) on that very last cycle remaining, RIOT stores your new value correctly, but it still changes the timer over to single-cycle resolution as part of the usual time-out housekeeping, instead of using the timing resolution you selected. That's quite the bug.

 

  • Like 4
Link to comment
Share on other sites

3 hours ago, RevEng said:

It seems that if you happen to update TIM64T (and presumably the other resolutions) on that very last cycle remaining, RIOT stores your new value correctly, but it still changes the timer over to single-cycle resolution as part of the usual time-out housekeeping, instead of using the timing resolution you selected. That's quite the bug.

 

This behaviour is described in the 6532 datasheet, altough not very clearly, and only referred to read accesses:

Quote

After the interrupt, whenever the timer is written or read the interrupt is reset. However, the reading of the timer at the same time the interrupt occurs will not reset the interrupt flag.

And from previous research, we know that the interrupt flag is what determines if the timer counts at 1 clock rate or uses the previously stored divider (so if you read the timer after the flag has been set, that is after it has counted past to 0, it normally resumes counting with the previously set divider. The exception would be if the read happens at the wraparound cycle.


To sum up, I think this is what's going on:

 

- If the interrupt flag (bit 7 of TIMINT) is set, the programmed divider is ignored and the timer counts at 1 clock rate.

 

- Whenever the timer wrapsaround from 0 to $FF, the interrupt flag is set. (if it was already set, it stays that way)

 

- Writing or reading the timer clears the interrupt flag, unless the read/write happens at the exact wraparound cycle, in which case the flag is set afterwards.

 

So

If you read INTIM at wraparound, the result is $FF, the flag is set and the timer counts down at 1T rate

If you write to TIM64T at wraparound, the timer is updated with the correct value, but the flag is set and it counts at 1T

 

 

So a read access at the exact wraparound cycle stills needs to be confirmed. (This might already be implemented in stella, as it's part of the datasheet). It's also worth checking the behaviour on subsequent wraparounds (when the interrupt flag is already set)

 

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

1 hour ago, Thomas Jentzsch said:

That explains it, yes. But it doesn't explain why that bug has never been noticed before. The coincidence is not that big.

Assuming even distribution (which I don't think is quite correct) it would be a 1 in 256 chance that your code timing aligns with the one crucial cycle, from the time one INTIM test loop has finished (and begun counting down in single cycles) to the next time you try setting a RIOT timer. Since the bug is easily perturbed, I think if someone has run across it before, they've probably "fixed" it and moved on.

 

[edit - and that 1 in 256 chance is assuming the bug is still possible, even when the interrupt has already been triggered once.]

 

  • Like 1
Link to comment
Share on other sites

4 minutes ago, alex_79 said:

Sure, but I think it would be better to confirm that this is the actual behaviour first.

Sure, but this can be part of the issue.

 

4 minutes ago, alex_79 said:

After this has been fixed, a developer option to break on timer accesses at the wraparound cycle would save future headaches.

Good idea.

Link to comment
Share on other sites

I believe I have run into this issue before! In this thread I converted Alien 8K to PAL60, and went through several versions until I fixed the rolling.

 

Rolling roms are in posts 12, 17, 19. The fixed rom is in this post:

 

 

 

Please note, the title screen is fine. The roll only occurs in the game screen every 1 or 2 seconds.

  • Like 2
Link to comment
Share on other sites

I’m amazed. A hardware bug in a chip discovered some 45 years after its release. And such an onerous bug too, I am surprised it’s never been identified before. Just when we are sure we know everything there is to know about the 2600, new stuff still gets found. 

  • Like 3
Link to comment
Share on other sites

3 hours ago, batari said:

I’m amazed. A hardware bug in a chip discovered some 45 years after its release. And such an onerous bug too, I am surprised it’s never been identified before. Just when we are sure we know everything there is to know about the 2600, new stuff still gets found. 

Atari should do a recall of all '2600 units ASAP.

  • Like 1
  • Haha 4
Link to comment
Share on other sites

I've been playing with these ideas this evening and they seem to fix the timing issues I was seeing in https://github.com/stella-emu/stella/issues/108 . I now get the correct values as reported to be seen on the real hardware.

 

Just as a point of note, when setting a new timer, the bit pattern that is used to clear TIMINT seems to differ depending on whether TIMINT is already off or not. As far as I can tell, if TIMINT is currently on, it is cleared with but pattern 0x00. If it has already been cleared it is given the bit pattern 0x40

 

You can see this difference in test2.bas.bin and testTIMINT_withDelay.bin

 

In test2.bas.bin if TIMINT is cleared with 0x00 then the incorrect value is written to RAM register 0xd7. When 0xd7 is later tested for the overflow bit it will never reach the correct branch. This results in the incorrect number on the display (000249 instead of 064249)

 

It would be nice to see the schematics for the RIOT chip to see what's going on and whether it matches the observations.

 

on edit: this is of course, wrong. the difference is to do with PA7 interrupt.

 

more edit: if we say the pa7 flag is set at startup (ie. before TIMINT is ever read) and only reset when TIMINT is read for the first time, then that satisfies all the timer test cases.

 

Edited by JetSetIlly
  • Like 1
Link to comment
Share on other sites

On 4/4/2020 at 1:21 AM, JetSetIlly said:

more edit: if we say the pa7 flag is set at startup (ie. before TIMINT is ever read) and only reset when TIMINT is read for the first time, then that satisfies all the timer test cases.

The PA7 flag value reported in that Stella issue is likely the result of loading the roms from the Harmony menu. Since you use the left joystick to navigate the files and directories in the SD card, the flag gets easily set before starting the rom. I tried again those roms ensuring not to move the joystick to the right, and the result I got is that flag is cleared.


So it might be always cleared on startup, or maybe its status is undefined and varies depending on the specific console.

 

 

I tried compiling an up to date version of Gopher2600 and the results with the test rom posted in this thread matches my observations (238 scanliines).:thumbsup: Too bad that my PC seems to be too old to run the emulator at full speed.

 

gopher2k6_debug.thumb.png.c928fa646bd778c5f4dc6fa9a715765f.png

 

  • Like 1
Link to comment
Share on other sites

Quote

The PA7 flag value reported in that Stella issue is likely the result of loading the roms from the Harmony menu. Since you use the left joystick to navigate the files and directories in the SD card, the flag gets easily set before starting the rom. I tried again those roms ensuring not to move the joystick to the right, and the result I got is that flag is cleared.

Ahh. Okay. That makes sense. My next step then, is to add the code that will set the PA7 when the correct conditions are met.

 

 24 minutes ago, alex_79 said:

I tried compiling an up to date version of Gopher2600 and the results with the test rom posted in this thread matches my observations (238 scanliines).:thumbsup: Too bad that my PC seems to be too old to run the emulator at full speed.

Yeah. It is slow. That's partly a consequence of the choice of language (garbage collecting etc.) Sorry about that ? The project began as a learning exercise (for both the language and the 2600) and I never expected it to get to the stage it is.

 

Thanks for trying it out though, that pleases me greatly.

 

  • Like 1
Link to comment
Share on other sites

On 4/2/2020 at 8:05 AM, Thomas Jentzsch said:

That explains it, yes. But it doesn't explain why that bug has never been noticed before. The coincidence is not that big.

Turns out it has, but apparently passed under the radar...

This is from the "Kim-1/6502 User's notes" newsletter, issue 12 (July 1978).

(Note tha the KIM-1 uses a 6530 RRIOT (Rom, Ram, I/O, Timer) and the timer part works the same as the 6532.)

6530_Timer_Bug-6502_users_notes_11.thumb.png.8de01a2f60877870ef36c650944bf020.png

 

Note tha the proposed workaround is to write the timer twice, as suggested by @RevEng

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

12 hours ago, alex_79 said:

Turns out it has, but apparently passed under the radar...

This is from the "Kim-1/6502 User's notes" newsletter, issue 12 (July 1978).

(Note tha the KIM-1 uses a 6530 RRIOT (Rom, Ram, I/O, Timer) and the timer part works the same as the 6532.)

 

 

Also this post from AtariAge in 2008.

 

 

on edit: my mistake. on second reading, that post is talking about reading rather than writing.

Edited by JetSetIlly
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...