From 0214df58047c0d4b7f361c04cc2a36fae01f3370 Mon Sep 17 00:00:00 2001 From: Andreas Olofsson Date: Wed, 13 May 2015 23:26:41 -0400 Subject: [PATCH] Complete redesign of erx io logic -Building from primitives -Work in progress, not quite complete --- elink/hdl/erx_io.v | 457 +++++++++++++++++++++++---------------------- 1 file changed, 233 insertions(+), 224 deletions(-) diff --git a/elink/hdl/erx_io.v b/elink/hdl/erx_io.v index b1c3c12..15d5560 100644 --- a/elink/hdl/erx_io.v +++ b/elink/hdl/erx_io.v @@ -1,233 +1,244 @@ module erx_io (/*AUTOARG*/ // Outputs - rxo_wr_wait_p, rxo_wr_wait_n, rxo_rd_wait_p, rxo_rd_wait_n, - rx_lclk_div4, rx_frame_par, rx_data_par, + 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, // Inputs - reset, 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, 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 IOSTANDARD = "LVDS_25"; + parameter PW = 104; - //########### - //# reset - //########### - input reset; // Reset (from ecfg) - - //########### - //# eLink pins - //########### - input rxi_lclk_p, rxi_lclk_n; //link rx clock input - input rxi_frame_p, rxi_frame_n; //link rx frame signal - input [7:0] rxi_data_p, rxi_data_n; //link rx data - output rxo_wr_wait_p,rxo_wr_wait_n; //link rx write pushback output - output rxo_rd_wait_p,rxo_rd_wait_n; //link rx read pushback output + //######################### + //# 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 - //############# - //# Fabric interface, 1/8 bit rate of eLink - //############# - output rx_lclk_div4; // Parallel clock output (slow) - output [7:0] rx_frame_par; - output [63:0] rx_data_par; - input rx_wr_wait; - input rx_rd_wait; + //########################## + //# erx logic interface + //########################## + output rx_access; + output rx_burst; + output [PW-1:0] rx_packet; + input rx_wr_wait; + input rx_rd_wait; //############ //# WIRES //############ - wire [7:0] rx_data; // High-speed serial data - wire rx_frame; // serial frame - wire rx_lclk; // Single-ended clock - wire rx_lclk_s; // Serial clock after BUFIO + 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; + + //################################ //# Input Buffers Instantiation //################################ + IBUFDS #(.DIFF_TERM ("TRUE"), .IOSTANDARD (IOSTANDARD)) - ibufds_rxdata[7:0] + ibuf_data[7:0] (.I (rxi_data_p[7:0]), - .IB (rxi_data_n[7:0]), - .O (rx_data[7:0])); + .IB (rxi_data_n[7:0]), + .O (rxi_data[7:0])); + + IBUFDS + #(.DIFF_TERM ("TRUE"), + .IOSTANDARD (IOSTANDARD)) + ibuf_frame + (.I (rxi_frame_p), + .IB (rxi_frame_n), + .O (rxi_frame)); IBUFDS #(.DIFF_TERM ("TRUE"), .IOSTANDARD (IOSTANDARD)) - ibufds_rx_frame - (.I (rxi_frame_p), - .IB (rxi_frame_n), - .O (rx_frame)); - - //##################### - //# Clock Buffers - //##################### - - IBUFGDS - #(.DIFF_TERM ("TRUE"), - .IOSTANDARD (IOSTANDARD)) - ibufds_rxlclk - (.I (rxi_lclk_p), - .IB (rxi_lclk_n), - .O (rx_lclk)); - - BUFIO bufio_rxlclk - (.I (rx_lclk), - .O (rx_lclk_s)); + ibuf_lclk + (.I (rxi_lclk_p), + .IB (rxi_lclk_n), + .O (rx_clk_pll) + ); - // BUFR generates the slow clock - BUFR - #(.SIM_DEVICE("7SERIES"), - .BUFR_DIVIDE("4")) - rx_lclk_div4_buf - (.O (rx_lclk_div4), - .CE(1'b1), - .CLR(reset),//no reset - .I (rx_lclk)); + //##################### + //# 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; + + //##################### + //# DDR SAMPLERS + //##################### + + //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]; + + assign data_in[15:0] = {data_odd_reg[7:0],data_even_reg[7:0]}; + + //##################### + //#CREATE 112 BIT PACKET + //##################### + + //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) +*/ + + //##################### + //#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) + ); + + + 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 - //############################# - //# Deserializer instantiations - //############################# - genvar i; - generate for(i=0; i<8; i=i+1) - begin : gen_serdes - ISERDESE2 - #( - .DATA_RATE("DDR"), // DDR, SDR - .DATA_WIDTH(8), // Parallel data width (2-8,10,14) - .DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE) - .DYN_CLK_INV_EN("FALSE"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE) - // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1) - .INIT_Q1(1'b0), - .INIT_Q2(1'b0), - .INIT_Q3(1'b0), - .INIT_Q4(1'b0), - .INTERFACE_TYPE("NETWORKING"), - // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE - .IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD - .NUM_CE(2), // Number of clock enables (1,2) - .OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE) - .SERDES_MODE("MASTER"), // MASTER, SLAVE - // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1) - .SRVAL_Q1(1'b0), - .SRVAL_Q2(1'b0), - .SRVAL_Q3(1'b0), - .SRVAL_Q4(1'b0) - ) - ISERDESE2_rxdata - ( - .O(), // 1-bit output: Combinatorial output - // Q1 - Q8: 1-bit (each) output: Registered data outputs - .Q1(rx_data_par[i]), // Last data in? - .Q2(rx_data_par[i+8]), - .Q3(rx_data_par[i+16]), - .Q4(rx_data_par[i+24]), - .Q5(rx_data_par[i+32]), - .Q6(rx_data_par[i+40]), - .Q7(rx_data_par[i+48]), - .Q8(rx_data_par[i+56]), // First data in? - // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports - .SHIFTOUT1(), - .SHIFTOUT2(), - .BITSLIP(1'b0), // 1-bit input: The BITSLIP pin performs a Bitslip operation - // synchronous to CLKDIV when asserted (active High). Subsequently, the data - // seen on the Q1 to Q8 output ports will shift, as in a barrel-shifter - // operation, one position every time Bitslip is invoked. DDR operation is - // different from SDR. - // CE1, CE2: 1-bit (each) input: Data register clock enable inputs - .CE1(1'b1), - .CE2(1'b1), - .CLKDIVP(1'b0), // 1-bit input: TBD - // Clocks: 1-bit (each) input: ISERDESE2 clock input ports - .CLK(rx_lclk_s), // 1-bit input: High-speed clock - .CLKB(~rx_lclk_s), // 1-bit input: High-speed secondary clock - .CLKDIV(rx_lclk_div4), // 1-bit input: Divided clock - .OCLK(1'b0), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" - // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity - .DYNCLKDIVSEL(1'b0), // 1-bit input: Dynamic CLKDIV inversion - .DYNCLKSEL(1'b0), // 1-bit input: Dynamic CLK/CLKB inversion - // Input Data: 1-bit (each) input: ISERDESE2 data input ports - .D(rx_data[i]), // 1-bit input: Data input - .DDLY(1'b0), // 1-bit input: Serial data from IDELAYE2 - .OFB(1'b0), // 1-bit input: Data feedback from OSERDESE2 - .OCLKB(1'b0), // 1-bit input: High speed negative edge output clock - .RST(reset), // 1-bit input: Active high asynchronous reset - // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports - .SHIFTIN1(1'b0), - .SHIFTIN2(1'b0) - ); - end // block: gen_serdes - endgenerate - - ISERDESE2 - #( - .DATA_RATE("DDR"), // DDR, SDR - .DATA_WIDTH(8), // Parallel data width (2-8,10,14) - .DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE) - .DYN_CLK_INV_EN("FALSE"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE) - // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1) - .INIT_Q1(1'b0), - .INIT_Q2(1'b0), - .INIT_Q3(1'b0), - .INIT_Q4(1'b0), - .INTERFACE_TYPE("NETWORKING"), - // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE - .IOBDELAY("NONE"), // NONE, BOTH, IBUF, IFD - .NUM_CE(2), // Number of clock enables (1,2) - .OFB_USED("FALSE"), // Select OFB path (FALSE, TRUE) - .SERDES_MODE("MASTER"), // MASTER, SLAVE - // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1) - .SRVAL_Q1(1'b0), - .SRVAL_Q2(1'b0), - .SRVAL_Q3(1'b0), - .SRVAL_Q4(1'b0) - ) - ISERDESE2_rx_frame - ( - .O(), // 1-bit output: Combinatorial output - // Q1 - Q8: 1-bit (each) output: Registered data outputs - .Q1(rx_frame_par[0]), - .Q2(rx_frame_par[1]), - .Q3(rx_frame_par[2]), - .Q4(rx_frame_par[3]), - .Q5(rx_frame_par[4]), - .Q6(rx_frame_par[5]), - .Q7(rx_frame_par[6]), - .Q8(rx_frame_par[7]), - // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports - .SHIFTOUT1(), - .SHIFTOUT2(), - .BITSLIP(1'b0), // 1-bit input: The BITSLIP pin performs a Bitslip operation - // synchronous to CLKDIV when asserted (active High). Subsequently, the data - // seen on the Q1 to Q8 output ports will shift, as in a barrel-shifter - // operation, one position every time Bitslip is invoked. DDR operation is - // different from SDR. - // CE1, CE2: 1-bit (each) input: Data register clock enable inputs - .CE1(1'b1), - .CE2(1'b1), - .CLKDIVP(1'b0), // 1-bit input: TBD - // Clocks: 1-bit (each) input: ISERDESE2 clock input ports - .CLK(rx_lclk_s), // 1-bit input: High-speed clock - .CLKB(~rx_lclk_s), // 1-bit input: High-speed secondary clock - .CLKDIV(rx_lclk_div4), // 1-bit input: Divided clock - .OCLK(1'b0), // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" - // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity - .DYNCLKDIVSEL(1'b0), // 1-bit input: Dynamic CLKDIV inversion - .DYNCLKSEL(1'b0), // 1-bit input: Dynamic CLK/CLKB inversion - // Input Data: 1-bit (each) input: ISERDESE2 data input ports - .D(rx_frame), // 1-bit input: Data input - .DDLY(1'b0), // 1-bit input: Serial data from IDELAYE2 - .OFB(1'b0), // 1-bit input: Data feedback from OSERDESE2 - .OCLKB(1'b0), // 1-bit input: High speed negative edge output clock - .RST(reset), // 1-bit input: Active high asynchronous reset - // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports - .SHIFTIN1(1'b0), - .SHIFTIN2(1'b0) - ); - - //############# + //##################################### //# Wait signals (asynchronous) - //############# + //##################################### OBUFDS #( @@ -250,29 +261,27 @@ module erx_io (/*AUTOARG*/ .OB(rxo_rd_wait_n), .I(rx_rd_wait) ); - + endmodule // erx_io +// Local Variables: +// verilog-library-directories:("." "../../emesh/hdl" "../../common/hdl") +// End: /* - File: e_rx_io.v + Copyright (C) 2014 Adapteva, Inc. + Contributed by Andreas Olofsson - This file is part of the Parallella Project . - - Copyright (C) 2014 Adapteva, Inc. - Contributed by Fred Huettig - Contributed by Andreas Olofsson - - 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 - . + 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 + . */