2014-12-14 17:18:53 -05:00
|
|
|
module erx_io (/*AUTOARG*/
|
|
|
|
// Outputs
|
2015-05-13 23:26:41 -04:00
|
|
|
rx_clk_pll, rxo_wr_wait_p, rxo_wr_wait_n, rxo_rd_wait_p,
|
|
|
|
rxo_rd_wait_n, rx_access, rx_burst, rx_packet,
|
2014-12-14 17:18:53 -05:00
|
|
|
// Inputs
|
2015-05-13 23:26:41 -04:00
|
|
|
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
|
2014-12-14 17:18:53 -05:00
|
|
|
);
|
|
|
|
|
2015-04-23 18:01:19 -04:00
|
|
|
parameter IOSTANDARD = "LVDS_25";
|
2015-05-13 23:26:41 -04:00
|
|
|
parameter PW = 104;
|
2015-04-08 13:20:25 -04:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
//#########################
|
|
|
|
//# reset, clocks
|
|
|
|
//#########################
|
|
|
|
input reset; // reset
|
|
|
|
input rx_lclk; // fast I/O clock
|
|
|
|
input rx_lclk_div4; // slow clock
|
|
|
|
output rx_clk_pll; // clock output for pll
|
|
|
|
|
|
|
|
//##########################
|
|
|
|
//# elink pins
|
|
|
|
//##########################
|
|
|
|
input rxi_lclk_p, rxi_lclk_n; // rx clock input
|
|
|
|
input rxi_frame_p, rxi_frame_n; // rx frame signal
|
|
|
|
input [7:0] rxi_data_p, rxi_data_n; // rx data
|
|
|
|
output rxo_wr_wait_p,rxo_wr_wait_n; // rx write pushback output
|
|
|
|
output rxo_rd_wait_p,rxo_rd_wait_n; // rx read pushback output
|
2015-04-13 23:35:21 -04:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
//##########################
|
|
|
|
//# erx logic interface
|
|
|
|
//##########################
|
|
|
|
output rx_access;
|
|
|
|
output rx_burst;
|
|
|
|
output [PW-1:0] rx_packet;
|
|
|
|
input rx_wr_wait;
|
|
|
|
input rx_rd_wait;
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
//############
|
|
|
|
//# WIRES
|
|
|
|
//############
|
2015-05-13 23:26:41 -04:00
|
|
|
wire [7:0] rxi_data; // High-speed serial data
|
|
|
|
wire rxi_frame; // serial frame
|
|
|
|
wire access_wide;
|
|
|
|
reg valid_packet;
|
|
|
|
wire [15:0] data_in;
|
|
|
|
|
|
|
|
//############
|
|
|
|
//# REGS
|
|
|
|
//############
|
|
|
|
reg [7:0] data_even_reg;
|
|
|
|
reg [7:0] data_odd_reg;
|
|
|
|
reg rx_frame;
|
|
|
|
reg rx_frame_old;
|
|
|
|
reg [111:0] rx_sample;
|
|
|
|
reg [6:0] rx_pointer; //7 cycles
|
|
|
|
reg access;
|
|
|
|
reg burst;
|
|
|
|
reg [PW-1:0] rx_packet_lclk;
|
|
|
|
reg rx_access;
|
|
|
|
reg [PW-1:0] rx_packet;
|
|
|
|
reg rx_burst;
|
|
|
|
|
|
|
|
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
//################################
|
|
|
|
//# Input Buffers Instantiation
|
|
|
|
//################################
|
2015-05-13 23:26:41 -04:00
|
|
|
|
2014-12-14 17:18:53 -05:00
|
|
|
IBUFDS
|
2015-04-23 18:01:19 -04:00
|
|
|
#(.DIFF_TERM ("TRUE"),
|
|
|
|
.IOSTANDARD (IOSTANDARD))
|
2015-05-13 23:26:41 -04:00
|
|
|
ibuf_data[7:0]
|
2015-04-14 14:00:23 -04:00
|
|
|
(.I (rxi_data_p[7:0]),
|
2015-05-13 23:26:41 -04:00
|
|
|
.IB (rxi_data_n[7:0]),
|
|
|
|
.O (rxi_data[7:0]));
|
|
|
|
|
2014-12-14 17:18:53 -05:00
|
|
|
IBUFDS
|
2015-04-23 18:01:19 -04:00
|
|
|
#(.DIFF_TERM ("TRUE"),
|
|
|
|
.IOSTANDARD (IOSTANDARD))
|
2015-05-13 23:26:41 -04:00
|
|
|
ibuf_frame
|
2015-04-13 23:35:21 -04:00
|
|
|
(.I (rxi_frame_p),
|
2015-05-13 23:26:41 -04:00
|
|
|
.IB (rxi_frame_n),
|
|
|
|
.O (rxi_frame));
|
|
|
|
|
|
|
|
IBUFDS
|
|
|
|
#(.DIFF_TERM ("TRUE"),
|
|
|
|
.IOSTANDARD (IOSTANDARD))
|
|
|
|
ibuf_lclk
|
|
|
|
(.I (rxi_lclk_p),
|
|
|
|
.IB (rxi_lclk_n),
|
|
|
|
.O (rx_clk_pll)
|
|
|
|
);
|
|
|
|
|
|
|
|
//#####################
|
|
|
|
//# FRAME EDGE DETECTOR
|
|
|
|
//#####################
|
|
|
|
|
|
|
|
always @ (posedge rx_lclk or posedge reset)
|
|
|
|
if(reset)
|
|
|
|
begin
|
|
|
|
rx_frame <= 1'b0;
|
|
|
|
rx_frame_old <= rx_frame;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
rx_frame <= rxi_frame;
|
|
|
|
rx_frame_old <= rx_frame;
|
|
|
|
end
|
|
|
|
|
|
|
|
assign new_tran = rx_frame & ~rx_frame_old;
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
//#####################
|
2015-05-13 23:26:41 -04:00
|
|
|
//# DDR SAMPLERS
|
2014-12-14 17:18:53 -05:00
|
|
|
//#####################
|
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
//odd bytes
|
|
|
|
always @ (posedge rx_lclk)
|
|
|
|
data_even_reg[7:0] <= rxi_data[7:0];
|
|
|
|
|
|
|
|
//odd bytes
|
|
|
|
always @ (negedge rx_lclk)
|
|
|
|
data_odd_reg[7:0] <= rxi_data[7:0];
|
2014-12-14 17:18:53 -05:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
assign data_in[15:0] = {data_odd_reg[7:0],data_even_reg[7:0]};
|
|
|
|
|
|
|
|
//#####################
|
|
|
|
//#CREATE 112 BIT PACKET
|
|
|
|
//#####################
|
2014-12-14 17:18:53 -05:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
//write Pointer
|
|
|
|
always @ (posedge rx_lclk)
|
|
|
|
if (~rx_frame)
|
|
|
|
rx_pointer[6:0]<=7'b0000001; //new frame
|
|
|
|
else if (rx_pointer[6])
|
|
|
|
rx_pointer[6:0]<=7'b0001000; //anticipate burst
|
|
|
|
else if(rx_frame)
|
|
|
|
rx_pointer[6:0]<={rx_pointer[5:0],1'b0};//middle of frame
|
|
|
|
|
|
|
|
//convert to 112 bit packet
|
|
|
|
always @ (posedge rx_lclk)
|
|
|
|
if(rx_frame)
|
|
|
|
begin
|
|
|
|
if(rx_pointer[0])
|
|
|
|
rx_sample[15:0] <= data_in[15:0];
|
|
|
|
if(rx_pointer[1])
|
|
|
|
rx_sample[31:16] <= data_in[15:0];
|
|
|
|
if(rx_pointer[2])
|
|
|
|
rx_sample[47:32] <= data_in[15:0];
|
|
|
|
if(rx_pointer[3])
|
|
|
|
rx_sample[63:48] <= data_in[15:0];
|
|
|
|
if(rx_pointer[4])
|
|
|
|
rx_sample[79:64] <= data_in[15:0];
|
|
|
|
if(rx_pointer[5])
|
|
|
|
rx_sample[95:80] <= data_in[15:0];
|
|
|
|
if(rx_pointer[6])
|
|
|
|
rx_sample[111:96] <= data_in[15:0];
|
|
|
|
end
|
|
|
|
/*
|
|
|
|
case(rx_pointer[7:0])
|
|
|
|
8'b0000001: rx_sample[15:0] <= data_in[15:0];
|
|
|
|
8'b0000010: rx_sample[31:16] <= data_in[15:0];
|
|
|
|
8'b0000100: rx_sample[47:32] <= data_in[15:0];
|
|
|
|
8'b0001000: rx_sample[63:48] <= data_in[15:0];
|
|
|
|
8'b0010000: rx_sample[79:64] <= data_in[15:0];
|
|
|
|
8'b0100000: rx_sample[95:80] <= data_in[15:0];
|
|
|
|
8'b1000000: rx_sample[111:96] <= data_in[15:0];
|
|
|
|
default: rx_sample[111:0] <= 'b0;
|
|
|
|
endcase // case (rx_pointer)
|
|
|
|
*/
|
2014-12-14 17:18:53 -05:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
//#####################
|
|
|
|
//#DATA VALID SIGNAL
|
|
|
|
//#####################
|
|
|
|
always @ (posedge rx_lclk)
|
|
|
|
begin
|
|
|
|
access <= rx_pointer[6];
|
|
|
|
valid_packet <= access;//data pipeline
|
|
|
|
end
|
|
|
|
|
|
|
|
//###################################
|
|
|
|
//#SAMPLE AND HOLD DATA
|
|
|
|
//###################################
|
|
|
|
|
|
|
|
//(..and shuffle data for 104 bit packet)
|
|
|
|
always @ (posedge rx_lclk)
|
|
|
|
if(access)
|
|
|
|
begin
|
|
|
|
//access
|
|
|
|
burst <= rx_frame; //burst detected (for next cycle)
|
|
|
|
rx_packet_lclk[0] <= rx_sample[40];
|
|
|
|
//write
|
|
|
|
rx_packet_lclk[1] <= rx_sample[41];
|
|
|
|
//datamode
|
|
|
|
rx_packet_lclk[3:2] <= rx_sample[43:42];
|
|
|
|
//ctrlmode
|
|
|
|
rx_packet_lclk[7:4] <= rx_sample[15:12];
|
|
|
|
//dstaddr
|
|
|
|
rx_packet_lclk[39:8] <= {rx_sample[11:8],
|
|
|
|
rx_sample[23:16],
|
|
|
|
rx_sample[31:24],
|
|
|
|
rx_sample[39:32],
|
|
|
|
rx_sample[47:44]};
|
|
|
|
//data
|
|
|
|
rx_packet_lclk[71:40] <= {rx_sample[55:48],
|
|
|
|
rx_sample[63:56],
|
|
|
|
rx_sample[71:64],
|
|
|
|
rx_sample[79:72]};
|
|
|
|
//srcaddr
|
|
|
|
rx_packet_lclk[103:72]<= {rx_sample[87:80],
|
|
|
|
rx_sample[95:88],
|
|
|
|
rx_sample[103:96],
|
|
|
|
rx_sample[111:104]
|
|
|
|
};
|
|
|
|
end
|
|
|
|
|
|
|
|
//###################################
|
|
|
|
//#SYNCHRONIZE TO SLOW CLK
|
|
|
|
//###################################
|
|
|
|
|
|
|
|
//stretch access pulse to 4 cycles
|
|
|
|
pulse_stretcher #(.DW(3)) ps0 (.out (access_wide),
|
|
|
|
.in (valid_packet),
|
|
|
|
.clk (rx_lclk),
|
|
|
|
.reset (reset)
|
|
|
|
);
|
|
|
|
|
2014-12-14 17:18:53 -05:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
always @ (posedge rx_lclk_div4)
|
|
|
|
rx_access <= access_wide;
|
|
|
|
|
|
|
|
always @ (posedge rx_lclk_div4)
|
|
|
|
if(access_wide)
|
|
|
|
begin
|
|
|
|
rx_packet[PW-1:0] <= rx_packet_lclk[PW-1:0];
|
|
|
|
rx_burst <= burst;
|
|
|
|
end
|
|
|
|
|
|
|
|
//#####################################
|
2014-12-14 17:18:53 -05:00
|
|
|
//# Wait signals (asynchronous)
|
2015-05-13 23:26:41 -04:00
|
|
|
//#####################################
|
2014-12-14 17:18:53 -05:00
|
|
|
|
|
|
|
OBUFDS
|
|
|
|
#(
|
2015-04-23 18:01:19 -04:00
|
|
|
.IOSTANDARD(IOSTANDARD),
|
2014-12-14 17:18:53 -05:00
|
|
|
.SLEW("SLOW")
|
|
|
|
) OBUFDS_RXWRWAIT
|
|
|
|
(
|
2015-04-13 23:35:21 -04:00
|
|
|
.O(rxo_wr_wait_p),
|
|
|
|
.OB(rxo_wr_wait_n),
|
2015-05-10 23:38:08 -04:00
|
|
|
.I(rx_wr_wait)
|
2014-12-14 17:18:53 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
OBUFDS
|
|
|
|
#(
|
2015-04-23 18:01:19 -04:00
|
|
|
.IOSTANDARD(IOSTANDARD),
|
2014-12-14 17:18:53 -05:00
|
|
|
.SLEW("SLOW")
|
|
|
|
) OBUFDS_RXRDWAIT
|
|
|
|
(
|
2015-04-13 23:35:21 -04:00
|
|
|
.O(rxo_rd_wait_p),
|
|
|
|
.OB(rxo_rd_wait_n),
|
2015-05-10 23:38:08 -04:00
|
|
|
.I(rx_rd_wait)
|
2014-12-14 17:18:53 -05:00
|
|
|
);
|
2015-05-13 23:26:41 -04:00
|
|
|
|
2015-04-14 14:00:23 -04:00
|
|
|
endmodule // erx_io
|
2015-05-13 23:26:41 -04:00
|
|
|
// Local Variables:
|
|
|
|
// verilog-library-directories:("." "../../emesh/hdl" "../../common/hdl")
|
|
|
|
// End:
|
2015-04-14 14:00:23 -04:00
|
|
|
|
|
|
|
/*
|
2015-05-13 23:26:41 -04:00
|
|
|
Copyright (C) 2014 Adapteva, Inc.
|
|
|
|
Contributed by Andreas Olofsson <fred@adapteva.com>
|
2015-04-14 14:00:23 -04:00
|
|
|
|
2015-05-13 23:26:41 -04:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program (see the file COPYING). If not, see
|
|
|
|
<http://www.gnu.org/licenses/>.
|
2015-04-14 14:00:23 -04:00
|
|
|
*/
|