From b4c2aa0a4076c388cf5fe6638b95686445573d78 Mon Sep 17 00:00:00 2001 From: Mark Eid Date: Tue, 18 Jul 2023 16:42:46 -0500 Subject: [PATCH] fpga: x400: Fix SPI trigger clock crossing Original-commit: 5da42f3542ed555623c73c7ce487b9960849f209 --- top/x400/x4xx_gpio_spi.v | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/top/x400/x4xx_gpio_spi.v b/top/x400/x4xx_gpio_spi.v index 25591d5..e9d3c0f 100644 --- a/top/x400/x4xx_gpio_spi.v +++ b/top/x400/x4xx_gpio_spi.v @@ -369,19 +369,48 @@ module x4xx_gpio_spi #( assign readback_stb_extended = readback_stb; `else // X410 - // Register set_stb for use in 2x domain. + + // We only trigger one cycle of set_stb_2x per state change. This way the latency + // is deterministic from the first change and aligned to the correct address, + // without the need to pipeline the signal. + // ┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ + //clk : └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─── + // xxxxxx/ \/ \/ \xxxxxxxxxxxxxxxxxxxxxx + //state : xxxxxx\ ctrl /\ div /\ data /xxxxxxxxxxxxxxxxxxxxxx + // xxxxxxxxxxxxxxxxxx/ \/ \/ \xxxxxxxxxx + //state_dlyd : xxxxxxxxxxxxxxxxxx\ ctrl /\ div /\ data /xxxxxxxxxx + // ┐ ┌───────────────────────────────────┐ + //set_stb : └─────────────────┘ └───────── + // xxxxxxxxxxxxxxxxxx/ \/ \/ \xxxxxxxxxx + //set_addr : xxxxxxxxxxxxxxxxxx\ 0x1 /\ 0x0 /\ 0x2 /xxxxxxxxxx + // ──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ + //clk_2x : └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └ + // xxxxxxxxxxxxxxxxxxxxxxxx/ \/ \/ \xxxx + //state_dlyd_2x: xxxxxxxxxxxxxxxxxxxxxxxx\ ctrl /\ div /\ data /xxxx + // ┌─────┐ ┌─────┐ ┌─────┐ + //set_stb_2x : ────────────────────────┘ └─────┘ └─────┘ └───────── + // ┌─────┐ + //trigger_spi : ──────────────────────────────────────────────────────┘ └─── + // + reg set_stb_2x = 1'b0; - reg ctrlport_clk_phase = 1'b1; + reg [2:0] state_dlyd, state_dlyd_2x = IDLE; + + always @ (posedge ctrlport_clk) begin + if (ctrlport_rst) begin + state_dlyd <= IDLE; + end else begin + state_dlyd <= state; + end + end always @ (posedge ctrlport_clk_2x) begin if (ctrlport_rst) begin - ctrlport_clk_phase <= 1'b1; - set_stb_2x <= 1'b0; + state_dlyd_2x <= IDLE; + set_stb_2x <= 1'b0; end else begin - // Assert strobe only during a single 2x cycle of the - // 1x pulse, when 1x clock is low. - set_stb_2x <= ctrlport_clk_phase & set_stb; - ctrlport_clk_phase <= ~ctrlport_clk_phase; + state_dlyd_2x <= state_dlyd; + set_stb_2x <= set_stb && (state_dlyd_2x != state_dlyd); end end