From d7d959da4543487dd0cd740a5f5c17ad5c053599 Mon Sep 17 00:00:00 2001 From: Andreas Olofsson Date: Wed, 7 Oct 2015 11:49:46 -0400 Subject: [PATCH] Adding software programmable IDELAY - This is DEFINITELY the way to do things, sweep the delays and find the right value. No f'ing way to get these stupid FPGAs to work otherwise with the ridiculuosly over margined PVT nubmers they are running through the STAs. I understand they want to make the design bullet proof, but as a result designers are wasting countless hours overoptimzinng designs and being clever. So much performance is left on the table for expert users. - Lesson: I/O design should be "self syncrhonizing". Only contraints in the design should be create_clk - Made RX clock async, too tricky to guarantee that there clock is there. No way to do this if the clock sources are actually independent for RX/TX! --- elink/hdl/ecfg_if.v | 2 +- elink/hdl/elink_regmap.v | 6 ++-- elink/hdl/ereset.v | 9 ++++-- elink/hdl/erx_cfg.v | 43 ++++++++++++++++++++++------ elink/hdl/erx_core.v | 9 ++++-- elink/hdl/erx_io.v | 60 +++++++++++++++++----------------------- 6 files changed, 76 insertions(+), 53 deletions(-) diff --git a/elink/hdl/ecfg_if.v b/elink/hdl/ecfg_if.v index 1ac6b9b..acd682d 100644 --- a/elink/hdl/ecfg_if.v +++ b/elink/hdl/ecfg_if.v @@ -137,7 +137,7 @@ module ecfg_if (/*AUTOARG*/ //Access out packet assign access_forward = (mi_rx_en | mi_rd); - always @ (posedge clk) + always @ (posedge clk) if(reset) access_out <= 1'b0; else if(~wait_in) diff --git a/elink/hdl/elink_regmap.v b/elink/hdl/elink_regmap.v index aefc960..c5d49cf 100644 --- a/elink/hdl/elink_regmap.v +++ b/elink/hdl/elink_regmap.v @@ -4,9 +4,9 @@ //MEMORY MAP //[31:20] = LINKID -//[19:16] = GROUP SELECT +//[19:16] = GROUP SELECT //[15] = MMU SELECT (for RX/TX) -//[14:11] = USED BY MMU ONLY +//[14:11] = USED BY MMU ONLY //[10:8] = register group //[7:2] = REGISTER ADDRESS (0..63) //[1:0] = IGNORED (no byte access) @@ -32,6 +32,8 @@ `define ERX_OFFSET 6'd3 //F030C-memory base for remap `define E_MAILBOXLO 6'd4 //F0314-reserved-->move? `define E_MAILBOXHI 6'd5 //F0318-reserved +`define ERX_IDELAY0 6'd6 //F0320-tap delay for d[3:0] +`define ERX_IDELAY1 6'd7 //F0324-tap delays for {frame,d[7:4]} //DMA (same numbering as in Epiphany, limit to 4 channels) `define DMACFG 5'd0 //F0500/F0520 diff --git a/elink/hdl/ereset.v b/elink/hdl/ereset.v index eeb7160..9f6c840 100644 --- a/elink/hdl/ereset.v +++ b/elink/hdl/ereset.v @@ -24,12 +24,15 @@ module ereset (/*AUTOARG*/ //erx reset synchronizer - synchronizer sync_erx (.out (erx_resetb), + /* + + synchronizer sync_erx (.out (erx_resetb), .in (1'b1), .clk (rx_lclk_div4), .reset (reset) ); - + */ + //etx reset synchronizer synchronizer sync_etx (.out (etx_resetb), .in (1'b1), @@ -45,8 +48,8 @@ module ereset (/*AUTOARG*/ ); assign etx_reset =~etx_resetb; - assign erx_reset =~erx_resetb; assign sys_reset =~sys_resetb; + assign erx_reset = reset; //async reset! can't guarantee rx clock endmodule // ereset // Local Variables: diff --git a/elink/hdl/erx_cfg.v b/elink/hdl/erx_cfg.v index 2cb87b8..3b37e42 100644 --- a/elink/hdl/erx_cfg.v +++ b/elink/hdl/erx_cfg.v @@ -9,7 +9,7 @@ module erx_cfg (/*AUTOARG*/ // Outputs mi_dout, rx_enable, mmu_enable, remap_mode, remap_base, - remap_pattern, remap_sel, timer_cfg, + remap_pattern, remap_sel, timer_cfg, idelay_value, load_taps, // Inputs reset, clk, mi_en, mi_we, mi_addr, mi_din, gpio_datain, rx_status ); @@ -25,6 +25,7 @@ module erx_cfg (/*AUTOARG*/ /******************************/ input reset; // ecfg registers reset only by "hard reset" input clk; + /*****************************/ /*SIMPLE MEMORY INTERFACE */ /*****************************/ @@ -47,6 +48,8 @@ module erx_cfg (/*AUTOARG*/ output [11:0] remap_pattern; // patter for static remap (static) output [11:0] remap_sel; // selects for static remap (static) output [1:0] timer_cfg; // timeout config (00=off) (static) + output [39:0] idelay_value; // tap values for erx idelay + output load_taps; // loads the idelay_value into IDELAY prim /*------------------------CODE BODY---------------------------------------*/ @@ -54,15 +57,19 @@ module erx_cfg (/*AUTOARG*/ reg [31:0] ecfg_rx_reg; reg [31:0] ecfg_offset_reg; reg [8:0] ecfg_gpio_reg; - reg [2:0] ecfg_rx_status_reg; + reg [2:0] ecfg_rx_status_reg; + reg [63:0] ecfg_idelay_reg; + reg load_taps; reg [31:0] mi_dout; //wires wire ecfg_read; wire ecfg_write; wire ecfg_rx_write; - wire ecfg_base_write; + wire ecfg_offset_write; wire ecfg_remap_write; + wire ecfg_idelay0_write; + wire ecfg_idelay1_write; /*****************************/ /*ADDRESS DECODE LOGIC */ @@ -74,12 +81,14 @@ module erx_cfg (/*AUTOARG*/ //Config write enables assign ecfg_rx_write = ecfg_write & (mi_addr[RFAW+1:2]==`ERX_CFG); - assign ecfg_base_write = ecfg_write & (mi_addr[RFAW+1:2]==`ERX_OFFSET); - + assign ecfg_offset_write = ecfg_write & (mi_addr[RFAW+1:2]==`ERX_OFFSET); + assign ecfg_idelay0_write = ecfg_write & (mi_addr[RFAW+1:2]==`ERX_IDELAY0); + assign ecfg_idelay1_write = ecfg_write & (mi_addr[RFAW+1:2]==`ERX_IDELAY1); + //########################### //# RXCFG //########################### - always @ (posedge clk) + always @ (posedge clk or posedge reset) if(reset) ecfg_rx_reg[31:0] <= 'b0; else if (ecfg_rx_write) @@ -101,7 +110,7 @@ module erx_cfg (/*AUTOARG*/ //###########################1 //# DEBUG //########################### - always @ (posedge clk) + always @ (posedge clk or posedge reset) if(reset) ecfg_rx_status_reg[2:0] <= 'b0; else @@ -111,11 +120,27 @@ module erx_cfg (/*AUTOARG*/ //# DYNAMIC REMAP BASE //########################### always @ (posedge clk) - if (ecfg_base_write) + if (ecfg_offset_write) ecfg_offset_reg[31:0] <= mi_din[31:0]; assign remap_base[31:0] = ecfg_offset_reg[31:0]; - + + //###########################1 + //# IDELAY TAP VALUES + //########################### + always @ (posedge clk or posedge reset) + if(reset) + ecfg_idelay_reg[63:0] <= 'b0; + else if (ecfg_idelay0_write) + ecfg_idelay_reg[31:0] <= mi_din[31:0]; + else if(ecfg_idelay1_write) + ecfg_idelay_reg[63:32] <= mi_din[31:0]; + + assign idelay_value[39:0] = {ecfg_idelay_reg[41:32],ecfg_idelay_reg[29:0]}; + + always @ (posedge clk) + load_taps <= ecfg_idelay1_write; + //############################### //# DATA READBACK MUX //############################### diff --git a/elink/hdl/erx_core.v b/elink/hdl/erx_core.v index 9d31ea1..52bff0a 100644 --- a/elink/hdl/erx_core.v +++ b/elink/hdl/erx_core.v @@ -1,8 +1,8 @@ module erx_core (/*AUTOARG*/ // Outputs - rx_rd_wait, rx_wr_wait, rxrd_access, rxrd_packet, rxrr_access, - rxrr_packet, rxwr_access, rxwr_packet, erx_cfg_wait, mailbox_full, - mailbox_not_empty, + rx_rd_wait, rx_wr_wait, idelay_value, load_taps, rxrd_access, + rxrd_packet, rxrr_access, rxrr_packet, rxwr_access, rxwr_packet, + erx_cfg_wait, mailbox_full, mailbox_not_empty, // Inputs reset, clk, rx_packet, rx_access, rx_burst, rxrd_wait, rxrr_wait, rxwr_wait, erx_cfg_access, erx_cfg_packet @@ -25,6 +25,8 @@ module erx_core (/*AUTOARG*/ input rx_burst; output rx_rd_wait; output rx_wr_wait; + output [39:0] idelay_value; + output load_taps; //FIFO Access output rxrd_access; @@ -289,6 +291,7 @@ module erx_core (/*AUTOARG*/ .remap_base (remap_base[31:0]), .remap_pattern (remap_pattern[11:0]), .remap_sel (remap_sel[11:0]), + .idelay_value (idelay_value[39:0]), // Inputs .reset (reset), .clk (clk), diff --git a/elink/hdl/erx_io.v b/elink/hdl/erx_io.v index 0f58135..cb0f286 100644 --- a/elink/hdl/erx_io.v +++ b/elink/hdl/erx_io.v @@ -8,31 +8,15 @@ module erx_io (/*AUTOARG*/ rx_lclk_pll, rxo_wr_wait_p, rxo_wr_wait_n, rxo_rd_wait_p, rxo_rd_wait_n, rx_access, rx_burst, rx_packet, // Inputs - reset, rx_lclk, rx_lclk_div4, rxi_lclk_p, rxi_lclk_n, rxi_frame_p, - rxi_frame_n, rxi_data_p, rxi_data_n, rx_wr_wait, rx_rd_wait + reset, rx_lclk, rx_lclk_div4, idelay_value, load_taps, rxi_lclk_p, + rxi_lclk_n, rxi_frame_p, rxi_frame_n, rxi_data_p, rxi_data_n, + rx_wr_wait, rx_rd_wait ); parameter IOSTD_ELINK = "LVDS_25"; parameter PW = 104; parameter ETYPE = 1;//0=parallella //1=ephycard - // Can we do this in a better way? - //parameter [3:0] RX_TAP_DELAY [8:0]=; - //parameter RX_TAP_DELAY = 1; - - parameter [5*10:0] RX_TAP_DELAY ={5'd0, //clk - 5'd12, //frame - 5'd12, //d7 - 5'd12, //d6 - 5'd12, //d5 - 5'd12, //d4 - 5'd12, //d3 - 5'd12, //d2 - 5'd12, //d1 - 5'd12 //d0 - }; - - //######################### //# reset, clocks //######################### @@ -40,7 +24,13 @@ module erx_io (/*AUTOARG*/ input rx_lclk; // fast I/O clock input rx_lclk_div4; // slow clock output rx_lclk_pll; // clock output for pll - + + //######################### + //# idelays + //######################### + input [39:0] idelay_value; + input load_taps; + //########################## //# elink pins //########################## @@ -292,27 +282,27 @@ module erx_io (/*AUTOARG*/ IDELAYE2 #(.CINVCTRL_SEL("FALSE"), .DELAY_SRC("IDATAIN"), .HIGH_PERFORMANCE_MODE("FALSE"), - .IDELAY_TYPE("FIXED"), - .IDELAY_VALUE(RX_TAP_DELAY[(j+1)*5-1:j*5]), + .IDELAY_TYPE("VAR_LOAD"), + .IDELAY_VALUE(5'b0), .PIPE_SEL("FALSE"), .REFCLK_FREQUENCY(200.0), .SIGNAL_PATTERN("DATA")) - idelay_inst (.CNTVALUEOUT(), - .DATAOUT(rxi_delay_out[j]), - .C(1'b0), - .CE(1'b0), - .CINVCTRL(1'b0), - .CNTVALUEIN(5'b0), - .DATAIN(1'b0), - .IDATAIN(rxi_delay_in[j]), - .INC(1'b0), - .LD(1'b0), - .LDPIPEEN(1'b0), - .REGRST(1'b0) + + idelay_inst (.CNTVALUEOUT(), // monitoring value + .DATAOUT(rxi_delay_out[j]), // delayed data + .C(rx_lclk_div4), // variable tap delay clock + .CE(1'b0), // inc/dec tap value + .CINVCTRL(1'b0), // inverts clock polarity + .CNTVALUEIN(idelay_value[(j+1)*5-1:j*5]), //variable tap + .DATAIN(1'b0), // data from FPGA + .IDATAIN(rxi_delay_in[j]), // data from ibuf + .INC(1'b0), // increment tap + .LD(load_taps), // load new + .LDPIPEEN(1'b0), // only for pipeline mode + .REGRST(1'b0) // only for pipeline mode ); end // block: gen_idelay endgenerate - //############################# //# IDDR SAMPLERS