2014-12-14 17:18:53 -05:00
|
|
|
module etx_io (/*AUTOARG*/
|
|
|
|
// Outputs
|
2015-04-13 23:35:21 -04:00
|
|
|
txo_lclk_p, txo_lclk_n, txo_frame_p, txo_frame_n, txo_data_p,
|
2015-11-15 01:35:46 -05:00
|
|
|
txo_data_n, tx_wr_wait, tx_rd_wait,
|
2014-12-14 17:18:53 -05:00
|
|
|
// Inputs
|
2015-11-24 01:12:07 -05:00
|
|
|
tx_lclk_io, tx_lclk_div4, tx_lclk90, txi_wr_wait_p, txi_wr_wait_n,
|
|
|
|
txi_rd_wait_p, txi_rd_wait_n, tx_data_slow, tx_frame_slow
|
2014-12-14 17:18:53 -05:00
|
|
|
);
|
2015-10-07 19:12:01 -04:00
|
|
|
|
2014-12-14 17:18:53 -05:00
|
|
|
parameter IOSTD_ELINK = "LVDS_25";
|
2015-09-14 22:03:22 -04:00
|
|
|
parameter PW = 104;
|
2015-11-06 22:41:43 -05:00
|
|
|
parameter ETYPE = 0; // 0 = parallella
|
|
|
|
// 1 = ephycard
|
2015-03-25 19:25:12 -04:00
|
|
|
//###########
|
2015-05-13 23:24:54 -04:00
|
|
|
//# reset, clocks
|
|
|
|
//##########
|
2015-11-03 14:15:09 -05:00
|
|
|
input tx_lclk_io; //fast ODDR
|
2015-11-15 01:35:46 -05:00
|
|
|
input tx_lclk_div4; //slow clock
|
2015-10-07 19:12:01 -04:00
|
|
|
input tx_lclk90; //fast 90deg shifted lclk
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
//###########
|
|
|
|
//# eLink pins
|
|
|
|
//###########
|
2015-05-13 23:24:54 -04:00
|
|
|
output txo_lclk_p, txo_lclk_n; // tx clock output
|
|
|
|
output txo_frame_p, txo_frame_n; // tx frame signal
|
|
|
|
output [7:0] txo_data_p, txo_data_n; // tx data (dual data rate)
|
|
|
|
input txi_wr_wait_p,txi_wr_wait_n; // tx write pushback
|
|
|
|
input txi_rd_wait_p, txi_rd_wait_n; // tx read pushback
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
//#############
|
2015-03-25 19:25:12 -04:00
|
|
|
//# Fabric interface
|
2014-12-14 17:18:53 -05:00
|
|
|
//#############
|
2015-11-24 01:12:07 -05:00
|
|
|
input [63:0] tx_data_slow; //data for burst or transaction
|
|
|
|
input [3:0] tx_frame_slow; //framing signal
|
2015-05-13 23:24:54 -04:00
|
|
|
output tx_wr_wait;
|
|
|
|
output tx_rd_wait;
|
2014-12-14 17:18:53 -05:00
|
|
|
|
2015-03-25 19:25:12 -04:00
|
|
|
//############
|
|
|
|
//# REGS
|
|
|
|
//############
|
2015-11-24 01:12:07 -05:00
|
|
|
reg [63:0] tx_data;
|
|
|
|
reg [3:0] tx_frame;
|
|
|
|
wire [15:0] tx_data16;
|
|
|
|
wire tx_frame16;
|
|
|
|
reg tx_wr_wait_sync;
|
|
|
|
reg tx_rd_wait_sync;
|
2015-11-25 21:55:37 -05:00
|
|
|
reg tx_wr_wait_reg;
|
|
|
|
reg tx_rd_wait_reg;
|
|
|
|
reg tx_wr_wait_reg2;
|
|
|
|
reg tx_rd_wait_reg2;
|
2014-12-14 17:18:53 -05:00
|
|
|
//############
|
|
|
|
//# WIRES
|
|
|
|
//############
|
2015-11-24 01:12:07 -05:00
|
|
|
wire [15:0] tx_data_mux;
|
|
|
|
wire txo_frame_ddr;
|
|
|
|
wire txo_lclk90;
|
2015-11-13 16:31:59 -05:00
|
|
|
wire tx_wr_wait_async;
|
|
|
|
wire tx_rd_wait_async;
|
2015-11-24 01:12:07 -05:00
|
|
|
wire [7:0] txo_data_ddr;
|
2016-01-13 15:32:46 -05:00
|
|
|
wire invert_pins;
|
2015-11-15 01:35:46 -05:00
|
|
|
|
2016-01-13 15:32:46 -05:00
|
|
|
//#########################################
|
|
|
|
//# Pins inverted for 64-core board
|
|
|
|
//#########################################
|
|
|
|
`ifdef TARGET_E64
|
|
|
|
assign invert_pins=1'b1;
|
|
|
|
`else
|
|
|
|
assign invert_pins=1'b0;
|
|
|
|
`endif
|
2015-11-15 01:35:46 -05:00
|
|
|
//#########################################
|
2015-11-24 01:12:07 -05:00
|
|
|
//# Synchronizatsion to fast domain
|
|
|
|
//#########################################
|
2015-11-15 01:35:46 -05:00
|
|
|
|
|
|
|
//Find the aligned edge
|
2015-11-30 13:45:49 -05:00
|
|
|
oh_edgealign edgealign0 (.firstedge (firstedge),
|
|
|
|
.fastclk (tx_lclk_io),
|
|
|
|
.slowclk (tx_lclk_div4)
|
|
|
|
);
|
2015-11-24 01:12:07 -05:00
|
|
|
|
|
|
|
//Data shift registers
|
2015-11-13 16:31:59 -05:00
|
|
|
always @ (posedge tx_lclk_io)
|
2015-11-24 01:12:07 -05:00
|
|
|
if(firstedge) //"load"
|
2015-11-17 09:46:22 -05:00
|
|
|
begin
|
2015-11-24 01:12:07 -05:00
|
|
|
tx_data[63:0] <= tx_data_slow[63:0]; //changes every 4 cycles
|
|
|
|
tx_frame[3:0] <= tx_frame_slow[3:0];
|
|
|
|
end
|
|
|
|
else //"shift"
|
|
|
|
begin
|
|
|
|
tx_data[63:0] <= {16'b0,tx_data[63:16]};
|
|
|
|
tx_frame[3:0] <= {tx_frame[2:0],1'b0};
|
2015-11-17 09:46:22 -05:00
|
|
|
end
|
2015-11-13 16:31:59 -05:00
|
|
|
|
2015-11-24 01:12:07 -05:00
|
|
|
assign tx_data16[15:0] = tx_data[15:0];
|
|
|
|
assign tx_frame16 = tx_frame[3];
|
2015-11-17 16:51:19 -05:00
|
|
|
|
2015-11-15 01:35:46 -05:00
|
|
|
//##############################################
|
|
|
|
//# Wait signal synchronization
|
2015-11-24 01:12:07 -05:00
|
|
|
//##############################################
|
2015-11-25 21:55:37 -05:00
|
|
|
always @ (negedge tx_lclk_io)
|
2015-11-16 00:42:34 -05:00
|
|
|
begin
|
2016-01-13 15:32:46 -05:00
|
|
|
tx_wr_wait_sync <= tx_wr_wait_async ^ invert_pins;
|
|
|
|
tx_rd_wait_sync <= tx_rd_wait_async ^ invert_pins;
|
2015-11-16 00:42:34 -05:00
|
|
|
end
|
2015-11-03 14:15:09 -05:00
|
|
|
|
2015-11-25 21:55:37 -05:00
|
|
|
//Looks like legacy elink puts out short wait pulses.
|
|
|
|
//Let's make sure they don't sneak through
|
|
|
|
|
|
|
|
always @ (posedge tx_lclk_div4)
|
2015-11-16 00:42:34 -05:00
|
|
|
begin
|
2015-11-25 21:55:37 -05:00
|
|
|
tx_wr_wait_reg <= tx_wr_wait_sync;
|
|
|
|
tx_wr_wait_reg2 <= tx_wr_wait_reg;
|
|
|
|
tx_rd_wait_reg <= tx_rd_wait_sync;
|
|
|
|
tx_rd_wait_reg2 <= tx_rd_wait_reg;
|
2015-11-16 00:42:34 -05:00
|
|
|
end
|
2015-11-25 21:55:37 -05:00
|
|
|
assign tx_wr_wait = tx_wr_wait_reg | tx_wr_wait_reg2;
|
|
|
|
assign tx_rd_wait = tx_rd_wait_reg | tx_rd_wait_reg2;
|
2015-11-24 01:12:07 -05:00
|
|
|
|
|
|
|
//############################################
|
2015-11-15 01:35:46 -05:00
|
|
|
//# IO DRIVER STUFF
|
2015-11-24 01:12:07 -05:00
|
|
|
//############################################
|
2015-05-13 23:24:54 -04:00
|
|
|
|
2015-05-15 15:31:01 -04:00
|
|
|
//DATA
|
|
|
|
genvar i;
|
|
|
|
generate for(i=0; i<8; i=i+1)
|
|
|
|
begin : gen_oddr
|
|
|
|
ODDR #(.DDR_CLK_EDGE ("SAME_EDGE"))
|
|
|
|
oddr_data (
|
2015-11-24 01:12:07 -05:00
|
|
|
.Q (txo_data_ddr[i]),
|
2015-11-08 23:28:39 -05:00
|
|
|
.C (tx_lclk_io),
|
2015-05-15 15:31:01 -04:00
|
|
|
.CE (1'b1),
|
2016-01-13 15:32:46 -05:00
|
|
|
.D1 (tx_data16[i+8] ^ invert_pins),
|
|
|
|
.D2 (tx_data16[i] ^ invert_pins),
|
2015-05-15 15:31:01 -04:00
|
|
|
.R (1'b0),
|
|
|
|
.S (1'b0)
|
|
|
|
);
|
|
|
|
end
|
|
|
|
endgenerate
|
|
|
|
|
|
|
|
//FRAME
|
2015-11-03 14:15:09 -05:00
|
|
|
ODDR #(.DDR_CLK_EDGE ("SAME_EDGE"))
|
2015-05-15 15:31:01 -04:00
|
|
|
oddr_frame (
|
2015-11-24 01:12:07 -05:00
|
|
|
.Q (txo_frame_ddr),
|
2015-11-08 23:28:39 -05:00
|
|
|
.C (tx_lclk_io),
|
2015-05-15 15:31:01 -04:00
|
|
|
.CE (1'b1),
|
2016-01-13 15:32:46 -05:00
|
|
|
.D1 (tx_frame16 ^ invert_pins),
|
|
|
|
.D2 (tx_frame16 ^ invert_pins),
|
2015-10-08 10:34:59 -04:00
|
|
|
.R (1'b0), //reset
|
2015-05-15 15:31:01 -04:00
|
|
|
.S (1'b0)
|
|
|
|
);
|
|
|
|
|
|
|
|
//LCLK
|
|
|
|
ODDR #(.DDR_CLK_EDGE ("SAME_EDGE"))
|
|
|
|
oddr_lclk (
|
|
|
|
.Q (txo_lclk90),
|
2015-11-10 09:19:01 -05:00
|
|
|
.C (tx_lclk90),
|
2015-05-15 15:31:01 -04:00
|
|
|
.CE (1'b1),
|
2016-01-13 15:32:46 -05:00
|
|
|
.D1 (1'b1 ^ invert_pins),
|
|
|
|
.D2 (1'b0 ^ invert_pins),
|
2015-10-08 10:34:59 -04:00
|
|
|
.R (1'b0),//should be no reason to reset clock, static input
|
2015-05-15 15:31:01 -04:00
|
|
|
.S (1'b0)
|
|
|
|
);
|
2015-11-24 01:12:07 -05:00
|
|
|
|
2015-11-15 01:35:46 -05:00
|
|
|
//Buffer drivers
|
2015-05-13 23:24:54 -04:00
|
|
|
OBUFDS obufds_data[7:0] (
|
|
|
|
.O (txo_data_p[7:0]),
|
|
|
|
.OB (txo_data_n[7:0]),
|
2015-11-24 01:12:07 -05:00
|
|
|
.I (txo_data_ddr[7:0])
|
2015-05-13 23:24:54 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
OBUFDS obufds_frame ( .O (txo_frame_p),
|
|
|
|
.OB (txo_frame_n),
|
2015-11-24 01:12:07 -05:00
|
|
|
.I (txo_frame_ddr)
|
2015-05-13 23:24:54 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
OBUFDS obufds_lclk ( .O (txo_lclk_p),
|
|
|
|
.OB (txo_lclk_n),
|
2015-05-15 15:31:01 -04:00
|
|
|
.I (txo_lclk90)
|
2015-05-13 23:24:54 -04:00
|
|
|
);
|
2015-11-15 01:35:46 -05:00
|
|
|
//Wait inputs
|
2015-09-14 22:03:22 -04:00
|
|
|
generate
|
|
|
|
if(ETYPE==1)
|
|
|
|
begin
|
2015-11-13 16:31:59 -05:00
|
|
|
assign tx_wr_wait_async = txi_wr_wait_p;
|
2015-09-14 22:03:22 -04:00
|
|
|
end
|
|
|
|
else if (ETYPE==0)
|
|
|
|
begin
|
|
|
|
IBUFDS
|
|
|
|
#(.DIFF_TERM ("TRUE"), // Differential termination
|
|
|
|
.IOSTANDARD (IOSTD_ELINK))
|
|
|
|
ibufds_wrwait
|
|
|
|
(.I (txi_wr_wait_p),
|
|
|
|
.IB (txi_wr_wait_n),
|
2015-11-13 16:31:59 -05:00
|
|
|
.O (tx_wr_wait_async));
|
2015-09-14 22:03:22 -04:00
|
|
|
end
|
|
|
|
endgenerate
|
2015-11-08 23:28:39 -05:00
|
|
|
|
2015-04-13 23:35:21 -04:00
|
|
|
//TODO: Come up with cleaner defines for this
|
|
|
|
`ifdef TODO
|
|
|
|
IBUFDS
|
|
|
|
#(.DIFF_TERM ("TRUE"), // Differential termination
|
|
|
|
.IOSTANDARD (IOSTD_ELINK))
|
2015-09-14 22:03:22 -04:00
|
|
|
ibufds_rdwait
|
2015-04-13 23:35:21 -04:00
|
|
|
(.I (txi_rd_wait_p),
|
|
|
|
.IB (txi_rd_wait_n),
|
2015-11-13 16:31:59 -05:00
|
|
|
.O (tx_rd_wait_async));
|
2015-04-13 23:35:21 -04:00
|
|
|
`else
|
2015-03-25 19:25:12 -04:00
|
|
|
//On Parallella this signal comes in single-ended
|
2015-11-13 16:31:59 -05:00
|
|
|
assign tx_rd_wait_async = txi_rd_wait_p;
|
2015-04-13 23:35:21 -04:00
|
|
|
`endif
|
2015-11-13 16:31:59 -05:00
|
|
|
|
2015-03-25 19:25:12 -04:00
|
|
|
endmodule // etx_io
|
2015-05-13 23:24:54 -04:00
|
|
|
// Local Variables:
|
2015-11-15 01:35:46 -05:00
|
|
|
// verilog-library-directories:("." "../../emesh/hdl" "../../common/hdl")
|
2015-05-13 23:24:54 -04:00
|
|
|
// End:
|
2014-12-14 17:18:53 -05:00
|
|
|
|