scotws wrote:
Dr. Jefyll offers a second description [of VPA/VDA] at
viewtopic.php?f=1&t=2882&start=15#p35929 Scot, that description needed a rewrite, which I humbly present below.With 65xx processors, about 20% of the clock cycles require no memory access. Certain instructions cause the CPU to pause while it completes an internal operation of some kind. These cycles are predictable and documented -- for example in Table 5-7 of the W65C816S datasheet. Every CPU clock cycle is also a bus cycle, and, for the 20% in question, the bus cycle is a dummy -- there is no useful reason to access memory.
You'd think memory ought to be turned off during a dummy bus cycle, but the complement of control pins on the 6502 & 65c02 is so simple that memory can only be commanded to Read or Write -- it's actually impossible to tell memory to do nothing! Therefore what must happen during the dummy cycle is either a write that has no effect or a read that has no effect. Usually it's a read, and the CPU just ignores the data that was fetched. This is a reasonable substitute for doing nothing because reading from memory doesn't change what's stored there -- reading memory has no effect. (I suspect reads
may affect some EEPROMs, but only in the context of the quirky procedures used for programming. The no-effect write is rare, AFAIK only occurring on the modify cycle of a Read-Modify-Write instruction for 6502 and '816 in Emulation mode. It's no-effect because the data written is the same as that just fetched.)
-- The plot thickens! -- I/O devices get their commands in the same way memory does; the only distinction is address. Depending on the address presented by the CPU during a dummy bus cycle, it's possible an I/O device will be touched. Our default assumption is that writes produce an effect and reads do not, but in fact some I/O devices
are affected by reads (dummy or otherwise). By design, they attach extra activity to a read. For example, reading the Interrupt Flag Register of a 6522 not only returns the device's interrupt flag status to the CPU; it also clears those flags. Because flag status is erased this is called a "destructive read" -- the 6522 IFR is said to be "read sensitive." It's convenient to have the interrupt flags automatically cleared after a read, but only if you coded the read explicitly --
not when it gets slipped in behind your back!
Other I/O devices -- generally
not from the 65xx or 68xx families -- may be read-sensitive in a different way. They require an idle period between accesses. For example, a read followed too closely by another read (or write) might cause the device to become confused. Presumably you've studied the datasheet, and if such a specification exists then your code will be written to provide the necessary delay between accesses. Your plans will be spoiled if a rogue read occurs in the midst of some legitimate accesses.
-- Managing VDA. Managing without VDA. --The 65816 and 65c816 CPUs
do have the necessary pins to command memory-I/O to do nothing. There are various ways these pins (VPA and VDA) can be connected, but
the key point is to ensure read-sensitive devices can't be activated when VDA is low. Preventing activation usually means withholding the device's chip-select somehow. Alternatively, non-65xx/68xx I/O devices use read-enable and write-enable inputs called /RD and /WR or something similar, and withholding the signals to those pins is another way to prevent activation. (Withholding /WR is probably unnecessary. AFAIK all dummy cycles are reads except the M of an RMW when in Emulation mode.)
VDA can be very helpful, but attaching the necessary circuitry isn't always an attractive option, and most 65xx CPUs don't feature a VDA pin anyway.
The alternative is to ensure that addresses produced during dummy cycles don't coincide with addresses that map to sensitive I/O devices. We can control where I/O devices appear because the address map is a function of our hardware design. And we can control which dummy addresses (aka invalid addresses) appear -- they depend on our coding practices and on the choice of CPU. Here are three problem scenarios and their possible remedies:
Code:
TRB I-O_Device ;this device requires an idle period between accesses
Read-Modify-Write instructions such as INC and TRB result in three successive cycles during which the address bus bears the address of the device, and the device must activate at least for the 1st and 3rd of these cycles -- the read and the write. The 2nd cycle is a dummy, during which the CPU internally performs the "modify." During the dummy cycle the CPU's R/W pin will indicate either a read (65c02), a write (6502) or either a read
or write, depending whether Emulation mode prevails ('816). If VDA is used then the device won't activate and R/W means nothing. The dummy cycle gives the device a one-cycle pause... which
might be long enough to serve as an idle period between the cycle 1 and 3 accesses. If VDA isn't used then the 2nd cycle will be an actual read or write (which is probably not alright, given the activity in 1 and 3). You might be tempted to simply avoid using R-M-W with a device like this! Just remember that even a closely-spaced LDA and STA (ie, not R-M-W) could violate the spec, depending on the value cited.
Code:
STA Block_Of_I-O_Devices,X ;the intended device requires an idle period between accesses
This example uses absolute,X address mode, which is one of the indexed address modes which, due to a possible page crossing, can result in a dummy cycle immediately before the intended access. When this kind of dummy cycle appears on 6502 or '816 the address bus will bear either:
- a partially-processed address which, because carry is 0, needs no further processing and is okay as-is, OR...
- a partially-processed address which, because carry is 1, is $100 too low and needs its high-byte incremented.
(I mean carry from the low-bye of the index addition. The carry has not yet propagated into the high byte to produce the page crossing that's required.)
The problem illustrated in the code example happens when there's no page crossing and a dummy cycle is present anyway. (LDA will never do this, but STA can.) The correct address will be present during the dummy cycle
and during the intended access which immediately follows -- IOW a double access, which can violate the device's spec requiring an idle period between accesses.
One possible remedy is to use 65c02, which is documented as placing PC on the address bus when indexing is about to produce a page crossing. This prevents device activation because PC says where your instruction bytes are being fetched from, and that'll be an address that maps to memory, not I/O. VDA is another possible remedy.
If VDA can't be used then we could simply avoid using indexed addressing -- but that's wimpy, and costs functionality.
A better solution is to re-code the indexed addressing in a way that
guarantees a page crossing!
For example use an address ending in $FF as your base address, with an index that's always >= 1. This will eliminate the double access because the address during the dummy cycle will be $100 below the device. (Specifically, the low-byte of the address during the dummy will be the sum of the low-bytes of the index and the base address. The high-byte will be simply the high-byte of the base address -- no carry included yet.)
Code:
STA Memory_Array,X ;a 6522 or other read-sensitive I/O device is located $100 below the intended target in memory
Here's another example that involves indexed addressing and 6502 or '816. In this case a problem results when a page crossing
does occur. The partially-formed address during the dummy cycle can touch the I/O device that happens to lie $100 below the intended target. 65c02 is one possible remedy since, as noted, it places PC on the address bus during dummy cycles related to page crossing. VDA is another possible remedy, as it directly prevents device activation during the dummy cycle. Two other solutions exist. We
could mentally check ourselves every single time we code some indexed addressing.
But a more palatable and less error-prone solution is to
arrange the memory map so the 6522 has at least $100 of unpopulated space above it -- a sort of "no-fly zone"! Leaving the region unpopulated lessens the chance you'll accidentally code an indexed access into what's stored there.
I
think that covers all the main points. I should mention that dummy cycles can arise from other causes, and VDA protects against them all. But IMO the "other causes" protection is hardly needed since the addresses involved are virtually guaranteed to map to memory, not I/O. (The addresses come from the stack pointer or are addresses pertaining to a MVP or MVN operation.)
Unfortunately our understanding of dummy-cycle behavior relies very heavily on manufacturers' documentation, which may include errors, omit details or lack clarity. For that reason and others, it's possible you'll fall victim to a read-sensitivity problem someday, so it pays to remember the symptoms should they arise. For example the interrupt-flag thing will seemingly cause interrupts (or at least the flag status) to disappear, and that will be an utterly baffling problem to troubleshoot if you've forgotten about the read sensitivity of the 6522's IFR. (ORA, ORB, SR, T1L and T2L are also read-sensitive in some respects but, as with IFR, you'll suffer no consequences unless you're actually
using the associated function. And the 6522 is still a very useful chip even without these functions.)
Attachment:
6522 IFR.gif [ 83.3 KiB | Viewed 2962 times ]
Finally, another reason you might face destructive-read symptoms is a programming trick that replaces a forward BRA such as $80 $02 (ie; skip the following two bytes) with $CD (a CMP absolute opcode, whose intended purpose is merely to absorb the following two bytes as its operand). When the CMP absolute executes it generates a read cycle which may touch an I/O device. The cycle is NOT a dummy, and VDA circuitry won't neutralize it.
-- Jeff