rtl: 68k bus arbitration (BR/BG/BGACK) for Zorro II DMA#87
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>
|
I totally vibe coded this since I know calmost nothing about Verilog. Sorry if this isn't not the correct approach. What I can say is that I have flashed the EPM240 variant on my PiStorm Classic and tested it with my A590 as described above by Claude. DMA works reliably with it: This svf is untested, since I don't have an EPM570-based PiStorm: |
|
I also have a GVP Impact HC+8 controller which I can hook up to my A500 with a Zorro adapter. From past testing, I know that this combo requires the "longer_hold" firmware in order to fix data corruption issues when accessing onboard Fast RAM. I have attempted to recreate this patch since the sources are lost, but it's out of scope for this PR. Lightly tested patch available on demand. |
|
I tested the GVP Impact HC+8, and it's also behaving very well. All I/O tests with DMA to chipram and GVP onboard ram are passing: |
|
AmigaTestKit crashed (yes, crashed!) once during a long-running memory test on the GVP onboard RAM :-( However, I have already experienced RAM issues on this GVP card when 4 SIMMs are installed. My DMA changes are unlikely to affect the stability of CPU bus cycles (except for slight timing differences). This happened with a single c7m delay cycle in S6, but I think my GVP requires 2 delay cycles (as done by the longer_hold firmware). I will test more and report back. |
|
UPDATE: this was a bad idea, do not use these variants. See PR #89 instead. I built a few more variants of the bus arbitration firmware with extra changes to holds AS, address and data lines for the specified number of 7MHz clock semi-cycles: EPM240_0hold.svf.gz The 0hold variant should match the stock firmware timings. The 2hold variant works on my A500 and makes access to the GVP onboard RAM 100% reliable, but I still see occasional compare errors in devtest's integrity tests when using GVP onboard RAM (-m zorro). I think this matches the former "long_hold" firmware. The 3hold variant is my attempt to approximate the "longer_hold" firmware: since 2 full 7MHz cycles would throw the m68k bus access beyond the 4-clock cycle expected by Agnus, I thought that maybe 3 half cycles would fit. However, IT MAKES MY A500 RESET LOOP. I'm sharing it in the hope someone can figure out what's wrong with it. These are entirely untested, since I don't have a PiStorm with an EPM570: I will open a followup PR after some more testing and cleaning up things a bit. Meanwhile, this is the raw diff corresponding to the above builds. Comments welcome. diff --git a/rtl/pistorm.v b/rtl/pistorm.v
index d0c1b8c..abdba94 100644
--- a/rtl/pistorm.v
+++ b/rtl/pistorm.v
@@ -2,6 +2,17 @@
* Copyright 2020 Claude Schwarz
* Copyright 2020 Niklas Ekström - rewrite in Verilog
*/
+
+// Extra bus-access hold: HOLD_CLOCKS half-c7m steps added in S6 to every
+// 68k cycle, holding AS / address / data longer before deassert. Meant to
+// help Zorro II cards that mishandle the PiStorm's very short bus cycles
+// (e.g. GVP RAM). Default 0 = stock, so scripts that don't set it (e.g.
+// the Windows make.bat) keep working.
+// 0 = stock 2 = +1 c7m 3 = +1.5 c7m
+`ifndef HOLD_CLOCKS
+`define HOLD_CLOCKS 0
+`endif
+
module pistorm(
output reg PI_TXN_IN_PROGRESS, // GPIO0
output reg PI_IPL_ZERO, // GPIO1
@@ -186,6 +197,11 @@ module pistorm(
reg [2:0] state = 3'd0;
reg [2:0] PI_TXN_IN_PROGRESS_delay;
+ // Bus-access hold depth, in half-c7m steps. At HOLD_N==0 the S6 compare
+ // folds to a constant and synthesis prunes s6_hold_cnt, so 0 == the
+ // original counter-free logic.
+ localparam HOLD_N = `HOLD_CLOCKS;
+ reg [2:0] s6_hold_cnt = 3'd0; // half-c7m hold counter — see S6
// -------- Bus arbitration (BR/BG/BGACK) --------
// Two-flop synchronizers for async inputs from the other master.
@@ -330,10 +346,18 @@ module pistorm(
end
end
- 3'd6: begin // S6
- if (c7m_falling) begin
- M68K_VMA_n <= 1'b1;
- state <= 3'd7;
+ 3'd6: begin // S6 — bus-access hold (HOLD_CLOCKS half-c7m steps).
+ // Stock exits on the first c7m edge; each extra step holds AS /
+ // address / data one more half c7m (~70 ns) before S7 deasserts.
+ // Counting both c7m edges gives the half-c7m resolution.
+ if (c7m_rising || c7m_falling) begin
+ if (HOLD_N == 0 || s6_hold_cnt == HOLD_N) begin
+ s6_hold_cnt <= 3'd0;
+ M68K_VMA_n <= 1'b1;
+ state <= 3'd7;
+ end else begin
+ s6_hold_cnt <= s6_hold_cnt + 3'd1;
+ end
end
end
|
|
Timing analysis of the two svf variants (EPM240 and EPM570) built from this PR: |
Summary
Implements the standard 68000 BR / BG / BGACK bus-arbitration handshake in the CPLD. The stock RTL declares those pins as ports but never samples them, so Zorro II bus-master devices (e.g. the A590 SCSI controller) can't take the bus for DMA.
Changes in
rtl/pistorm.v:M68K_FC,M68K_AS_n,M68K_UDS_n,M68K_LDS_n,M68K_RWare nowinout, gated by abus_ownedflag so the PiStorm cleanly releases the bus when the requester asserts BGACKChanges in
rtl/pistorm.qsf:M68K_BR_n/M68K_BGACK_n— the long CPLD-to-CPU-socket trace was picking up DMA noise on the A500 and false-triggering the arbiter, which caused intermittent lockups during heavy disk activity even on fast-RAM accessesChanges in
rtl/pistorm.sdc:set_false_path -fromentries for the new async inputsNew
rtl/pistorm_tb.v:Resources: ~86 / 570 LEs on EPM570T100C5 (15 %), 88 / 240 LEs on EPM240T100C5 (37 %).
Test plan
Tested on PiStorm Classic (EPM240) + Amiga A500 + A590 sidecar:
devtest scsi.device 0 -i 8192 -l 1000 -m zorro— A590 fast RAM via DMAdevtest scsi.device 0 -i 8192 -l 1000 -m chip— chip RAM via DMA (Agnus arbitration)devtest scsi.device 0 -i 8192 -l 1000— no-m, regression checkiverilog -g2012 -o pistorm_tb pistorm_tb.v pistorm.v && vvp pistorm_tb— all 8 scenarios passDraft because I want to do one more hardware run with the latest build to confirm no regressions before marking ready for review.
🤖 Generated with Claude Code