Spurious LCD write caused by an address-transition race on a 65C02 board
A 65C02 board runs at 1 MHz. RAM is 0x0000–0x3FFF, an HD44780 LCD occupies 0x7000–0x700F and ROM is 0xC000–0xFFFF. The LCD chip select is decoded with 74HC00 and 74HC04 gates from A15–A12, and the LCD enable E is formed as CS + /WR. Because the LCD is slow, the designer stretched /WR with a 10 kΩ/100 pF network so that E stays low for about 1 µs. The system works, but a routine that stores to the top of RAM (STA $3FFF) and then fetches the next instruction from ROM produces stray characters on the display. A scope triggered on the address transition 0x3FFF → 0xC000 shows A14 rising about 18 ns before A13 and A12 fall, and a 20 ns low-going glitch on E while the data bus still holds the stored value. The LCD datasheet requires E high for at least 450 ns and data stable around the falling edge of E.
1. Show the transient address, and trace the sequence that turns it into a stray character on the display.
Read the worked answer
The transient address. 0x3FFF is A15–A12 = 0,0,1,1. 0xC000 is A15–A12 = 1,1,0,0. A14 rises ~18 ns before A13 and A12 fall, so for that window the bus reads A15 = 0, A14 = 1, A13 = 1, A12 = 1 - that is 0x7000, the LCD block. The decode is correct for every stable address; the intermediate combination is a valid address for a different device.
Why it becomes a write. The stretched /WR is still low during the address change (that is exactly what the 1 µs RC does), so the transient CS assertion pulls E low. E then returns high when the address finishes changing. The LCD latches on the falling edge of E, so it takes the 20 ns low as a real enable and latches whatever is on the data bus - which is still the value stored to $3FFF, a stale byte, presented as a command. That is how a data store at the top of RAM appears as a random instruction or character on the display.
Why it is intermittent. It depends on which pairs of addresses are adjacent in the program and on the skew between the address buffers, so it appears on particular code paths rather than uniformly. The stretched /WR is the enabler: without it, the write strobe would have ended before the address moved.
2. Is this a static hazard that a better minimisation would remove? Explain what kind of fault it is and why Karnaugh-map reasoning does not fix it.
Read the worked answer
It is a multi-bit transition race, not a static hazard. In a static hazard one input changes while the others are held constant and a two-level implementation momentarily drops the output because two product terms hand over without overlap; the cure is a consensus term, one extra product term. Here several address bits change at once and the decode output is correct for every stable input combination; the intermediate combination 0x7000 is simply a legal address for another device. No product term can be added, because the function never gives a wrong answer for a stable input - the error lives only in the time domain.
Consequences of the distinction:
- The fault cannot be found by K-map minimisation, by a different cover, or by adding don't-care terms. SOP and POS implementations both show it.
- It cannot be found in zero-delay simulation; it needs gate-level timing with the real buffer delays, or a bench measurement.
- The fixes are temporal: qualify the decode with a strobe that is only active when addresses are stable (φ2 or the address strobe), register the decode on the clock edge, or make the write strobe end before the address can change. Only after the decode is qualified does the minimisation of the gate count matter.
3. Choose and justify a fix, using a timing budget that satisfies the HD44780's 450 ns enable width at a 1 MHz bus.
Read the worked answer
Option A - remove the RC and gate E with φ2. With /WR no longer stretched, E = /CS·/WR·φ2 can only be low when the address decode is stable, because the CPU holds the address through the cycle. At 1 MHz, φ2 is high for 500 ns, so a low E pulse of roughly 400–500 ns meets the 450 ns minimum only if the decode and gate delays are small: 500 ns − (2 × 15 ns) ≈ 470 ns, a ~20 ns margin. That is too tight for a proper design and varies with VCC and temperature.
Option B - a one-shot on /WR. Use a 74HC123 triggered by the CPU write strobe to generate a fixed 1 µs E, with /CS ANDed in only as a gate, and remove the RC. The pulse width no longer depends on the address, and the address is stable before /WR is asserted, so a decode glitch cannot start a pulse. Cost: one package, and the one-shot must be retrigger-safe.
Option C - registered decode. Latch the chip select with a 74HC273 on the φ2 falling edge so CS changes only at a clock boundary. Safe but adds a cycle and still needs a write strobe that respects the 450 ns.
Recommendation. Option B, with a series 100 Ω at the E output for the cable. It decouples pulse width from the address bus, guarantees the 450 ns with margin, and removes the RC that caused the fault. Verify with a scope across E at the LCD connector: width ≥ 450 ns, RS and data stable ≥ 195 ns before the falling edge, and no glitch on any address transition across the whole memory map.