1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00

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!
This commit is contained in:
Andreas Olofsson 2015-10-07 11:49:46 -04:00
parent 8bba86d6cd
commit d7d959da45
6 changed files with 76 additions and 53 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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
//###############################

View File

@ -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),

View File

@ -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