rtl: hold address/data after AS through S0 - #89
Conversation
The stock RTL declares M68K_BR_n and M68K_BGACK_n as input ports but
never samples them, and ties M68K_BG_n high — so the CPLD ignores
bus-master requests from Zorro II devices like the A590 SCSI controller
during DMA. This patch implements the standard 68000 BR/BG/BGACK
handshake:
- Two-flop synchronizers on M68K_BR_n and M68K_BGACK_n
- A 3-state arbitration FSM (IDLE -> GRANTING -> RELEASED -> IDLE)
sharing the c200m clock domain with the existing CPU FSM
- Tri-state hand-off: M68K_FC, M68K_AS_n, M68K_UDS_n, M68K_LDS_n,
M68K_RW are now inout, driven through a bus_owned flag so the
PiStorm cleanly releases the bus when BGACK is asserted by the
requester
- The CPU FSM stays parked at S1 while the arbiter is not in IDLE,
matching the real 68k's behavior (no new cycles are started
between BG-out and BGACK-in)
- Internal weak pullups on BR_n / BGACK_n to backstop the
motherboard's external pullups; the long CPLD-to-CPU-socket trace
picks up DMA noise otherwise, which previously caused intermittent
lockups on fast-RAM accesses during heavy disk activity
- set_false_path entries in the SDC for the new async inputs
- rtl/pistorm_tb.v: an Icarus Verilog testbench covering eight
scenarios — normal cycle, BR while idle, queued op during release,
BR asserted mid-cycle, BR pulsed (sync filter), BGACK delayed,
two grants back-to-back, BR + queued op race
Also moves the `ipl` reg declaration earlier in pistorm.v so open
source simulators (iverilog) accept declaration-before-use; Quartus
was lenient about this but iverilog is not.
Tested on PiStorm Classic (EPM240) + Amiga A500 + A590 sidecar:
devtest scsi.device 0 -i 8192 -l 1000 -m zorro (A590 fast RAM via DMA)
devtest scsi.device 0 -i 8192 -l 1000 -m chip (chip RAM via DMA)
devtest scsi.device 0 -i 8192 -l 1000 (no -m, works as before)
Destructive read/write modes also pass — devtest compares read-back
data, so the bus is verified correct both with and without DMA.
Resources: ~86 / 570 LEs on EPM570T100C5 (15 %), 88 / 240 LEs on
EPM240T100C5 (37 %).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Restructure the FSM end-of-cycle so AS/DS deassert on the stock S7 schedule but the address-latch OEs and the write-data buffer stay driven through to S0 (one half-c7m of hold after AS). S0 then releases the OEs and waits for op_req and arb_state == ARB_IDLE on c7m_falling, so the deassertion is deterministically clock-aligned and the arbiter window is well defined. S1 collapses to a transitional c7m_rising into S2. This is the 68000-style address/data hold after AS that some Zorro II cards (e.g. GVP RAM) need and that the stock PiStorm gave as zero. The inter-cycle gap grows from 0.5 to 1.5 c7m, putting the cycle at the spec 4-clock 68k bus cycle. Quartus STA on PI_CLK at 200 MHz: this commit's slow-corner worst-case setup slack is within fitter noise of pristine main (no arbitration); the change is timing-neutral. Hold and pulse-width slack are positive at both corners. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add quartus_docker_install.sh (one-time Quartus install into ~/intelFPGA_lite, MAX II/V device family only) and quartus_docker_run.sh (wraps the stock raetro/quartus:base image with -e HOME / PATH / LD_PRELOAD, the LD_PRELOAD being the tcmalloc fix for Quartus 20.1's libsys_cpt udev double-free). The build flow consumes them via ../quartus_docker_run.sh from rtl/. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Build the EPM240 and EPM570 bitstreams via a throwaway pistorm_build
Quartus revision so the tracked pistorm.qpf/qsf are never mutated.
Outputs gzipped SVFs as rtl/{EPM240,EPM570}_pistorm.svf.gz.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Compile and run rtl/pistorm_tb.v with Icarus Verilog and exit non-zero if the testbench does not report PASSED. No Quartus or Docker required; used as a fast pre-build sanity check. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
SVF files compiled from this PR using build_svfs.sh. EPM240_pistorm.svf.gz Sof far I have only tested the EPM240 variant on an A500 Rev 5 with:
Please help test different configurations and report here. I used AmigaTestKit to test RAM access and devtest for I/O and DMA: Add |
Quartus STA: PI_CLK setup slack at 200 MHz (worst-case / TNS, ns)
Slow corner = 1200 mV, 85 C; Fast = 1200 mV, 0 C. Hold and pulse-width slacks are positive across all configs and corners. Compared to pristine Numbers come from quartus_sta against pistorm_build for both families, with PI_CLK constrained at 200 MHz via pistorm.sdc. Same fitter results as the three-way comparison from earlier (numbers are reproducible across runs). Full timing analysis (HTML) |
…ups) pistorm.v: reformat with 4-space indent and section banners, group port list by function, add copyright header. One functional change: move the E-counter and M68K_E generation from @(negedge c7m) into @(posedge c200m) if (c7m_falling), making the whole design single-clock on c200m and removing the standalone `wire c7m = c7m_sync[2]` net. pistorm.sdc: drop Intel/Quartus boilerplate; replace the per-path set_false_path pairs between PI_CLK and M68K_CLK/C1/C3 with one set_clock_groups -asynchronous; cut CLK_SEL false_path; extend the async input list with M68K_RESET_n and M68K_HALT_n, and the async output list with PI_RESET. Verified with iverilog testbench, Quartus 20.1.1 Lite STA on EPM240T100C5 and EPM570T100C5 (fast corner clean, slow corner negative slacks fall on the same paths reported on main), and hardware testing on an A3000 with AmigaTestKit memory tests plus Boing demo concurrent DMA - no regression. Co-Authored-By: Claude Schwarz <claude.schwarz@gmail.com>
|
Firmware built from this PR after Claude's improvements: Timing report for the above: The EPM240 was stress-tested on my A500 with:
Both configurations passed hours of AmigaTestKit memory tests in all regions. DMA works fine on the A590 in all regions, while the GVP still occasionally fails compares in devtest's destructive tests, but previously it was just hanging, so it's an improvement. I suspect these rare failures are caused by an unrelated hardware quirk with my setup, but I couldn't confirm it by testing without the PiStorm. Another user independently tested the EPM240 firmware on an A2000 with a MaxV 5M240Z. The EPM570 firmware remains untested. |
Rework S0 so all decisions happen on c7m_falling. With an op queued and the bus owned, switch the external latches directly to the next op without releasing OE: the address bus never floats between back-to-back cycles, and the new address and RW are driven through S1, giving half a c7m of setup before AS asserts in S2 - the same sequence as a real 68000 (address valid from S1). When idle or arbitration is pending, release the bus; total address/data hold after AS grows to one full c7m (~140 ns), which Amigas with Buster (e.g. A2000) need to latch the address cleanly. bus_idle now also requires LTCH_A_OE_n released, so the arbiter cannot grant while the address latches still drive the bus. Also drop two comments that restated the code (e_counter / M68K_E).
The firmware dropped TXN early in S4 (via a 3-tick delay shifter) so the Pi could overlap the next op with the cycle tail. But the Pi's register writes pulse the external latch LEs combinationally: once TXN is low, the Pi can rewrite the address/write-data latches during S5-S7, changing the bus mid-cycle while AS/DS are still asserted. A real 68000 holds address and data until the cycle ends. Keep TXN asserted until the S7->S0 edge, so the Pi's earliest latch reload (poll + GPIO latency) lands in S0, between the old address's hold past AS and the new address's setup through S1. Costs some op-to-op overlap; correctness first. Removes the delay shifter.
DTACK only promises read data by the end of S6 (a real 68000 latches on the S6->S7 falling edge); slaves with buffered data paths can deliver well after asserting DTACK. Closing the read latch at S5 entry missed late-arriving data. Close at S6 entry instead, half a c7m more margin. Two later capture points were tried and rejected: closing on the synchronized S6->S7 edge corrupts chipmem (the c7m synchronizer plus output delay land the physical close 15-25 ns after the real edge, past Agnus' slot turnover; the machine does not boot), and a c200m tick-counted close just before the real edge did not help the GVP either. This depends on the previous commit: TXN must not drop before the latch closes, or the Pi could read it while still transparent. Validated on A500: boots, A590 passes devtest -i 8192 -l 1000 on zorro/chip/fast under load, GVP -m chip passes under load. GVP -m zorro (DPRC hidden DMA to onboard RAM) still fails under load on all our builds; scoped to not be read-latch timing, no BR involved.
|
Just pushed a large update tested thoroughly on my A500 R5 with an A590 and a GVP HC+8 Series II. Please test it with different Amiga variants and Zorro cards. BinariesChanges relative to previous binaries
All three fixes have been implemented by Claude Opus in response to test failures and to align the PiStorm timings to the official 68000 bus cycle diagrams. Timing reportTest results
The last failure happens every time if the Boing demo is running in the background, rarely without it. It means that CPU activity, even to other regions, can disrupt the DPRC hidden DMA somehow. While this remaining issue proves that there's still a critical difference between the PiStorm timing and a real 68000, this firmware behaves substantially better than anything else I have tested before. |
|
Bus timing diagram of the current release.
NOTE: the first S0 cycle has several "3-stated" signals because it's at the start of the simulation. The second S0 cycle should be representative. Generated by this script (requires python3-matplotlib): |

Adds a 68000-style address/data hold after AS by holding the latch OEs and write-data buffer through S0 (one half-c7m of hold past the AS rising edge that ends S7). Intended for Zorro II cards that need address and data valid past AS to latch correctly, e.g. GVP RAM.
Stacked on #87: until #87 merges this diff also shows the arbitration commit; review/merge #87 first.
Build/test infra: