aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rtl/fmc_arbiter.v401
1 files changed, 228 insertions, 173 deletions
diff --git a/src/rtl/fmc_arbiter.v b/src/rtl/fmc_arbiter.v
index 037d640..376e85b 100644
--- a/src/rtl/fmc_arbiter.v
+++ b/src/rtl/fmc_arbiter.v
@@ -7,7 +7,7 @@
//
//
// Author: Pavel Shatov
-// Copyright (c) 2015, 2018 NORDUnet A/S All rights reserved.
+// Copyright (c) 2015, 2018-2019 NORDUnet A/S All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
@@ -38,174 +38,208 @@
//======================================================================
module fmc_arbiter
- (
- // fmc bus
- fmc_a, fmc_d,
- fmc_ne1, fmc_nl, fmc_nwe, fmc_noe, fmc_nwait,
-
- // system clock
- sys_clk,
-
- // user bus
- sys_addr,
- sys_wr_en,
- sys_data_out,
- sys_rd_en,
- sys_data_in
- );
-
-
- //
- // Parameters
- //
- parameter NUM_ADDR_BITS = 22;
-
-
- //
- // Ports
- //
- input wire [NUM_ADDR_BITS-1:0] fmc_a;
- inout wire [ 31:0] fmc_d;
- input wire fmc_ne1;
- input wire fmc_nl;
- input wire fmc_nwe;
- input wire fmc_noe;
- output wire fmc_nwait;
-
- input wire sys_clk;
-
- output wire [NUM_ADDR_BITS-1:0] sys_addr;
- output wire sys_wr_en;
- output wire [ 31:0] sys_data_out;
- output wire sys_rd_en;
- input wire [ 31:0] sys_data_in;
-
-
- //
- // Data Bus PHY
- //
-
- /* PHY is needed to control bi-directional data bus. */
-
- wire [31: 0] fmc_d_ro; // value read from pins (receiver output)
- wire [31: 0] fmc_d_di; // value drives onto pins (driver input)
-
- fmc_d_phy #
- (
- .BUS_WIDTH(32)
- )
- d_phy
- (
- .buf_io(fmc_d), // <-- connect directly to top-level bi-dir port
- .buf_di(fmc_d_di),
- .buf_ro(fmc_d_ro),
- .buf_t(fmc_noe) // <-- bus direction is controlled by STM32
- );
+(
+ // fmc bus
+ fmc_a, fmc_d,
+ fmc_ne1, fmc_nl, fmc_nwe, fmc_noe, fmc_nwait,
+
+ // system clock, i/o clock
+ sys_clk,
+ io_clk,
+
+ // user bus
+ sys_addr,
+ sys_wr_en,
+ sys_data_out,
+ sys_rd_en,
+ sys_data_in
+);
+
+
+ //
+ // Parameters
+ //
+ parameter NUM_ADDR_BITS = 24;
+
+
+ //
+ // Ports
+ //
+ input wire [NUM_ADDR_BITS-1:0] fmc_a;
+ inout wire [ 31:0] fmc_d;
+ input wire fmc_ne1;
+ input wire fmc_nl;
+ input wire fmc_nwe;
+ input wire fmc_noe;
+ output wire fmc_nwait;
+
+ input wire sys_clk;
+ input wire io_clk;
+
+ output wire [NUM_ADDR_BITS-1:0] sys_addr;
+ output wire sys_wr_en;
+ output wire [ 31:0] sys_data_out;
+ output wire sys_rd_en;
+ input wire [ 31:0] sys_data_in;
+
+
+ //
+ // Data Bus PHY
+ //
+
+ /* PHY is needed to control bi-directional data bus. */
+
+ wire [31: 0] fmc_d_ro; // value read from pins (receiver output)
+ wire [31: 0] fmc_d_di; // value drives onto pins (driver input)
+
+ fmc_d_phy #
+ (
+ .BUS_WIDTH(32)
+ )
+ d_phy
+ (
+ //.buf_io (fmc_d_swapped), // <-- connect directly to top-level bi-dir port
+
+ // we just swap the order of wires in the bi-directional data bus
+ .buf_io({fmc_d[7:0], fmc_d[15:8], fmc_d[23:16], fmc_d[31:24]}),
+
+ .buf_di (fmc_d_di), // driver input (from FPGA to STM32)
+ .buf_ro (fmc_d_ro), // receiver output (from STM32 to FPGA)
+ .buf_t (fmc_noe) // <-- bus direction is controlled by STM32
+ );
+
+
+ //
+ // CDC Helper Signals
+ //
+ reg cdc_slow_ff = 1'b0;
+ reg cdc_fast_ff = 1'b0;
+
+ always @(posedge io_clk) cdc_slow_ff <= ~cdc_slow_ff;
+ always @(posedge sys_clk) cdc_fast_ff <= cdc_slow_ff;
+
+ reg cdc_same_edges;
+
+ always @(posedge sys_clk)
+ cdc_same_edges <= cdc_slow_ff ^ cdc_fast_ff;
+
//
- // Two-Stage Synchronizer
+ // Synchronizer
//
- (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg [23: 0] fmc_a_ff1;
- (* SHREG_EXTRACT="NO" *) reg [23: 0] fmc_a_ff2;
+ (* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg [NUM_ADDR_BITS-1:0] fmc_a_ff1;
+ (* SHREG_EXTRACT="NO" *) reg [NUM_ADDR_BITS-1:0] fmc_a_ff2;
+ (* SHREG_EXTRACT="NO" *) reg [NUM_ADDR_BITS-1:0] fmc_a_ff3;
- (* SHREG_EXTRACT="NO" *) (* IOB="TRUE" *) reg [31: 0] fmc_d_ro_ff1;
- (* SHREG_EXTRACT="NO" *) reg [31: 0] fmc_d_ro_ff2;
+ (* SHREG_EXTRACT="NO" *) (* IOB="TRUE" *) reg [ 32-1:0] fmc_d_ro_ff1;
+ (* SHREG_EXTRACT="NO" *) reg [ 32-1:0] fmc_d_ro_ff2;
+ (* SHREG_EXTRACT="NO" *) reg [ 32-1:0] fmc_d_ro_ff3;
(* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_ne1_ff1;
(* SHREG_EXTRACT="NO" *) reg fmc_ne1_ff2;
+ (* SHREG_EXTRACT="NO" *) reg fmc_ne1_ff3;
(* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_nwe_ff1;
(* SHREG_EXTRACT="NO" *) reg fmc_nwe_ff2;
+ (* SHREG_EXTRACT="NO" *) reg fmc_nwe_ff3;
(* SHREG_EXTRACT="NO" *) (* IOB="FALSE" *) reg fmc_nl_ff1;
(* SHREG_EXTRACT="NO" *) reg fmc_nl_ff2;
+ (* SHREG_EXTRACT="NO" *) reg fmc_nl_ff3;
+
+ wire [NUM_ADDR_BITS-1:0] fmc_a_sync_sys = fmc_a_ff3;
+ wire [ 32-1:0] fmc_d_ro_sync_sys = fmc_d_ro_ff3;
+ wire fmc_ne1_sync_sys = fmc_ne1_ff3;
+ wire fmc_nwe_sync_sys = fmc_nwe_ff3;
+ wire fmc_nl_sync_sys = fmc_nl_ff3;
+
+ always @(posedge io_clk) begin
+ //
+ {fmc_a_ff2, fmc_a_ff1} <= {fmc_a_ff1, fmc_a};
+ {fmc_d_ro_ff2, fmc_d_ro_ff1} <= {fmc_d_ro_ff1, fmc_d_ro};
+ {fmc_ne1_ff2, fmc_ne1_ff1} <= {fmc_ne1_ff1, fmc_ne1};
+ {fmc_nwe_ff2, fmc_nwe_ff1} <= {fmc_nwe_ff1, fmc_nwe};
+ {fmc_nl_ff2, fmc_nl_ff1} <= {fmc_nl_ff1, fmc_nl};
+ //
+ end
+
+ always @(posedge sys_clk)
+ //
+ if (cdc_same_edges) begin
+ fmc_a_ff3 <= fmc_a_ff2;
+ fmc_d_ro_ff3 <= fmc_d_ro_ff2;
+ fmc_ne1_ff3 <= fmc_ne1_ff2;
+ fmc_nwe_ff3 <= fmc_nwe_ff2;
+ fmc_nl_ff3 <= fmc_nl_ff2;
+ end
+
+
+ //
+ // FSM
+ //
+ localparam FSM_STATE_IDLE = 4'd00;
- wire [23: 0] fmc_a_sync = fmc_a_ff2;
- wire [31: 0] fmc_d_ro_sync = fmc_d_ro_ff2;
- wire fmc_ne1_sync = fmc_ne1_ff2;
- wire fmc_nwe_sync = fmc_nwe_ff2;
- wire fmc_nl_sync = fmc_nl_ff2;
-
- always @(posedge sys_clk) begin
- fmc_a_ff1 <= fmc_a;
- fmc_a_ff2 <= fmc_a_ff1;
-
- fmc_d_ro_ff1 <= fmc_d_ro;
- fmc_d_ro_ff2 <= fmc_d_ro_ff1;
-
- fmc_ne1_ff1 <= fmc_ne1;
- fmc_ne1_ff2 <= fmc_ne1_ff1;
-
- fmc_nwe_ff1 <= fmc_nwe;
- fmc_nwe_ff2 <= fmc_nwe_ff1;
-
- fmc_nl_ff1 <= fmc_nl;
- fmc_nl_ff2 <= fmc_nl_ff1;
- end
-
-
- //
- // FSM
- //
- localparam FSM_STATE_IDLE = 4'd0;
-
- localparam FSM_STATE_WRITE_START = 4'd1;
- localparam FSM_STATE_WRITE_LATENCY_1 = 4'd2;
- localparam FSM_STATE_WRITE_LATENCY_2 = 4'd3;
- localparam FSM_STATE_WRITE_LATENCY_3 = 4'd4;
- localparam FSM_STATE_WRITE_LATENCY_4 = 4'd5;
- localparam FSM_STATE_WRITE_STOP = 4'd6;
-
- localparam FSM_STATE_READ_START = 4'd7;
- localparam FSM_STATE_READ_LATENCY_1 = 4'd8;
- localparam FSM_STATE_READ_STOP = 4'd9;
-
- reg [ 3: 0] fsm_state = FSM_STATE_IDLE;
- reg [ 3: 0] fsm_state_next;
-
- always @(posedge sys_clk)
- //
- fsm_state <= fsm_state_next;
-
-
- //
- // FSM Transition Logic
- //
- always @*
- //
- if (fmc_ne1_sync) fsm_state_next = FSM_STATE_IDLE;
- else case (fsm_state)
- FSM_STATE_IDLE: fsm_state_next = !fmc_nwe_sync ? FSM_STATE_WRITE_START : FSM_STATE_READ_START;
- FSM_STATE_WRITE_START: fsm_state_next = FSM_STATE_WRITE_LATENCY_1;
- FSM_STATE_WRITE_LATENCY_1: fsm_state_next = FSM_STATE_WRITE_LATENCY_2;
- FSM_STATE_WRITE_LATENCY_2: fsm_state_next = FSM_STATE_WRITE_LATENCY_3;
- FSM_STATE_WRITE_LATENCY_3: fsm_state_next = FSM_STATE_WRITE_LATENCY_4;
- FSM_STATE_WRITE_LATENCY_4,
- FSM_STATE_WRITE_STOP: fsm_state_next = FSM_STATE_WRITE_STOP;
- FSM_STATE_READ_START: fsm_state_next = FSM_STATE_READ_LATENCY_1;
- FSM_STATE_READ_LATENCY_1,
- FSM_STATE_READ_STOP: fsm_state_next = FSM_STATE_READ_STOP;
- default: fsm_state_next = FSM_STATE_IDLE;
- endcase
+ localparam FSM_STATE_WRITE_START = 4'd01;
+ localparam FSM_STATE_WRITE_LATENCY_1 = 4'd02;
+ localparam FSM_STATE_WRITE_LATENCY_2 = 4'd03;
+ localparam FSM_STATE_WRITE_LATENCY_3 = 4'd04;
+ localparam FSM_STATE_WRITE_LATENCY_4 = 4'd05;
+ localparam FSM_STATE_WRITE_LATENCY_5 = 4'd06;
+ localparam FSM_STATE_WRITE_LATENCY_6 = 4'd07;
+ localparam FSM_STATE_WRITE_STOP = 4'd08;
+ localparam FSM_STATE_READ_START = 4'd09;
+ localparam FSM_STATE_READ_LATENCY_1 = 4'd10;
+ localparam FSM_STATE_READ_LATENCY_2 = 4'd11;
+ localparam FSM_STATE_READ_LATENCY_3 = 4'd12;
+ localparam FSM_STATE_READ_STOP = 4'd13;
+
+ reg [ 3: 0] fsm_state = FSM_STATE_IDLE;
+ reg [ 3: 0] fsm_state_next;
+
+ always @(posedge sys_clk)
+ //
+ fsm_state <= fsm_state_next;
+
+
+ //
+ // FSM Transition Logic
+ //
+ always @*
+ //
+ if (!cdc_same_edges) fsm_state_next = fsm_state;
+ else begin
+ //
+ if (fmc_ne1_sync_sys) fsm_state_next = FSM_STATE_IDLE;
+ else case (fsm_state)
+ FSM_STATE_IDLE: fsm_state_next = !fmc_nwe_sync_sys ? FSM_STATE_WRITE_START : FSM_STATE_READ_START;
+ FSM_STATE_WRITE_START: fsm_state_next = FSM_STATE_WRITE_LATENCY_1;
+ FSM_STATE_WRITE_LATENCY_1: fsm_state_next = FSM_STATE_WRITE_LATENCY_2;
+ FSM_STATE_WRITE_LATENCY_2: fsm_state_next = FSM_STATE_WRITE_LATENCY_3;
+ FSM_STATE_WRITE_LATENCY_3: fsm_state_next = FSM_STATE_WRITE_LATENCY_4;
+ FSM_STATE_WRITE_LATENCY_4: fsm_state_next = FSM_STATE_WRITE_LATENCY_5;
+ FSM_STATE_WRITE_LATENCY_5: fsm_state_next = FSM_STATE_WRITE_LATENCY_6;
+ FSM_STATE_WRITE_LATENCY_6,
+ FSM_STATE_WRITE_STOP: fsm_state_next = FSM_STATE_WRITE_STOP;
+ FSM_STATE_READ_START: fsm_state_next = FSM_STATE_READ_LATENCY_1;
+ FSM_STATE_READ_LATENCY_1: fsm_state_next = FSM_STATE_READ_LATENCY_2;
+ FSM_STATE_READ_LATENCY_2: fsm_state_next = FSM_STATE_READ_LATENCY_3;
+ FSM_STATE_READ_LATENCY_3,
+ FSM_STATE_READ_STOP: fsm_state_next = FSM_STATE_READ_STOP;
+ default: fsm_state_next = FSM_STATE_IDLE;
+ endcase
+ //
+ end
+
//
// Output Data Latch
//
+ reg [31:0] sys_data_in_latch_fast;
(* IOB="TRUE" *)
- reg [31:0] sys_data_in_latch;
+ reg [31:0] sys_data_in_latch_slow;
- assign fmc_d_di = sys_data_in_latch;
-
-
- //
- // Address Latch
- //
- always @(posedge sys_clk)
- //
- if (!fmc_ne1_sync && !fmc_nl_sync)
- //
- sys_addr_reg <= fmc_a_sync;
+ assign fmc_d_di = sys_data_in_latch_slow;
//
@@ -223,51 +257,72 @@ module fmc_arbiter
//
+ // Address Latch
+ //
+ always @(posedge sys_clk)
+ //
+ if (!fmc_ne1_sync_sys && !fmc_nl_sync_sys && cdc_same_edges)
+ sys_addr_reg <= fmc_a_sync_sys;
+
+
+ //
// Write Enable Logic
//
- always @(posedge sys_clk)
- //
- case (fsm_state)
- FSM_STATE_WRITE_LATENCY_4: sys_wr_en_reg <= 1'b1;
- default: sys_wr_en_reg <= 1'b0;
- endcase
+ always @(posedge sys_clk)
+ //
+ case (fsm_state)
+ FSM_STATE_WRITE_LATENCY_6: sys_wr_en_reg <= ~cdc_same_edges;
+ default: sys_wr_en_reg <= 1'b0;
+ endcase
+
-
//
// Read Enable Logic
//
- always @(posedge sys_clk)
- //
- case (fsm_state_next)
- FSM_STATE_READ_START: sys_rd_en_reg <= 1'b1;
- default: sys_rd_en_reg <= 1'b0;
- endcase
+ always @(posedge sys_clk)
+ //
+ case (fsm_state_next)
+ FSM_STATE_READ_START: sys_rd_en_reg <= cdc_same_edges;
+ default: sys_rd_en_reg <= 1'b0;
+ endcase
//
- // Output Data Latch
+ // Output Data Latches
//
- always @(posedge sys_clk)
- //
- case (fsm_state)
- FSM_STATE_READ_LATENCY_1: sys_data_in_latch <= sys_data_in;
- endcase
+ always @(posedge sys_clk)
+ //
+ case (fsm_state)
+ FSM_STATE_READ_LATENCY_2:
+ if (cdc_same_edges)
+ sys_data_in_latch_fast <= sys_data_in;
+ endcase
+
+ always @(negedge io_clk)
+ //
+ case (fsm_state)
+ FSM_STATE_READ_LATENCY_3:
+ sys_data_in_latch_slow <= sys_data_in_latch_fast;
+ endcase
+
//
// Input Data Latch
//
- always @(posedge sys_clk)
- //
- case (fsm_state)
- FSM_STATE_WRITE_LATENCY_4: sys_data_out_reg <= fmc_d_ro_sync;
- endcase
+ always @(posedge sys_clk)
+ //
+ case (fsm_state)
+ FSM_STATE_WRITE_LATENCY_6:
+ if (!cdc_same_edges)
+ sys_data_out_reg <= fmc_d_ro_sync_sys;
+ endcase
//
// Unused NWAIT tieoff
//
- assign fmc_nwait = 1'b0;
+ assign fmc_nwait = 1'b0;
endmodule