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 RAM and timers 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, otherwise this story seems to be fiction.
Why RIOT RAM and timers are unreliable in 7800 mode
In a word, the reason why writing to the RIOT RAM and timers are unreliable, is DMA. 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 a RIOT update, 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 write to RIOT RAM or timers, the more likely it is that you'll run into issues. Conversely, the reliability issues go away if Maria has DMA turned off.
Making RIOT RAM and timer operations more reliable
The easiest way to make the RIOT timer writes reliable in 7800 mode (without having to turn off the display) is to double-check the value you've just tried to write, and repeat it if required...
lda #10 Repeat64T sta TIM64T lda INTIM cmp #9 ; should always be the value 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 rely on TIMINT instead of INTIM.
In theory you could take the same approach with RIOT RAM writes if desired...
WriteLoop lda MyData,y sta $480,y eor $480,y bne WriteLoop
...provided you're happy with jumping through these hoops for 128 bytes. RIOT RAM usage is far less tested at this point than the timers, so you may well encounter other previously undiscovered issues.
RIOT Limitations and Workarounds was written by Mike Saarna (aka RevEng) as original content for 7800.8bitdev.org.