Add early OE cutoff for CPLD bus data output enable#37
Open
BrentRector wants to merge 1 commit intoa2fpga:mainfrom
Open
Add early OE cutoff for CPLD bus data output enable#37BrentRector wants to merge 1 commit intoa2fpga:mainfrom
BrentRector wants to merge 1 commit intoa2fpga:mainfrom
Conversation
Problem:
The A2FPGA emulates multiple cards through a single A2Bridge CPLD
(XC9572XL). When any emulated card responds to a bus read, the signal
a2_bridge_bus_d_oe_n_o tells the CPLD to drive data onto the Apple II
bus. This signal is purely combinational, tracking data_out_en_i:
assign a2_bridge_bus_d_oe_n_o = ~(data_out_en_i & BUS_DATA_OUT_ENABLE);
The CDC denoise pipeline (2-stage synchronizer + 3-bit debounce + FIFO)
delays phi0 by ~6 clk_logic cycles (~100ns at 54 MHz). When cards
deassert rd_en_o at the real phi0 falling edge, the CPLD OE doesn't
release until the CDC-delayed phi0 drop reaches the FPGA ~100ns later.
This creates ~100ns of bus contention where the CPLD continues driving
the Apple II data bus while the 6502 is already presenting the next
address. A real slot card's 74LS245 releases within ~10-20ns of phi0
dropping.
This ~100ns overlap is especially harmful during I/O write cycles
($C0xx) that originate from expansion ROM ($C800-$CFFF) instruction
fetches. The Apple II motherboard's I/O decode logic (GAL/PAL) responds
to $C0xx with timing that is sensitive to bus contention. ROM patch
testing confirmed: I/O writes from C8 space break disk loading; main
RAM writes from C8 space work fine.
How discovered:
This bug was found during Apple Pascal 1.3 boot testing with emulated
Videx VideoTerm (slot 3) and SSC (slot 2) cards. Both cards perform I/O
writes during their FINIT routines executed from C8 expansion ROM.
Pascal boot hung deterministically at the disk load phase — the SSC and
Videx FINIT I/O writes from C8 space created bus contention that
corrupted subsequent Disk II I/O cycles.
The bug is latent: the ~100ns OE extension exists on every bus read
cycle, but only causes failures when multiple cards with C8 expansion
ROM are active. With only the SSC (the only upstream card with C8 ROM),
the timing margin is sufficient. Adding any second C8-capable card
(emulated or physical) increases bus activity and OE transitions,
narrowing the margin past the failure threshold. The same issue would
affect physical Apple II cards with C8 ROMs sharing the CPLD bus.
Why registering OE doesn't work: Hardware-tested — registering
a2_bridge_bus_d_oe_n_o causes system crashes (Apple II resets). The
1-cycle delay extends CPLD drive INTO phi1, creating bus contention with
the 6502 that is worse than the ~100ns overlap.
Fix:
Use the existing phase counter (phase_cycles_r) to force-release OE
before the CDC-delayed phi0 drop. The phase counter resets on each
CDC-delayed phi edge. Real phi0 drops at approximately PHASE_COUNT -
CDC_DELAY (= 20) counts. The cutoff fires at cycle 22 (OE_MARGIN=2),
approximately 37ns after the estimated real phi0 drop. IO_WRITE_DATA
triggers at cycle 10 and completes by cycle 13, so all card data is
latched to the bridge well before cutoff.
This reduces the contention window from ~100ns to ~37ns, more closely
matching real slot card behavior. The 37ns post-phi0 margin is
conservative — the 6502 latches data before phi0 drops, so the data
hold time is already satisfied.
Only applies to CPLD-based boards (a2n20v2, a2n20v2-Enhanced). The
a2mega board has direct bus access (no CPLD bridge) and is not affected.
If OE_MARGIN=2 is too aggressive (cards fail to respond), it can be
increased to 3 or 4. If too conservative, it can be reduced to 1.
Testing:
Verified on Apple ][+ hardware (A2N20v2 board) with emulated cards in
slots 2 (SSC), 3 (Videx), 4 (Mockingboard), and 7 (SuperSprite).
Apple Pascal 1.3 boots 100% with all emulated cards enabled. Original
Videx VideoTerm Demo application runs correctly. Pascal applications
run without errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Files:
boards/a2n20v2/hdl/bus/apple_bus.sv,boards/a2n20v2-Enhanced/hdl/bus/apple_bus.svThe CDC denoise pipeline (2-stage sync + 3-bit debounce + FIFO) delays phi0 by ~6
clk_logiccycles (~100ns at 54 MHz). The CPLD bus data output enable (
a2_bridge_bus_d_oe_n_o) is purelycombinational, tracking
data_out_en_i. When cards deassertrd_en_oat the real phi0 fallingedge, the CPLD OE doesn't release until the CDC-delayed phi0 drop reaches the FPGA — creating
~100ns of bus contention where the CPLD continues driving the Apple II data bus while the 6502
is already in its next cycle. A real slot card's 74LS245 releases within ~10-20ns of phi0
dropping.
This ~100ns overlap is especially harmful during I/O write cycles (
$C0xx) that originate fromexpansion ROM (
$C800-$CFFF) instruction fetches. The Apple II motherboard's I/O decode logicresponds with timing sensitive to bus contention. Binary search via ROM patching confirmed: I/O
writes from C8 space break disk loading; main RAM writes from C8 space work fine.
Why registering OE doesn't work
Hardware-tested: registering
a2_bridge_bus_d_oe_n_ocauses Apple II resets. The 1-cycledelay extends CPLD drive INTO phi1, creating bus contention with the 6502 that is worse than
the ~100ns overlap.
The fix
Use the existing phase counter (
phase_cycles_r) to force-release OE before the CDC-delayedphi0 drop. Real phi0 drops at approximately
PHASE_COUNT - CDC_DELAY(= 20) counts. Thecutoff fires at cycle 22 (
OE_MARGIN=2), ~37ns after the estimated real phi0 drop.IO_WRITE_DATAtriggers at cycle 10 and completes by cycle 13, so all card data is latchedwell before cutoff.
This reduces the contention window from ~100ns to ~37ns. The margin parameters (
OE_MARGIN)can be tuned if needed: increase to 3-4 if cards fail to respond, decrease to 1 if more
aggressive cutoff is needed.
Only applies to CPLD-based boards (a2n20v2, a2n20v2-Enhanced). The a2mega board has direct bus
access and is not affected.
How Discovered
Found during Apple Pascal 1.3 boot testing with Videx VideoTerm (slot 3) and SSC (slot 2)
emulated cards. Both perform I/O writes during FINIT routines from C8 expansion ROM. Pascal
boot hung deterministically at the disk load phase. The root cause was isolated through ROM
patch binary search: replacing C8-space I/O writes with main RAM writes eliminated the hang.
The bug is latent: the ~100ns OE extension exists on every bus read cycle, but only causes
failures when multiple cards with C8 expansion ROM are active. With only the SSC (the only
upstream card with C8 ROM), the timing margin is sufficient. Adding any second C8-capable
card increases bus activity and OE transitions, narrowing the margin past the failure
threshold. Physical Apple II cards with C8 ROMs sharing the CPLD bus would also be affected.
Test Plan