diff options
author | 2023-07-18 16:42:46 -0500 | |
---|---|---|
committer | 2023-07-31 17:35:44 -0500 | |
commit | 5da42f3542ed555623c73c7ce487b9960849f209 (patch) | |
tree | 7c9479c6e334e0e5fba7e82f20f06816d91fe891 | |
parent | docs: update FPGA build docs (diff) | |
download | uhd-5da42f3542ed555623c73c7ce487b9960849f209.tar.xz uhd-5da42f3542ed555623c73c7ce487b9960849f209.zip |
fpga: x400: Fix SPI trigger clock crossing
-rw-r--r-- | fpga/usrp3/top/x400/x4xx_gpio_spi.v | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/fpga/usrp3/top/x400/x4xx_gpio_spi.v b/fpga/usrp3/top/x400/x4xx_gpio_spi.v index 25591d570..e9d3c0fc0 100644 --- a/fpga/usrp3/top/x400/x4xx_gpio_spi.v +++ b/fpga/usrp3/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 |