RIOT limitations and workarounds
The 7800 Software Guide has the following to say about the RIOT chip...
This chip is used only for I/O in 7800 mode, whereas in 2600 mode it also supplies access to all RAM and timers.
...without a lot of technical explanation as to why this is. In fact, if you test this RIOT functionality, at first it would seem to be working just fine. However the longer you test with real world examples, you would would discover that the RIOT timers and RAM are indeed sometimes unreliable.
The Memory Map appendix of the Software Guide goes into a little more detail, blaming the RIOT RAM reliability issue on speed differences. While this may be true for access at Maria speeds, at 6502 speeds this explanation isn't the whole story.
Why RIOT timers and RAM are unreliable in 7800 mode
There's are two main reasons why accessing RIOT timers and RAM is unreliable - DMA, and Maria's own logic failings.
When Maria halts the 6502 for DMA, it doesn't have a corresponding halt line for the RIOT chip, so RIOT continues to run while the 6502 is halted. If the halt begins in the middle of RIOT access, the address and write enable asserted by the 6502 will disappear on RIOT mid-operation.
This may manifest differently on different consoles, with some consoles being seemly immune to the issue, likely due to rate of transition (hang-time) of the relevant lines when the 6502 is halted.
The heavier the DMA is while you attempt to access RIOT timers or RAM, the more likely it is that you'll run into issues. Conversely, the reliability issues go away if Maria has DMA turned off. In fact, the 7800 BIOS actually turns off DMA and uses RIOT RAM to boot into 2600 mode.
When the 6502 accesses TIA or RIOT addresses, Maria is responsible for slowing down the clock it feeds to these chips, as well as managing the chip enable and write enable lines. It seems to do a great job keeping track of the timing required for regular 6502 access modes - Absolute, Absolute Indexed, Indirect Indexed - but Maria's internal counters that manage the timings of the various lines go completely haywire when you try to execute code out of RIOT RAM.
Making RIOT timer and RAM operations more reliable
The easiest way to make the RIOT timer writes reliable in 7800 mode (without having to turn off DMA) is to double-check the value you've just tried to write, and repeat it if required...
Repeat64T lda #10 sta TIM64T lda INTIM cmp #9 ; immediately reading the value returns what you stored, less 1. bne Repeat64T
If you're checking INTIM during the visible screen, it should also be noted that DMA may make it difficult to catch the exact moment when 0 is reached, because the timer will switch to single-cycle resolution at the time. In this case you can either work with an offset value (e.g. add 10 to the timer value you want when setting the timer, and then act accordingly when INTIM is at 10 or less.) or you can use the RIOT interrupts, and just check TIMINT instead of INTIM.
In theory you could take the same approach with RIOT RAM reads and writes, but in practise checking the consistency of reads and writes isn't tenable. If you wish to use RIOT RAM, it should probably be kept to periods of VBLANK, or when DMA is disabled.
RIOT Limitations and Workarounds was written by Mike Saarna (aka RevEng) as original content for 7800.8bitdev.org.