11

To be clear, I'm talking about the actual memory cells at addresses $0000 and $0001 in the DRAM chips. Devices can of course initiate read or write requests to these address on the address/data buses to which they're connected, but that doesn't necessarily mean that this will result in an actual read from or write to the RAM device.

According to §4 of Christian Bauer's excellent VIC-II article, the CPU's data bus is tri-stated during a write access to the registers of the 6510's on-board PIO at addresses $0000 and $0001. (This is not mentioned in the 6510 data sheet.)

He says, however, that these memory locations can be written anyway though a mechanism that I don't really understand¹, involving the VIC-II actually doing the write.

He also says that, at least on some C64s, those locations in RAM can be read by the processor via reads in the $DE00 "I/O 1" area (presumably so long as a cartridge or whatever hasn't mapped some I/O devices in there) or via "sprite collisions."

So how exactly does this work? What devices (the 6510, the VIC-II, external devices you add yourself on the expansion bus, etc.) can read from and/or write to locations $0000 and $0001 in the RAM devices, and how exactly do they do it?


¹ It seems to be something to do with what goes on during φ1—the "VIC-II's phase" of RAM access—where the VIC-II has enabled RAM for its own purposes and R/W̅ is low, causing a write to happen anyway. But I don't see at all where the data come from, or why there would not be a re-write of random data to that location during φ2, when presumably nothing is driving the data bus. And I guess for this to work the VIC-II needs to be programmed to be using the first 16K block of memory? This is probably all wrong; I include this speculation just to give you an idea of where I am in my confusion.

13

Data lines hold their previous state if nothing drives them

Each trace on the motherboard has some tiny capacitance, depending on its length, routing, and distance from the ground plane. Each time there is some traffic on the data lines, the data lines D0-D7 are charged to high or depleted to low level, depending on the data put on them.

The VIC reads some data from memory on every φ1 half-cycle, no matter whether it needs to or not (when displaying the border). If nothing is driving the data bus during the φ2 half-cycle, this data remains on the data bus.

Writing to $00/$01

As you have noted, when the CPU executes an instruction to write to $00 or $01, the external data lines are not driven, so they hold their value (charge) from the previous VIC access. Although the CPU doesn't drive the data lines, it sets the address and control lines, going through all the motions to write some data without putting anything on the data bus. So the data that just happen to sit on the data bus from the previous access by the VIC gets written to memory.

If you can figure out which memory address would be accessed by the VIC just before the write by the CPU, and store some value there, that value gets copied to $00 or $01.

Reading from $00/$01 through the unmapped area

In a somewhat similar fashion, executing a read from anywhere between $DE00 and $DFFF would return whatever the VIC has read just before. I'm not sure that it can be arranged that the load instruction is executed exactly when the VIC reads from $0000, because it should happen on a bad line, when the CPU is stopped, but if there is a clever VIC timing trick to do it, then the CPU read would return the byte at $0000. However it's certainly possible to read $0001 this way.

Reading from $00/$01 through sprite collision

The bits in the VIC sprite collision register are set whenever there is a non-transparent pixel of the respective sprite at the same position as a non-background pixel of the main graphics plane.

Set the VIC to graphics mode, bitmap starting at $0000. Now the contents of $0000 and $0001 are displayed at the beginning of line 0 and 1, respectively. You can actually see the contents on the screen.

Let all sprites have an empty ($00) bitmap except byte 0. Set byte 0 of sprite 0 to $01, byte 0 of sprite 1 to $02, byte 0 of sprite 2 to $04, etc, i.e. sprite x has bit x of the first byte set. Display all of them at (0,0) and wait for the collision register to get updated. Bit x would be set, if the single pixel of sprite x collided with a pixel on the bitmap screen, effectively giving back the contents of $0000. Move the sprites down one pixel to get the value at $0001.

  • I think memory-expansion cartridges that use DMA could also access addresses 0 and 1 of RAM. – supercat Sep 21 at 18:34
  • 2
    So, in principle, you could create a Spectre-like attack against the C64? That's fascinating. – Kevin Sep 21 at 19:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.