-
Notifications
You must be signed in to change notification settings - Fork 0
RIOT
The RIOT (RAM-I/O-Timer; called "PIA" in the Stella Programmer's Guide) has no direct analog in most other consoles Rusty2600's sibling emulators cover — it's a standard MOS 6532, entirely independent of the TIA. It supplies the three things the VCS needs outside the TIA: the console's only RAM, its two I/O ports, and an interval timer.
Audio is NOT here. The Atari 2600's two sound channels live entirely in the TIA (see TIA); the 6532 has no sound hardware of any kind. This is worth stating plainly since a reader coming from another console's architecture might otherwise assume a chip named "I/O and Timer" also carries sound — it doesn't, on this console.
128 bytes, at $80..=$FF. There is no separate work RAM on the 2600 — this is it, and the CPU stack overlaps this same region (the 6502 $0100 stack page maps into the RIOT RAM mirror). Rusty2600's Bus therefore has no wram field at all; the RIOT's own RAM array is the entire story. Power-on RAM contents are randomized from the same seeded PRNG that seeds CPU register state (see Architecture-Decision-Records ADR 0004/0006), never the OS RNG.
| Port | Address | DDR | Contents |
|---|---|---|---|
SWCHA |
$280 |
SWACNT ($281) |
Port A: the two joystick directionals (and paddle/keypad multiplexing) |
SWCHB |
$282 |
SWBCNT ($283) |
Port B: console switches — Reset, Select, Color/B&W, the two difficulty switches |
Idle inputs read high (pulled up): ports power on to 0xFF.
Writing the count to one of four prescaler-selecting addresses starts the timer decrementing at that rate:
| Write addr | Name | Prescale | Tick period (NTSC) |
|---|---|---|---|
| $294 | TIM1T |
1 CPU cycle | 838 ns |
| $295 | TIM8T |
8 cycles | 6.7 µs |
| $296 | TIM64T |
64 cycles | 53.6 µs |
| $297 | T1024T |
1024 cycles | 858.2 µs (power-on default) |
Read the current value at INTIM ($284) and the underflow status at INSTAT ($285, undocumented). After hitting zero, the timer holds 0 for one prescale interval, then wraps to $FF and decrements once per CPU cycle — the classic "fast rollover" real hardware exhibits. Because the 6507 has no interrupt lines, the timer cannot fire an IRQ; software must poll INTIM, and this is the 2600's only substitute for a frame interrupt.
Once the timer underflows, real 6532 silicon decrements at the forced 1-CPU-cycle rate until the next time a program reads INTIM — at which point the divider reverts to the originally-selected prescale. Rusty2600 originally modeled this as two separate flags (one for the INSTAT-visible interrupt latch, one for the actual decrement-rate gate) rather than the single flag real silicon uses for both, which meant a program's timer, once underflowed even once, stayed in fast mode forever. This was found via a real differential-testing session against Gopher2600 and Stella on Pitfall II's boot-time RIOT-timer wait loop, and fixed to match the confirmed real-hardware behavior exactly. See Testing-Strategy for more on how this kind of bug gets found.
The RIOT advances on the CPU cycle (every third TIA color clock); the interval timer is further prescaled by 1/8/64/1024. See Lockstep-Scheduler for the full divisor table.
Rusty2600 is a cycle-accurate Atari 2600 (VCS) emulator written in pure Rust. Licensed under MIT OR Apache-2.0. | GitHub Repository | Web Demo