Commit 7c04cd9c authored by Alexey Grebenkin's avatar Alexey Grebenkin

Initial files with license agreement

parent 10d25413
# gtxe2_nosecureip
GTXE2_CHANNEL_GPL.v is a non-synthesizable open-source replacement for a propriate xilinx's primitive GTXE2_CHANNEL.v
For now only basic features are implemented : OOB, comma aligment, 10-8 encoding/decoding, clocking scheme.
Still, that is enough to run SATA protocol implementation simulation.
/*******************************************************************************
* Module: GTXE2_CHANNEL
* Date: 2015-07-06
* Author: Alexey
* Description: A wrapper maintaining interface compability
*
* Copyright (c) 2015 Elphel, Inc.
* GTXE2_CHANNEL_GPL.v 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.
*
* GTXE2_CHANNEL_GPL.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
/**
* Original unisims primitive's interfaces, according to xilinx's user guide:
* "7 Series FPGAs GTX/GTH Transceivers User Guide UG476(v1.11)", which is further
* referenced as ug476 or UG476
*
* Due to lack of functionality of gtxe2_gpl project as compared to the xilinx's primitive,
* not all of the inputs are used and not all of the outputs are driven.
**/
`include "gtxe2_chnl.v"
module GTXE2_CHANNEL(
// clocking ports, UG476 p.37
input [2:0] CPLLREFCLKSEL,
input GTGREFCLK,
input GTNORTHREFCLK0,
input GTNORTHREFCLK1,
input GTREFCLK0,
input GTREFCLK1,
input GTSOUTHREFCLK0,
input GTSOUTHREFCLK1,
input [1:0] RXSYSCLKSEL,
input [1:0] TXSYSCLKSEL,
output GTREFCLKMONITOR,
// CPLL Ports, UG476 p.48
input CPLLLOCKDETCLK,
input CPLLLOCKEN,
input CPLLPD,
input CPLLRESET,
output CPLLFBCLKLOST,
output CPLLLOCK,
output CPLLREFCLKLOST,
output TSTOUT,
input GTRSVD,
input PCSRSVDIN,
input PCSRSVDIN2,
input PMARSVDIN,
input PMARSVDIN2,
input TSTIN,
// Reset Mode ports, ug476 p.62
input GTRESETSEL,
input RESETOVRD,
// TX Reset ports, ug476 p.65
input CFGRESET,
input GTTXRESET,
input TXPCSRESET,
input TXPMARESET,
output TXRESETDONE,
input TXUSERRDY,
output PCSRSVDOUT,
// RX Reset ports, UG476 p.73
input GTRXRESET,
input RXPMARESET,
input RXCDRRESET,
input RXCDRFREQRESET,
input RXDFELPMRESET,
input EYESCANRESET,
input RXPCSRESET,
input RXBUFRESET,
input RXUSERRDY,
output RXRESETDONE,
input RXOOBRESET,
// Power Down ports, ug476 p.88
input [1:0] RXPD,
input [1:0] TXPD,
input TXPDELECIDLEMODE,
input TXPHDLYPD,
input RXPHDLYPD,
// Loopback ports, ug476 p.91
input [2:0] LOOPBACK,
// Dynamic Reconfiguration Port, ug476 p.92
input [8:0] DRPADDR,
input DRPCLK,
input [15:0] DRPDI,
input [15:0] DRPDO,
input DRPEN,
output DRPRDY,
input DRPWE,
// Digital Monitor Ports, ug476 p.95
input [3:0] CLKRSVD,
input [7:0] DMONITOROUT,
// TX Interface Ports, ug476 p.110
input [7:0] TXCHARDISPMODE,
input [7:0] TXCHARDISPVAL,
input [63:0] TXDATA,
input TXUSRCLK,
input TXUSRCLK2,
// TX 8B/10B encoder ports, ug476 p.118
input [7:0] TX8B10BBYPASS,
input TX8B10BEN,
input [7:0] TXCHARISK,
// TX Gearbox ports, ug476 p.122
output TXGEARBOXREADY,
input [2:0] TXHEADER,
input [6:0] TXSEQUENCE,
input TXSTARTSEQ,
// TX BUffer Ports, ug476 p.134
input [1:0] TXBUFSTATUS,
// TX Buffer Bypass Ports, ug476 p.136
input TXDLYSRESET,
input TXPHALIGN,
input TXPHALIGNEN,
input TXPHINIT,
input TXPHOVRDEN,
input TXPHDLYRESET,
input TXDLYBYPASS,
input TXDLYEN,
input TXDLYOVRDEN,
input TXPHDLYTSTCLK,
input TXDLYHOLD,
input TXDLYUPDOWN,
output TXPHALIGNDONE,
output TXPHINITDONE,
output TXDLYSRESETDONE,
input TXSYNCMODE,
input TXSYNCALLIN,
input TXSYNCIN,
input TXSYNCOUT,
input TXSYNCDONE,
// TX Pattern Generator, ug476 p.147
input [2:0] TXPRBSSEL,
input TXPRBSFORCEERR,
// TX Polarity Control Ports, ug476 p.149
input TXPOLARITY,
// TX Fabric Clock Output Control Ports, ug476 p.152
input [2:0] TXOUTCLKSEL,
input [2:0] TXRATE,
output TXOUTCLKFABRIC,
output TXOUTCLK,
output TXOUTCLKPCS,
output TXRATEDONE,
// TX Phase Interpolator PPM Controller Ports, ug476 p.154
input TXPIPPMEN,
input TXPIPPMOVRDEN,
input TXPIPPMSEL,
input TXPIPPMPD,
input [4:0] TXPIPPMSTEPSIZE,
// TX Configurable Driver Ports, ug476 p.156
input [2:0] TXBUFDIFFCTRL,
input TXDEEMPH,
input [3:0] TXDIFFCTRL,
input TXELECIDLE,
input TXINHIBIT,
input [6:0] TXMAINCURSOR,
input [2:0] TXMARGIN,
input TXQPIBIASEN,
output TXQPISENN,
output TXQPISENP,
input TXQPISTRONGPDOWN,
input TXQPIWEAKPUP,
input [4:0] TXPOSTCURSOR,
input TXPOSTCURSORINV,
input [4:0] TXPRECURSOR,
input TXPRECURSORINV,
input TXSWING,
input TXDIFFPD,
input TXPISOPD,
// TX Receiver Detection Ports, ug476 p.165
input TXDETECTRX,
output PHYSTATUS,
input [2:0] RXSTATUS,
// TX OOB Signaling Ports, ug476 p.166
output TXCOMFINISH,
input TXCOMINIT,
input TXCOMSAS,
input TXCOMWAKE,
// RX AFE Ports, ug476 p.171
output RXQPISENN,
output RXQPISENP,
input RXQPIEN,
// RX OOB Signaling Ports, ug476 p.178
input [1:0] RXELECIDLEMODE,
output RXELECIDLE,
output RXCOMINITDET,
output RXCOMSASDET,
output RXCOMWAKEDET,
// RX Equalizer Ports, ug476 p.189
input RXLPMEN,
input RXOSHOLD,
input RXOSOVRDEN,
input RXLPMLFHOLD,
input RXLPMLFKLOVRDEN,
input RXLPMHFHOLD,
input RXLPMHFOVRDEN,
input RXDFEAGCHOLD,
input RXDFEAGCOVRDEN,
input RXDFELFHOLD,
input RXDFELFOVRDEN,
input RXDFEUTHOLD,
input RXDFEUTOVRDEN,
input RXDFEVPHOLD,
input RXDFEVPOVRDEN,
input RXDFETAP2HOLD,
input RXDFETAP2OVRDEN,
input RXDFETAP3HOLD,
input RXDFETAP3OVRDEN,
input RXDFETAP4HOLD,
input RXDFETAP4OVRDEN,
input RXDFETAP5HOLD,
input RXDFETAP5OVRDEN,
input RXDFECM1EN,
input RXDFEXYDHOLD,
input RXDFEXYDOVRDEN,
input RXDFEXYDEN,
input [1:0] RXMONITORSEL,
input [6:0] RXMONITOROUT,
// CDR Ports, ug476 p.202
input RXCDRHOLD,
input RXCDROVRDEN,
input RXCDRRESETRSV,
input [2:0] RXRATE,
output RXCDRLOCK,
// RX Fabric Clock Output Control Ports, ug476 p.213
input [2:0] RXOUTCLKSEL,
output RXOUTCLKFABRIC,
output RXOUTCLK,
output RXOUTCLKPCS,
output RXRATEDONE,
input RXDLYBYPASS,
// RX Margin Analysis Ports, ug476 p.220
output EYESCANDATAERROR,
input EYESCANTRIGGER,
input EYESCANMODE,
// RX Polarity Control Ports, ug476 p.224
input RXPOLARITY,
// Pattern Checker Ports, ug476 p.225
input RXPRBSCNTRESET,
input [2:0] RXPRBSSEL,
output RXPRBSERR,
// RX Byte and Word Alignment Ports, ug476 p.233
output RXBYTEISALIGNED,
output RXBYTEREALIGN,
output RXCOMMADET,
input RXCOMMADETEN,
input RXPCOMMAALIGNEN,
input RXMCOMMAALIGNEN,
input RXSLIDE,
// RX 8B/10B Decoder Ports, ug476 p.241
input RX8B10BEN,
output [7:0] RXCHARISCOMMA,
output [7:0] RXCHARISK,
output [7:0] RXDISPERR,
output [7:0] RXNOTINTABLE,
input SETERRSTATUS,
// RX Buffer Bypass Ports, ug476 p.244
input RXPHDLYRESET,
input RXPHALIGN,
input RXPHALIGNEN,
input RXPHOVRDEN,
input RXDLYSRESET,
input RXDLYEN,
input RXDLYOVRDEN,
input RXDDIEN,
output RXPHALIGNDONE,
output RXPHMONITOR,
output RXPHSLIPMONITOR,
output RXDLYSRESETDONE,
// RX Buffer Ports, ug476 p.259
input [2:0] RXBUFSTATUS,
// RX Clock Correction Ports, ug476 p.263
input [1:0] RXCLKCORCNT,
// RX Channel Bonding Ports, ug476 p.274
output RXCHANBONDSEQ,
output RXCHANISALIGNED,
output RXCHANREALIGN,
input [4:0] RXCHBONDI,
output [4:0] RXCHBONDO,
input [2:0] RXCHBONDLEVEL,
input RXCHBONDMASTER,
input RXCHBONDSLAVE,
input RXCHBONDEN,
// RX Gearbox Ports, ug476 p.285
output RXDATAVALID,
input RXGEARBOXSLIP,
input [2:0] RXHEADER,
output RXHEADERVALID,
output RXSTARTOFSEQ,
// FPGA RX Interface Ports, ug476 p.299
output [63:0] RXDATA,
input RXUSRCLK,
input RXUSRCLK2,
// ug476, p.323
output RXVALID,
// for correct clocking scheme in case of multilane structure
input QPLLCLK,
input QPLLREFCLK,
// Diffpairs
input GTXRXP,
input GTXRXN,
output GTXTXN,
output GTXTXP
);
// simulation common attributes, UG476 p.28
parameter SIM_RESET_SPEEDUP = "TRUE";
parameter SIM_CPLLREFCLK_SEL = 3'b001;
parameter SIM_RECEIVER_DETECT_PASS = "TRUE";
parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X";
parameter SIM_VERSION = "1.0";
// Clocking Atributes, UG476 p.38
parameter OUTREFCLK_SEL_INV = 1'b0;
// CPLL Attributes, UG476 p.49
parameter CPLL_CFG = 24'h0;
parameter CPLL_FBDIV = 4;
parameter CPLL_FBDIV_45 = 5;
parameter CPLL_INIT_CFG = 24'h0;
parameter CPLL_LOCK_CFG = 16'h0;
parameter CPLL_REFCLK_DIV = 1;
parameter RXOUT_DIV = 2;
parameter TXOUT_DIV = 2;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
parameter PMA_RSV3 = 2'b00;
// TX Initialization and Reset Attributes, ug476 p.66
parameter TXPCSRESET_TIME = 5'b00001;
parameter TXPMARESET_TIME = 5'b00001;
// RX Initialization and Reset Attributes, UG476 p.75
parameter RXPMARESET_TIME = 5'h0;
parameter RXCDRPHRESET_TIME = 5'h0;
parameter RXCDRFREQRESET_TIME = 5'h0;
parameter RXDFELPMRESET_TIME = 7'h0;
parameter RXISCANRESET_TIME = 7'h0;
parameter RXPCSRESET_TIME = 5'h0;
parameter RXBUFRESET_TIME = 5'h0;
// Power Down attributes, ug476 p.88
parameter PD_TRANS_TIME_FROM_P2 = 12'h0;
parameter PD_TRANS_TIME_NONE_P2 = 8'h0;
parameter PD_TRANS_TIME_TO_P2 = 8'h0;
parameter TRANS_TIME_RATE = 8'h0;
parameter RX_CLKMUX_PD = 1'b0;
parameter TX_CLKMUX_PD = 1'b0;
// GTX Digital Monitor Attributes, ug476 p.96
parameter DMONITOR_CFG = 24'h008101;
// TX Interface attributes, ug476 p.111
parameter TX_DATA_WIDTH = 20;
parameter TX_INT_DATAWIDTH = 0;
// TX Gearbox Attributes, ug476 p.121
parameter GEARBOX_MODE = 3'h0;
parameter TXGEARBOX_EN = "FALSE";
// TX BUffer Attributes, ug476 p.134
parameter TXBUF_EN = "TRUE";
// TX Bypass buffer, ug476 p.138
parameter TX_XCLK_SEL = "TXOUT";
parameter TXPH_CFG = 16'h0;
parameter TXPH_MONITOR_SEL = 5'h0;
parameter TXPHDLY_CFG = 24'h0;
parameter TXDLY_CFG = 16'h0;
parameter TXDLY_LCFG = 9'h0;
parameter TXDLY_TAP_CFG = 16'h0;
parameter TXSYNC_MULTILANE = 1'b0;
parameter TXSYNC_SKIP_DA = 1'b0;
parameter TXSYNC_OVRD = 1'b1;
parameter LOOPBACK_CFG = 1'b0;
// TX Pattern Generator, ug476 p.147
parameter RXPRBS_ERR_LOOPBACK = 1'b0;
// TX Fabric Clock Output Control Attributes, ug476 p. 153
parameter TXBUF_RESET_ON_RATE_CHANGE = "TRUE";
// TX Phase Interpolator PPM Controller Attributes, ug476 p.155
parameter TXPI_SYNCFREQ_PPM = 3'b001;
parameter TXPI_PPM_CFG = 8'd0;
parameter TXPI_INVSTROBE_SEL = 1'b0;
parameter TXPI_GREY_SEL = 1'b0;
parameter TXPI_PPMCLK_SEL = "12345";
// TX Configurable Driver Attributes, ug476 p.162
parameter TX_DEEMPH0 = 5'b10100;
parameter TX_DEEMPH1 = 5'b01101;
parameter TX_DRIVE_MODE = "DIRECT";
parameter TX_MAINCURSOR_SEL = 1'b0;
parameter TX_MARGIN_FULL_0 = 7'b0;
parameter TX_MARGIN_FULL_1 = 7'b0;
parameter TX_MARGIN_FULL_2 = 7'b0;
parameter TX_MARGIN_FULL_3 = 7'b0;
parameter TX_MARGIN_FULL_4 = 7'b0;
parameter TX_MARGIN_LOW_0 = 7'b0;
parameter TX_MARGIN_LOW_1 = 7'b0;
parameter TX_MARGIN_LOW_2 = 7'b0;
parameter TX_MARGIN_LOW_3 = 7'b0;
parameter TX_MARGIN_LOW_4 = 7'b0;
parameter TX_PREDRIVER_MODE = 1'b0;
parameter TX_QPI_STATUS_EN = 1'b0;
parameter TX_EIDLE_ASSERT_DELAY = 3'b110;
parameter TX_EIDLE_DEASSERT_DELAY = 3'b100;
parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE";
// TX Receiver Detection Attributes, ug476 p.165
parameter TX_RXDETECT_CFG = 14'h0;
parameter TX_RXDETECT_REF = 3'h0;
// TX OOB Signaling Attributes
parameter SATA_BURST_SEQ_LEN = 4'b0101;
// RX AFE Attributes, ug476 p.171
parameter RX_CM_SEL = 2'b11;
parameter TERM_RCAL_CFG = 5'b0;
parameter TERM_RCAL_OVRD = 1'b0;
parameter RX_CM_TRIM = 3'b010;
// RX OOB Signaling Attributes, ug476 p.179
parameter PCS_RSVD_ATTR = 48'h0100; // oob is up
parameter RXOOB_CFG = 7'b0000110;
parameter SATA_BURST_VAL = 3'b110;
parameter SATA_EIDLE_VAL = 3'b110;
parameter SAS_MIN_COM = 36;
parameter SATA_MIN_INIT = 12;
parameter SATA_MIN_WAKE = 4;
parameter SATA_MAX_BURST = 8;
parameter SATA_MIN_BURST = 4;
parameter SAS_MAX_COM = 64;
parameter SATA_MAX_INIT = 21;
parameter SATA_MAX_WAKE = 7;
// RX Equalizer Attributes, ug476 p.193
parameter RX_OS_CFG = 13'h0080;
parameter RXLPM_LF_CFG = 14'h00f0;
parameter RXLPM_HF_CFG = 14'h00f0;
parameter RX_DFE_LPM_CFG = 16'h0;
parameter RX_DFE_GAIN_CFG = 23'h020FEA;
parameter RX_DFE_H2_CFG = 12'h0;
parameter RX_DFE_H3_CFG = 12'h040;
parameter RX_DFE_H4_CFG = 11'h0e0;
parameter RX_DFE_H5_CFG = 11'h0e0;
parameter PMA_RSV = 32'h00018480;
parameter RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0;
parameter RX_DFE_XYD_CFG = 13'h0;
parameter PMA_RSV4 = 32'h0;
parameter PMA_RSV2 = 16'h0;
parameter RX_BIAS_CFG = 12'h040;
parameter RX_DEBUG_CFG = 12'h0;
parameter RX_DFE_KL_CFG = 13'h0;
parameter RX_DFE_KL_CFG2 = 32'h0;
parameter RX_DFE_UT_CFG = 17'h11e00;
parameter RX_DFE_VP_CFG = 17'h03f03;
// CDR Attributes, ug476 p.203
parameter RXCDR_CFG = 72'h0;
parameter RXCDR_LOCK_CFG = 6'h0;
parameter RXCDR_HOLD_DURING_EIDLE = 1'b0;
parameter RXCDR_FR_RESET_ON_EIDLE = 1'b0;
parameter RXCDR_PH_RESET_ON_EIDLE = 1'b0;
// RX Fabric Clock Output Control Attributes
parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE";
// RX Margin Analysis Attributes
parameter ES_VERT_OFFSET = 9'h0;
parameter ES_HORZ_OFFSET = 12'h0;
parameter ES_PRESCALE = 5'h0;
parameter ES_SDATA_MASK = 80'h0;
parameter ES_QUALIFIER = 80'h0;
parameter ES_QUAL_MASK = 80'h0;
parameter ES_EYE_SCAN_EN = 1'b1;
parameter ES_ERRDET_EN = 1'b0;
parameter ES_CONTROL = 6'h0;
parameter es_control_status = 4'b000;
parameter es_rdata = 80'h0;
parameter es_sdata = 80'h0;
parameter es_error_count = 16'h0;
parameter es_sample_count = 16'h0;
parameter RX_DATA_WIDTH = 20;
parameter RX_INT_DATAWIDTH = 0;
parameter ES_PMA_CFG = 10'h0;
// Pattern Checker Attributes, ug476 p.226
parameter RX_PRBS_ERR_CNT = 16'h15c;
// RX Byte and Word Alignment Attributes, ug476 p.235
parameter ALIGN_COMMA_WORD = 1;
parameter ALIGN_COMMA_ENABLE = 10'b1111111111;
parameter ALIGN_COMMA_DOUBLE = "FALSE";
parameter ALIGN_MCOMMA_DET = "TRUE";
parameter ALIGN_MCOMMA_VALUE = 10'b1010000011;
parameter ALIGN_PCOMMA_DET = "TRUE";
parameter ALIGN_PCOMMA_VALUE = 10'b0101111100;
parameter SHOW_REALIGN_COMMA = "TRUE";
parameter RXSLIDE_MODE = "OFF";
parameter RXSLIDE_AUTO_WAIT = 7;
parameter RX_SIG_VALID_DLY = 10;
parameter COMMA_ALIGN_LATENCY = 9'h14e;
// RX 8B/10B Decoder Attributes, ug476 p.242
parameter RX_DISPERR_SEQ_MATCH = "TRUE";
parameter DEC_MCOMMA_DETECT = "TRUE";
parameter DEC_PCOMMA_DETECT = "TRUE";
parameter DEC_VALID_COMMA_ONLY = "FALSE";
parameter UCODEER_CLR = 1'b0;
// RX Buffer Bypass Attributes, ug476 p.247
parameter RXBUF_EN = "TRUE";
parameter RX_XCLK_SEL = "RXREC";
parameter RXPH_CFG = 24'h0;
parameter RXPH_MONITOR_SEL = 5'h0;
parameter RXPHDLY_CFG = 24'h0;
parameter RXDLY_CFG = 16'h0;
parameter RXDLY_LCFG = 9'h0;
parameter RXDLY_TAP_CFG = 16'h0;
parameter RX_DDI_SEL = 6'h0;
parameter TST_RSV = 32'h0;
// RX Buffer Attributes, ug476 p.259
parameter RX_BUFFER_CFG = 6'b0;
parameter RX_DEFER_RESET_BUF_EN = "TRUE";
parameter RXBUF_ADDR_MODE = "FAST";
parameter RXBUF_EIDLE_HI_CNT = 4'b0;
parameter RXBUF_EIDLE_LO_CNT = 4'b0;
parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE";
parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE";
parameter RXBUF_RESET_ON_EIDLE = "FALSE";
parameter RXBUF_THRESH_OVFLW = 0;
parameter RXBUF_THRESH_OVRD = "FALSE";
parameter RXBUF_THRESH_UNDFLW = 0;
// RX Clock Correction Attributes, ug476 p.265
parameter CBCC_DATA_SOURCE_SEL = "DECODED";
parameter CLK_CORRECT_USE = "FALSE";
parameter CLK_COR_SEQ_2_USE = "FALSE";
parameter CLK_COR_KEEP_IDLE = "FALSE";
parameter CLK_COR_MAX_LAT = 9;
parameter CLK_COR_MIN_LAT = 7;
parameter CLK_COR_PRECEDENCE = "TRUE";
parameter CLK_COR_REPEAT_WAIT = 0;
parameter CLK_COR_SEQ_LEN = 1;
parameter CLK_COR_SEQ_1_ENABLE = 4'b1111;
parameter CLK_COR_SEQ_1_1 = 10'b0;
parameter CLK_COR_SEQ_1_2 = 10'b0;
parameter CLK_COR_SEQ_1_3 = 10'b0;
parameter CLK_COR_SEQ_1_4 = 10'b0;
parameter CLK_COR_SEQ_2_ENABLE = 4'b1111;
parameter CLK_COR_SEQ_2_1 = 10'b0;
parameter CLK_COR_SEQ_2_2 = 10'b0;
parameter CLK_COR_SEQ_2_3 = 10'b0;
parameter CLK_COR_SEQ_2_4 = 10'b0;
// RX Channel Bonding Attributes, ug476 p.276
parameter CHAN_BOND_MAX_SKEW = 1;
parameter CHAN_BOND_KEEP_ALIGN = "FALSE";
parameter CHAN_BOND_SEQ_LEN = 1;
parameter CHAN_BOND_SEQ_1_1 = 10'b0;
parameter CHAN_BOND_SEQ_1_2 = 10'b0;
parameter CHAN_BOND_SEQ_1_3 = 10'b0;
parameter CHAN_BOND_SEQ_1_4 = 10'b0;
parameter CHAN_BOND_SEQ_1_ENABLE = 4'b1111;
parameter CHAN_BOND_SEQ_2_1 = 10'b0;
parameter CHAN_BOND_SEQ_2_2 = 10'b0;
parameter CHAN_BOND_SEQ_2_3 = 10'b0;
parameter CHAN_BOND_SEQ_2_4 = 10'b0;
parameter CHAN_BOND_SEQ_2_ENABLE = 4'b1111;
parameter CHAN_BOND_SEQ_2_USE = "FALSE";
parameter FTS_DESKEW_SEQ_ENABLE = 4'b1111;
parameter FTS_LANE_DESKEW_CFG = 4'b1111;
parameter FTS_LANE_DESKEW_EN = "FALSE";
parameter PCS_PCIE_EN = "FALSE";
// RX Gearbox Attributes, ug476 p.287
parameter RXGEARBOX_EN = "FALSE";
// ug476 table p.326 - undocumented parameters
parameter RX_CLK25_DIV = 6;
parameter TX_CLK25_DIV = 6;
wire reset = EYESCANRESET | RXCDRFREQRESET | RXCDRRESET | RXCDRRESETRSV | RXPRBSCNTRESET | RXBUFRESET | RXDLYSRESET | RXPHDLYRESET | RXDFELPMRESET | GTRXRESET | RXOOBRESET | RXPCSRESET | RXPMARESET | CFGRESET | GTTXRESET | GTRESETSEL | RESETOVRD | TXDLYSRESET | TXPHDLYRESET | TXPCSRESET | TXPMARESET;
reg rx_rst_done = 1'b0;
reg tx_rst_done = 1'b0;
assign RXRESETDONE = rx_rst_done;
assign TXRESETDONE = tx_rst_done;
initial
forever @ (posedge reset)
begin
tx_rst_done <= 1'b0;
@ (negedge reset);
repeat (80)
@ (posedge GTREFCLK0);
tx_rst_done <= 1'b1;
end
initial
forever @ (posedge reset)
begin
rx_rst_done <= 1'b0;
@ (negedge reset);
repeat (100)
@ (posedge GTREFCLK0);
rx_rst_done <= 1'b1;
end
gtxe2_chnl #(
.CPLL_CFG (CPLL_CFG),
.CPLL_FBDIV (CPLL_FBDIV),
.CPLL_FBDIV_45 (CPLL_FBDIV_45),
.CPLL_INIT_CFG (CPLL_INIT_CFG),
.CPLL_LOCK_CFG (CPLL_LOCK_CFG),
.CPLL_REFCLK_DIV (CPLL_REFCLK_DIV),
.RXOUT_DIV (RXOUT_DIV),
.TXOUT_DIV (TXOUT_DIV),
.SATA_CPLL_CFG (SATA_CPLL_CFG),
.PMA_RSV3 (PMA_RSV3),
.TXOUT_DIV (TXOUT_DIV),
// .TXRATE (TXRATE),
.RXOUT_DIV (RXOUT_DIV),
// .RXRATE (RXRATE),
.TX_INT_DATAWIDTH (TX_INT_DATAWIDTH),
.TX_DATA_WIDTH (TX_DATA_WIDTH),
.RX_DATA_WIDTH (RX_DATA_WIDTH),
.RX_INT_DATAWIDTH (RX_INT_DATAWIDTH),
.PRX8B10BEN (1),
.DEC_MCOMMA_DETECT (DEC_MCOMMA_DETECT),
.DEC_PCOMMA_DETECT (DEC_PCOMMA_DETECT),
.ALIGN_MCOMMA_VALUE (ALIGN_MCOMMA_VALUE),
.ALIGN_MCOMMA_DET (ALIGN_MCOMMA_DET),
.ALIGN_PCOMMA_VALUE (ALIGN_PCOMMA_VALUE),
.ALIGN_PCOMMA_DET (ALIGN_PCOMMA_DET),
.ALIGN_COMMA_ENABLE (ALIGN_COMMA_ENABLE),
.ALIGN_COMMA_DOUBLE (ALIGN_COMMA_DOUBLE),
.TX_DATA_WIDTH (TX_DATA_WIDTH),
.TX_INT_DATAWIDTH (TX_INT_DATAWIDTH),
.PTX8B10BEN (1),
.SATA_BURST_SEQ_LEN (SATA_BURST_SEQ_LEN),
.SATA_CPLL_CFG (SATA_CPLL_CFG)
)
channel(
.reset (reset),
.TXP (GTXTXP),
.TXN (GTXTXN),
.TXDATA (TXDATA),
.TXUSRCLK (TXUSRCLK),
.TXUSRCLK2 (TXUSRCLK2),
.TX8B10BBYPASS (TX8B10BBYPASS),
.TX8B10BEN (TX8B10BEN),
.TXCHARDISPMODE (TXCHARDISPMODE),
.TXCHARDISPVAL (TXCHARDISPVAL),
.TXCHARISK (TXCHARISK),
.TXBUFSTATUS (TXBUFSTATUS),
.TXPOLARITY (TXPOLARITY),
.TXRATE (TXRATE),
.RXRATE (RXRATE),
.TXRATEDONE (TXRATEDONE),
.TXCOMINIT (TXCOMINIT),
.TXCOMWAKE (TXCOMWAKE),
.TXCOMFINISH (TXCOMFINISH),
.TXELECIDLE (TXELECIDLE),
.RXP (GTXRXP),
.RXN (GTXRXN),
.RXUSRCLK (RXUSRCLK),
.RXUSRCLK2 (RXUSRCLK2),
.RXDATA (RXDATA),
.RXELECIDLEMODE (RXELECIDLEMODE),
.RXELECIDLE (RXELECIDLE),
.RXCOMINITDET (RXCOMINITDET),
.RXCOMWAKEDET (RXCOMWAKEDET),
.RXPOLARITY (RXPOLARITY),
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (RXBYTEREALIGN),
.RXCOMMADET (RXCOMMADET),
.RXCOMMADETEN (RXCOMMADETEN),
.RXPCOMMAALIGNEN (RXPCOMMAALIGNEN),
.RXMCOMMAALIGNEN (RXMCOMMAALIGNEN),
.RX8B10BEN (RX8B10BEN),
.RXCHARISCOMMA (RXCHARISCOMMA),
.RXCHARISK (RXCHARISK),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.GTGREFCLK (GTGREFCLK),
.QPLLCLK (QPLLCLK),
.QPLLREFCLK (QPLLREFCLK),
.RXSYSCLKSEL (RXSYSCLKSEL),
.TXSYSCLKSEL (TXSYSCLKSEL),
.TXOUTCLKSEL (TXOUTCLKSEL),
.RXOUTCLKSEL (RXOUTCLKSEL),
.TXDLYBYPASS (TXDLYBYPASS),
.GTREFCLKMONITOR (GTREFCLKMONITOR),
.CPLLLOCKDETCLK (CPLLLOCKDETCLK ),
.CPLLLOCKEN (CPLLLOCKEN),
.CPLLPD (CPLLPD),
.CPLLRESET (CPLLRESET),
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.TXOUTCLKPMA (TXOUTCLKPMA),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXOUTCLK (TXOUTCLK),
.TXOUTCLKFABRIC (TXOUTCLKFABRIC),
.tx_serial_clk (),
.RXOUTCLKPMA (RXOUTCLKPMA),
.RXOUTCLKPCS (RXOUTCLKPCS),
.RXOUTCLK (RXOUTCLK),
.RXOUTCLKFABRIC (RXOUTCLKFABRIC),
.rx_serial_clk ()
);
endmodule
/*******************************************************************************
* Module: clock_divider
* Date: 2015-07-06
* Author: Alexey
* Description: Non-sinthesizable clock divider
*
* Copyright (c) 2015 Elphel, Inc.
* clock_divider.v 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.
*
* clock_divider.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
/**
* Divides input clock either by input 'div' or by parameter 'divide_by' if divide_by_param
* was set to 1
**/
`ifndef CLOCK_DIVIDER_V
`define CLOCK_DIVIDER_V
// non synthesisable!
module clock_divider(
input wire clk_in,
output reg clk_out,
input wire [31:0] div
);
parameter divide_by = 1;
parameter divide_by_param = 1;
reg [31:0] cnt = 0;
reg [31:0] div_r;
initial
begin
cnt = 0;
clk_out = 1'b1;
forever
begin
if (divide_by_param == 0)
begin
if (div > 32'h0)
div_r = div;
else
div_r = 1;
repeat (div_r)
@ (clk_in);
end
else
begin
repeat (divide_by)
@ (clk_in);
end
clk_out = ~clk_out;
end
end
endmodule
`endif
/*******************************************************************************
* Module: gtxe2_chnl
* Date: 2015-07-06
* Author: Alexey
* Description: top-level module gtxe2_chnl = tx + rx + clocking
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl.v 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.
*
* gtxe2_chnl.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_chnl_clocking.v"
`include "gtxe2_chnl_tx.v"
`include "gtxe2_chnl_rx.v"
module gtxe2_chnl(
input wire reset,
/*
* TX
*/
output wire TXP,
output wire TXN,
input wire [63:0] TXDATA,
input wire TXUSRCLK,
input wire TXUSRCLK2,
// 8/10 encoder
input wire [7:0] TX8B10BBYPASS,
input wire TX8B10BEN,
input wire [7:0] TXCHARDISPMODE,
input wire [7:0] TXCHARDISPVAL,
input wire [7:0] TXCHARISK,
// TX Buffer
output wire [1:0] TXBUFSTATUS,
// TX Polarity
input wire TXPOLARITY,
// TX Fabric Clock Control
input wire [2:0] TXRATE,
output wire TXRATEDONE,
// TX OOB
input wire TXCOMINIT,
input wire TXCOMWAKE,
output wire TXCOMFINISH,
// TX Driver Control
input wire TXELECIDLE,
/*
* RX
*/
input wire RXP,
input wire RXN,
input wire RXUSRCLK,
input wire RXUSRCLK2,
output wire [63:0] RXDATA,
input wire [2:0] RXRATE,
// oob
input wire [1:0] RXELECIDLEMODE,
output wire RXELECIDLE,
output wire RXCOMINITDET,
output wire RXCOMWAKEDET,
// polarity
input wire RXPOLARITY,
// aligner
output wire RXBYTEISALIGNED,
output wire RXBYTEREALIGN,
output wire RXCOMMADET,
input wire RXCOMMADETEN,
input wire RXPCOMMAALIGNEN,
input wire RXMCOMMAALIGNEN,
// 10/8 decoder
input wire RX8B10BEN,
output wire [7:0] RXCHARISCOMMA,
output wire [7:0] RXCHARISK,
output wire [7:0] RXDISPERR,
output wire [7:0] RXNOTINTABLE,
/*
* Clocking
*/
// top-level interfaces
input wire [2:0] CPLLREFCLKSEL,
input wire GTREFCLK0,
input wire GTREFCLK1,
input wire GTNORTHREFCLK0,
input wire GTNORTHREFCLK1,
input wire GTSOUTHREFCLK0,
input wire GTSOUTHREFCLK1,
input wire GTGREFCLK,
input wire QPLLCLK,
input wire QPLLREFCLK,
input wire [1:0] RXSYSCLKSEL,
input wire [1:0] TXSYSCLKSEL,
input wire [2:0] TXOUTCLKSEL,
input wire [2:0] RXOUTCLKSEL,
input wire TXDLYBYPASS,
output wire GTREFCLKMONITOR,
input wire CPLLLOCKDETCLK,
input wire CPLLLOCKEN,
input wire CPLLPD,
input wire CPLLRESET,
output wire CPLLFBCLKLOST,
output wire CPLLLOCK,
output wire CPLLREFCLKLOST,
// phy-level interfaces
output wire TXOUTCLKPMA,
output wire TXOUTCLKPCS,
output wire TXOUTCLK,
output wire TXOUTCLKFABRIC,
output wire tx_serial_clk,
output wire RXOUTCLKPMA,
output wire RXOUTCLKPCS,
output wire RXOUTCLK,
output wire RXOUTCLKFABRIC,
output wire rx_serial_clk
);
parameter [23:0] CPLL_CFG = 29'h00BC07DC;
parameter integer CPLL_FBDIV = 4;
parameter integer CPLL_FBDIV_45 = 5;
parameter [23:0] CPLL_INIT_CFG = 24'h00001E;
parameter [15:0] CPLL_LOCK_CFG = 16'h01E8;
parameter integer CPLL_REFCLK_DIV = 1;
parameter [1:0] PMA_RSV3 = 1;
parameter TXOUT_DIV = 2;
//parameter TXRATE = 3'b000;
parameter RXOUT_DIV = 2;
//parameter RXRATE = 3'b000;
parameter integer TX_INT_DATAWIDTH = 0;
parameter integer TX_DATA_WIDTH = 20;
parameter integer PTX8B10BEN = 1;
parameter integer RX_DATA_WIDTH = 20;
parameter integer RX_INT_DATAWIDTH = 0;
parameter integer PRX8B10BEN = 1;
parameter DEC_MCOMMA_DETECT = "TRUE";
parameter DEC_PCOMMA_DETECT = "TRUE";
parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011;
parameter ALIGN_MCOMMA_DET = "TRUE";
parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100;
parameter ALIGN_PCOMMA_DET = "TRUE";
parameter [9:0] ALIGN_COMMA_ENABLE = 10'b1111111111;
parameter ALIGN_COMMA_DOUBLE = "FALSE";
parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
gtxe2_chnl_tx #(
.TX_DATA_WIDTH (TX_DATA_WIDTH),
.TX_INT_DATAWIDTH (TX_INT_DATAWIDTH),
.PTX8B10BEN (PTX8B10BEN),
.SATA_BURST_SEQ_LEN (SATA_BURST_SEQ_LEN),
.SATA_CPLL_CFG (SATA_CPLL_CFG)
)
tx(
.reset (reset),
.TXP (TXP),
.TXN (TXN),
.TXDATA (TXDATA),
.TXUSRCLK (TXUSRCLK),
.TXUSRCLK2 (TXUSRCLK2),
.TX8B10BBYPASS (TX8B10BBYPASS),
.TX8B10BEN (TX8B10BEN),
.TXCHARDISPMODE (TXCHARDISPMODE),
.TXCHARDISPVAL (TXCHARDISPVAL),
.TXCHARISK (TXCHARISK),
.TXBUFSTATUS (TXBUFSTATUS),
.TXPOLARITY (TXPOLARITY),
.TXRATE (TXRATE),
.TXRATEDONE (TXRATEDONE),
.TXCOMINIT (TXCOMINIT),
.TXCOMWAKE (TXCOMWAKE),
.TXCOMFINISH (TXCOMFINISH),
.TXELECIDLE (TXELECIDLE),
.serial_clk (tx_serial_clk)
);
gtxe2_chnl_rx #(
.RX_DATA_WIDTH (RX_DATA_WIDTH),
.RX_INT_DATAWIDTH (RX_INT_DATAWIDTH),
.PRX8B10BEN (PRX8B10BEN),
.DEC_MCOMMA_DETECT (DEC_MCOMMA_DETECT),
.DEC_PCOMMA_DETECT (DEC_PCOMMA_DETECT),
.ALIGN_MCOMMA_VALUE (ALIGN_MCOMMA_VALUE),
.ALIGN_MCOMMA_DET (ALIGN_MCOMMA_DET),
.ALIGN_PCOMMA_VALUE (ALIGN_PCOMMA_VALUE),
.ALIGN_PCOMMA_DET (ALIGN_PCOMMA_DET),
.ALIGN_COMMA_ENABLE (ALIGN_COMMA_ENABLE),
.ALIGN_COMMA_DOUBLE (ALIGN_COMMA_DOUBLE)
)
rx(
.reset (reset),
.RXP (RXP),
.RXN (RXN),
.RXUSRCLK (RXUSRCLK),
.RXUSRCLK2 (RXUSRCLK2),
.RXDATA (RXDATA),
.RXELECIDLEMODE (RXELECIDLEMODE),
.RXELECIDLE (RXELECIDLE),
.RXCOMINITDET (RXCOMINITDET),
.RXCOMWAKEDET (RXCOMWAKEDET),
.RXPOLARITY (RXPOLARITY),
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (RXBYTEREALIGN),
.RXCOMMADET (RXCOMMADET),
.RXCOMMADETEN (RXCOMMADETEN),
.RXPCOMMAALIGNEN (RXPCOMMAALIGNEN),
.RXMCOMMAALIGNEN (RXMCOMMAALIGNEN),
.RX8B10BEN (RX8B10BEN),
.RXCHARISCOMMA (RXCHARISCOMMA),
.RXCHARISK (RXCHARISK),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.serial_clk (rx_serial_clk)
);
gtxe2_chnl_clocking #(
.CPLL_CFG (CPLL_CFG),
.CPLL_FBDIV (CPLL_FBDIV),
.CPLL_FBDIV_45 (CPLL_FBDIV_45),
.CPLL_INIT_CFG (CPLL_INIT_CFG),
.CPLL_LOCK_CFG (CPLL_LOCK_CFG),
.CPLL_REFCLK_DIV (CPLL_REFCLK_DIV),
.RXOUT_DIV (RXOUT_DIV),
.TXOUT_DIV (TXOUT_DIV),
.SATA_CPLL_CFG (SATA_CPLL_CFG),
.PMA_RSV3 (PMA_RSV3),
.TXOUT_DIV (TXOUT_DIV),
// .TXRATE (TXRATE),
.RXOUT_DIV (RXOUT_DIV),
// .RXRATE (RXRATE),
.TX_INT_DATAWIDTH (TX_INT_DATAWIDTH),
.TX_DATA_WIDTH (TX_DATA_WIDTH),
.RX_INT_DATAWIDTH (RX_INT_DATAWIDTH),
.RX_DATA_WIDTH (RX_DATA_WIDTH)
)
clocking(
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.GTGREFCLK (GTGREFCLK),
.QPLLCLK (QPLLCLK),
.QPLLREFCLK (QPLLREFCLK ),
.RXSYSCLKSEL (RXSYSCLKSEL),
.TXSYSCLKSEL (TXSYSCLKSEL),
.TXOUTCLKSEL (TXOUTCLKSEL),
.RXOUTCLKSEL (RXOUTCLKSEL),
.TXDLYBYPASS (TXDLYBYPASS),
.GTREFCLKMONITOR (GTREFCLKMONITOR),
.CPLLLOCKDETCLK (CPLLLOCKDETCLK),
.CPLLLOCKEN (CPLLLOCKEN),
.CPLLPD (CPLLPD),
.CPLLRESET (CPLLRESET),
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.TXRATE (TXRATE),
.RXRATE (RXRATE),
.TXOUTCLKPMA (TXOUTCLKPMA),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXOUTCLK (TXOUTCLK),
.TXOUTCLKFABRIC (TXOUTCLKFABRIC),
.tx_serial_clk (tx_serial_clk),
.RXOUTCLKPMA (RXOUTCLKPMA),
.RXOUTCLKPCS (RXOUTCLKPCS),
.RXOUTCLK (RXOUTCLK),
.RXOUTCLKFABRIC (RXOUTCLKFABRIC),
.rx_serial_clk (rx_serial_clk)
);
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_clocking
* Date: 2015-07-06
* Author: Alexey
* Description: channel's clocking top-level. Places muxes, plls, dividers,
* as they're depicted @ xilinx's ug476 p.36, p.46, p. 150, p. 211
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_clocking.v 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.
*
* gtxe2_chnl_clocking.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_chnl_cpll_inmux.v"
`include "gtxe2_chnl_outclk_mux.v"
`include "gtxe2_chnl_cpll.v"
`include "clock_divider.v"
module gtxe2_chnl_clocking(
// top-level interfaces
input wire [2:0] CPLLREFCLKSEL,
input wire GTREFCLK0,
input wire GTREFCLK1,
input wire GTNORTHREFCLK0,
input wire GTNORTHREFCLK1,
input wire GTSOUTHREFCLK0,
input wire GTSOUTHREFCLK1,
input wire GTGREFCLK,
input wire QPLLCLK,
input wire QPLLREFCLK,
input wire [1:0] RXSYSCLKSEL,
input wire [1:0] TXSYSCLKSEL,
input wire [2:0] TXOUTCLKSEL,
input wire [2:0] RXOUTCLKSEL,
input wire TXDLYBYPASS,
output wire GTREFCLKMONITOR,
input wire CPLLLOCKDETCLK,
input wire CPLLLOCKEN,
input wire CPLLPD,
input wire CPLLRESET,
output wire CPLLFBCLKLOST,
output wire CPLLLOCK,
output wire CPLLREFCLKLOST,
input wire [2:0] TXRATE,
input wire [2:0] RXRATE,
// phy-level interfaces
output wire TXOUTCLKPMA,
output wire TXOUTCLKPCS,
output wire TXOUTCLK,
output wire TXOUTCLKFABRIC,
output wire tx_serial_clk,
output wire tx_piso_clk,
output wire RXOUTCLKPMA,
output wire RXOUTCLKPCS,
output wire RXOUTCLK,
output wire RXOUTCLKFABRIC,
output wire rx_serial_clk,
output wire tx_sipo_clk
);
// CPLL
parameter [23:0] CPLL_CFG = 29'h00BC07DC;
parameter integer CPLL_FBDIV = 4;
parameter integer CPLL_FBDIV_45 = 5;
parameter [23:0] CPLL_INIT_CFG = 24'h00001E;
parameter [15:0] CPLL_LOCK_CFG = 16'h01E8;
parameter integer CPLL_REFCLK_DIV = 1;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
parameter [1:0] PMA_RSV3 = 1;
parameter TXOUT_DIV = 2;
//parameter TXRATE = 3'b000;
parameter RXOUT_DIV = 2;
//parameter RXRATE = 3'b000;
parameter TX_INT_DATAWIDTH = 0;
parameter TX_DATA_WIDTH = 20;
parameter RX_INT_DATAWIDTH = 0;
parameter RX_DATA_WIDTH = 20;
/*
localparam tx_serial_divider = TXRATE == 3'b001 ? 1
: TXRATE == 3'b010 ? 2
: TXRATE == 3'b011 ? 4
: TXRATE == 3'b100 ? 8
: TXRATE == 3'b101 ? 16 : TXOUT_DIV ;
localparam rx_serial_divider = RXRATE == 3'b001 ? 1
: RXRATE == 3'b010 ? 2
: RXRATE == 3'b011 ? 4
: RXRATE == 3'b100 ? 8
: RXRATE == 3'b101 ? 16 : RXOUT_DIV ;
*/
localparam tx_pma_divider1 = TX_INT_DATAWIDTH == 1 ? 4 : 2;
localparam tx_pcs_divider1 = tx_pma_divider1;
localparam tx_pma_divider2 = TX_DATA_WIDTH == 20 | TX_DATA_WIDTH == 40 | TX_DATA_WIDTH == 80 ? 5 : 4;
localparam tx_pcs_divider2 = tx_pma_divider2;
localparam rx_pma_divider1 = RX_INT_DATAWIDTH == 1 ? 4 : 2;
localparam rx_pma_divider2 = RX_DATA_WIDTH == 20 | RX_DATA_WIDTH == 40 | RX_DATA_WIDTH == 80 ? 5 : 4;
wire clk_mux_out;
wire cpll_clk_out;
wire tx_phy_clk;
wire rx_phy_clk;
wire TXPLLREFCLK_DIV1;
wire TXPLLREFCLK_DIV2;
wire RXPLLREFCLK_DIV1;
wire RXPLLREFCLK_DIV2;
assign tx_phy_clk = TXSYSCLKSEL[0] ? QPLLCLK : cpll_clk_out;
assign TXPLLREFCLK_DIV1 = TXSYSCLKSEL[1] ? QPLLREFCLK : clk_mux_out;
assign rx_phy_clk = RXSYSCLKSEL[0] ? QPLLCLK : cpll_clk_out;
assign RXPLLREFCLK_DIV1 = RXSYSCLKSEL[1] ? QPLLREFCLK : clk_mux_out;
assign tx_serial_clk = tx_phy_clk;
assign rx_serial_clk = rx_phy_clk;
// piso and sipo clocks
// are not used in the design - no need to use ddr mode during simulation. much easier just multi serial clk by 2
wire [31:0] tx_serial_divider;
wire [31:0] rx_serial_divider;
assign tx_serial_divider = TXRATE == 3'b001 ? 1
: TXRATE == 3'b010 ? 2
: TXRATE == 3'b011 ? 4
: TXRATE == 3'b100 ? 8
: TXRATE == 3'b101 ? 16 : TXOUT_DIV ;
assign rx_serial_divider = RXRATE == 3'b001 ? 1
: RXRATE == 3'b010 ? 2
: RXRATE == 3'b011 ? 4
: RXRATE == 3'b100 ? 8
: RXRATE == 3'b101 ? 16 : RXOUT_DIV ;
clock_divider #(
// .divide_by (tx_serial_divider),
.divide_by_param (0)
)
tx_toserialclk_div(
.clk_in (tx_phy_clk),
.clk_out (tx_piso_clk),
.div (tx_serial_divider)
);
clock_divider #(
// .divide_by (rx_serial_divider),
.divide_by_param (0)
)
rx_toserialclk_div(
.clk_in (rx_phy_clk),
.clk_out (rx_sipo_clk),
.div (rx_serial_divider)
);
// TXOUTCLKPCS/TXOUTCLKPMA generation
wire tx_pma_div1_clk;
assign TXOUTCLKPCS = TXOUTCLKPMA;
clock_divider #(
.divide_by (tx_pma_divider1)
)
tx_pma_div1(
.clk_in (tx_piso_clk),
.clk_out (tx_pma_div1_clk)
);
clock_divider #(
.divide_by (tx_pma_divider2)
)
tx_pma_div2(
.clk_in (tx_pma_div1_clk),
.clk_out (TXOUTCLKPMA)
);
// RXOUTCLKPCS/RXOUTCLKPMA generation
wire rx_pma_div1_clk;
assign RXOUTCLKPCS = RXOUTCLKPMA;
clock_divider #(
.divide_by (rx_pma_divider1)
)
rx_pma_div1(
.clk_in (rx_sipo_clk),
.clk_out (rx_pma_div1_clk)
);
clock_divider #(
.divide_by (rx_pma_divider2)
)
rx_pma_div2(
.clk_in (rx_pma_div1_clk),
.clk_out (RXOUTCLKPMA)
);
//
clock_divider #(
.divide_by (2)
)
txpllrefclk_div2(
.clk_in (TXPLLREFCLK_DIV1),
.clk_out (TXPLLREFCLK_DIV2)
);
clock_divider #(
.divide_by (2)
)
rxpllrefclk_div2(
.clk_in (RXPLLREFCLK_DIV1),
.clk_out (RXPLLREFCLK_DIV2)
);
gtxe2_chnl_outclk_mux tx_out_mux(
.TXPLLREFCLK_DIV1 (TXPLLREFCLK_DIV1),
.TXPLLREFCLK_DIV2 (TXPLLREFCLK_DIV2),
.TXOUTCLKPMA (TXOUTCLKPMA),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXOUTCLKSEL (TXOUTCLKSEL),
.TXDLYBYPASS (TXDLYBYPASS),
.TXOUTCLK (TXOUTCLK)
);
gtxe2_chnl_outclk_mux rx_out_mux(
.TXPLLREFCLK_DIV1 (RXPLLREFCLK_DIV1),
.TXPLLREFCLK_DIV2 (RXPLLREFCLK_DIV2),
.TXOUTCLKPMA (RXOUTCLKPMA),
.TXOUTCLKPCS (RXOUTCLKPCS),
.TXOUTCLKSEL (RXOUTCLKSEL),
.TXDLYBYPASS (RXDLYBYPASS),
.TXOUTCLK (RXOUTCLK)
);
gtxe2_chnl_cpll_inmux clk_mux(
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.GTGREFCLK (GTGREFCLK),
.CPLL_MUX_CLK_OUT (clk_mux_out)
);
gtxe2_chnl_cpll #(
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_REFCLK_DIV (1)
)
cpll(
.CPLLLOCKDETCLK (CPLLLOCKDETCLK),
.CPLLLOCKEN (CPLLLOCKEN),
.CPLLPD (CPLLPD),
.CPLLRESET (CPLLRESET),
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.GTRSVD (GTRSVD),
.PCSRSVDIN (PCSRSVDIN),
.PCSRSVDIN2 (PCSRSVDIN2),
.PMARSVDIN (PMARSVDIN),
.PMARSVDIN2 (PMARSVDIN2),
.TSTIN (TSTIN),
.TSTOUT (TSTOUT),
.ref_clk (clk_mux_out),
.clk_out (cpll_clk_out),
.pll_locked (pll_locked)
);
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_cpll
* Date: 2015-07-06
* Author: Alexey
* Description: non-synthesizable pll implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_cpll.v 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.
*
* gtxe2_chnl_cpll.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_chnl_cpll_def.v"
module gtxe2_chnl_cpll(
// top-level interfaces
input wire CPLLLOCKDETCLK,
input wire CPLLLOCKEN,
input wire CPLLPD,
input wire CPLLRESET, // active high
output wire CPLLFBCLKLOST,
output wire CPLLLOCK,
output wire CPLLREFCLKLOST,
input wire GTRSVD,
input wire PCSRSVDIN,
input wire PCSRSVDIN2,
input wire PMARSVDIN,
input wire PMARSVDIN2,
input wire TSTIN,
output wire TSTOUT,
// internal
input wire ref_clk,
output wire clk_out,
output wire pll_locked // equals CPLLLOCK
);
parameter [23:0] CPLL_CFG = 29'h00BC07DC;
parameter integer CPLL_FBDIV = 4;
parameter integer CPLL_FBDIV_45 = 5;
parameter [23:0] CPLL_INIT_CFG = 24'h00001E;
parameter [15:0] CPLL_LOCK_CFG = 16'h01E8;
parameter integer CPLL_REFCLK_DIV = 1;
parameter integer RXOUT_DIV = 2;
parameter integer TXOUT_DIV = 2;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
parameter [1:0] PMA_RSV3 = 1;
localparam multiplier = CPLL_FBDIV * CPLL_FBDIV_45;
localparam divider = CPLL_REFCLK_DIV;
assign pll_locked = locked;
assign CPLLLOCK = pll_locked;
wire fb_clk_out;
wire reset;
reg mult_clk;
reg mult_dev_clk;
assign clk_out = mult_dev_clk;
// generate internal async reset
assign reset = CPLLPD | CPLLRESET;
// apply multipliers
time last_edge; // reference clock edge's absolute time
time period; // reference clock's period
integer locked_f;
reg locked;
initial
begin
last_edge = 0;
period = 0;
forever @ (posedge ref_clk or posedge reset)
begin
period = reset ? 0 : $time - (last_edge == 0 ? $time : last_edge);
last_edge = reset ? 0 : $time;
end
end
reg tmp = 0;
initial
begin
@ (posedge reset);
forever @ (posedge ref_clk)
begin
tmp = ~tmp;
if (period > 0)
begin
locked_f = 1;
mult_clk = 1'b1;
repeat (multiplier * 2 - 1)
begin
#(period/multiplier/2)
mult_clk = ~mult_clk;
end
end
else
locked_f = 0;
end
end
// apply dividers
initial
begin
mult_dev_clk = 1'b1;
forever
begin
repeat (divider)
@ (mult_clk);
mult_dev_clk = ~mult_dev_clk;
end
end
// show if 'pll' is locked
reg [31:0] counter;
always @ (posedge ref_clk or posedge reset)
counter <= reset | locked_f == 0 ? 0 : counter == `GTXE2_CHNL_CPLL_LOCK_TIME ? counter : counter + 1;
always @ (posedge ref_clk)
locked <= counter == `GTXE2_CHNL_CPLL_LOCK_TIME;
/*
always @ (posedge ref_clk or posedge reset)
begin
if (locked_f == 1 && ~reset)
begin
repeat (`GTXE2_CHNL_CPLL_LOCK_TIME) @ (posedge ref_clk);
locked <= 1'b1;
end
else
locked <= 1'b0;
end*/
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_cpll_inmux
* Date: 2015-07-06
* Author: Alexey
* Description: non-sinthesizable clock multiplexer, used in clocking scheme
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_cpll_inmux.v 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.
*
* gtxe2_chnl_cpll_inmux.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
// cpll reference clock mux
module gtxe2_chnl_cpll_inmux(
input wire [2:0] CPLLREFCLKSEL,
input wire GTREFCLK0,
input wire GTREFCLK1,
input wire GTNORTHREFCLK0,
input wire GTNORTHREFCLK1,
input wire GTSOUTHREFCLK0,
input wire GTSOUTHREFCLK1,
input wire GTGREFCLK,
output wire CPLL_MUX_CLK_OUT
);
// clock multiplexer - pre-syntesis simulation only
assign CPLL_MUX_CLK_OUT = CPLLREFCLKSEL == 3'b000 ? 1'b0 // reserved
: CPLLREFCLKSEL == 3'b001 ? GTREFCLK0
: CPLLREFCLKSEL == 3'b010 ? GTREFCLK1
: CPLLREFCLKSEL == 3'b011 ? GTNORTHREFCLK0
: CPLLREFCLKSEL == 3'b100 ? GTNORTHREFCLK1
: CPLLREFCLKSEL == 3'b101 ? GTSOUTHREFCLK0
: CPLLREFCLKSEL == 3'b110 ? GTSOUTHREFCLK1
: /*CPLLREFCLKSEL == 3'b111 ?*/ GTGREFCLK;
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_cpll_outmux
* Date: 2015-07-06
* Author: Alexey
* Description: non-sinthesizable clock multiplexer, used in clocking scheme
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_cpll_outmux.v 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.
*
* gtxe2_chnl_cpll_outmux.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
module gtxe2_chnl_outclk_mux(
input wire TXPLLREFCLK_DIV1,
input wire TXPLLREFCLK_DIV2,
input wire TXOUTCLKPMA,
input wire TXOUTCLKPCS,
input wire [2:0] TXOUTCLKSEL,
input wire TXDLYBYPASS,
output wire TXOUTCLK
);
assign TXOUTCLK = TXOUTCLKSEL == 3'b001 ? TXOUTCLKPCS
: TXOUTCLKSEL == 3'b010 ? TXOUTCLKPMA
: TXOUTCLKSEL == 3'b011 ? TXPLLREFCLK_DIV1
: TXOUTCLKSEL == 3'b100 ? TXPLLREFCLK_DIV2
: /* 3'b000 */ 1'b1;
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_rx
* Date: 2015-07-06
* Author: Alexey
* Description: reciever top-level. Also includes polarity-inversion logic
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_rx.v 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.
*
* gtxe2_chnl_rx.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
/**
* For now contains only deserializer, oob, 10x8 decoder, aligner and polarity invertor blocks
**/
`include "gtxe2_chnl_rx_des.v"
`include "gtxe2_chnl_rx_oob.v"
`include "gtxe2_chnl_rx_10x8dec.v"
`include "gtxe2_chnl_rx_align.v"
module gtxe2_chnl_rx(
input wire reset,
input wire RXP,
input wire RXN,
input wire RXUSRCLK,
input wire RXUSRCLK2,
output wire [63:0] RXDATA,
// oob
input wire [1:0] RXELECIDLEMODE,
output wire RXELECIDLE,
output wire RXCOMINITDET,
output wire RXCOMWAKEDET,
// polarity
input wire RXPOLARITY,
// aligner
output wire RXBYTEISALIGNED,
output wire RXBYTEREALIGN,
output wire RXCOMMADET,
input wire RXCOMMADETEN,
input wire RXPCOMMAALIGNEN,
input wire RXMCOMMAALIGNEN,
// 10/8 decoder
input wire RX8B10BEN,
output wire [7:0] RXCHARISCOMMA,
output wire [7:0] RXCHARISK,
output wire [7:0] RXDISPERR,
output wire [7:0] RXNOTINTABLE,
// internal
input wire serial_clk
);
parameter integer RX_DATA_WIDTH = 20;
parameter integer RX_INT_DATAWIDTH = 0;
parameter integer PRX8B10BEN = 1;
parameter DEC_MCOMMA_DETECT = "TRUE";
parameter DEC_PCOMMA_DETECT = "TRUE";
parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011;
parameter ALIGN_MCOMMA_DET = "TRUE";
parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100;
parameter ALIGN_PCOMMA_DET = "TRUE";
parameter [9:0] ALIGN_COMMA_ENABLE = 10'b1111111111;
parameter ALIGN_COMMA_DOUBLE = "FALSE";
function integer calc_idw;
input RX8B10BEN;
input RX_INT_DATAWIDTH;
input RX_DATA_WIDTH;
begin
if (RX8B10BEN == 1)
calc_idw = RX_INT_DATAWIDTH == 1 ? 40 : 20;
else
begin
if (RX_INT_DATAWIDTH == 1)
calc_idw = RX_DATA_WIDTH == 32 ? 32
: RX_DATA_WIDTH == 40 ? 40
: RX_DATA_WIDTH == 64 ? 32 : 40;
else
calc_idw = RX_DATA_WIDTH == 16 ? 16
: RX_DATA_WIDTH == 20 ? 20
: RX_DATA_WIDTH == 32 ? 16 : 20;
end
end
endfunction
localparam internal_data_width = calc_idw(PRX8B10BEN, RX_INT_DATAWIDTH, RX_DATA_WIDTH);
// OOB
gtxe2_chnl_rx_oob #(
.width (internal_data_width)
)
rx_oob(
.reset (reset),
.clk (serial_clk),
.RXN (RXN),
.RXP (RXP),
.RXELECIDLEMODE (RXELECIDLEMODE),
.RXELECIDLE (RXELECIDLE),
.RXCOMINITDET (RXCOMINITDET),
.RXCOMWAKEDET (RXCOMWAKEDET)
);
// Polarity
// no need to invert data after a deserializer, no need to resync or make a buffer trigger for simulation
wire indata_ser;
assign indata_ser = RXPOLARITY ^ RXP;
// due to non-syntasisable usage, CDR is missing
// deserializer
wire [internal_data_width - 1:0] parallel_data;
gtxe2_chnl_rx_des #(
.width (internal_data_width)
)
des(
.reset (reset),
.inclk (serial_clk),
.outclk (RXUSRCLK),
.indata (indata_ser),
.outdata (parallel_data)
);
// aligner
wire [internal_data_width - 1:0] aligned_data;
gtxe2_chnl_rx_align #(
.width (internal_data_width),
.ALIGN_MCOMMA_VALUE (ALIGN_MCOMMA_VALUE),
.ALIGN_MCOMMA_DET (ALIGN_MCOMMA_DET),
.ALIGN_PCOMMA_VALUE (ALIGN_PCOMMA_VALUE),
.ALIGN_PCOMMA_DET (ALIGN_PCOMMA_DET),
.ALIGN_COMMA_ENABLE (ALIGN_COMMA_ENABLE),
.ALIGN_COMMA_DOUBLE (ALIGN_COMMA_DOUBLE)
)
aligner(
.clk (RXUSRCLK),
.rst (reset),
.indata (parallel_data),
.outdata (aligned_data),
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (RXBYTEREALIGN),
.RXCOMMADET (RXCOMMADET),
.RXCOMMADETEN (RXCOMMADETEN),
.RXPCOMMAALIGNEN (RXPCOMMAALIGNEN),
.RXMCOMMAALIGNEN (RXMCOMMAALIGNEN)
);
// 10x8 decoder
gtxe2_chnl_rx_10x8dec #(
.iwidth (internal_data_width),
.owidth (RX_DATA_WIDTH),
.DEC_MCOMMA_DETECT (DEC_MCOMMA_DETECT),
.DEC_PCOMMA_DETECT (DEC_PCOMMA_DETECT)
)
decoder_10x8(
.clk (RXUSRCLK),
.rst (reset),
.indata (aligned_data),
.RX8B10BEN (RX8B10BEN),
.RXCHARISCOMMA (RXCHARISCOMMA),
.RXCHARISK (RXCHARISK),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.outdata (),
.RXDATA (RXDATA)
);
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_rx_10x8dec
* Date: 2015-07-06
* Author: Alexey
* Description: 10x8 decoder implementation, has reduced parameterization abilities
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_rx_10x8dec.v 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.
*
* gtxe2_chnl_rx_10x8dec.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
// always enabled, wasnt tested with width parameters, disctinct from 20
module gtxe2_chnl_rx_10x8dec #(
parameter iwidth = 20,
parameter owidth = 20,
parameter DEC_MCOMMA_DETECT = "TRUE",
parameter DEC_PCOMMA_DETECT = "TRUE"
)
(
input wire clk,
input wire rst,
input wire [iwidth - 1:0] indata,
input wire RX8B10BEN,
output wire [7:0] RXCHARISCOMMA,
output wire [7:0] RXCHARISK,
output wire [7:0] RXDISPERR,
output wire [7:0] RXNOTINTABLE,
output wire [owidth - 1:0] outdata,
output wire [63:0] RXDATA
);
localparam word_count = iwidth / 10;
localparam add_2out_bits = owidth == 20 | owidth == 40 | owidth == 80 ? "TRUE" : "FALSE";
wire [iwidth - 2 * word_count - 1:0] pure_data;
wire [iwidth - 1:0] data;
wire [word_count - 1:0] disp; //consecutive disparity calculations;
wire [word_count - 1:0] disp_word; // 0 - negative, 1 - positive
wire [word_count - 1:0] no_disp_word; // ignore disp_word, '1's and '0's have equal count
wire [word_count - 1:0] disp_err;
reg disp_init; // disparity after last clock's portion of data
always @ (posedge clk)
disp_init <= rst ? 1'b0 : disp[word_count - 1];
genvar ii;
generate
for (ii = 0; ii < word_count; ii = ii + 1)
begin: asdf
//data = {1'(is in table) + 3'(decoded 4/3) + 1'(is in table) + 5'(decoded 6/5)}
//6/5 decoding
assign data[ii*10+5:ii*10] = RXCHARISK[ii] ? (
indata[ii*10 + 9:ii*10] == 10'b0010111100 | indata[ii*10 + 9:ii*10] == 10'b1101000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b1001111100 | indata[ii*10 + 9:ii*10] == 10'b0110000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b1010111100 | indata[ii*10 + 9:ii*10] == 10'b0101000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b1100111100 | indata[ii*10 + 9:ii*10] == 10'b0011000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b0100111100 | indata[ii*10 + 9:ii*10] == 10'b1011000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b0101111100 | indata[ii*10 + 9:ii*10] == 10'b1010000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b0110111100 | indata[ii*10 + 9:ii*10] == 10'b1001000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b0001111100 | indata[ii*10 + 9:ii*10] == 10'b1110000011 ? 6'b011100 :
indata[ii*10 + 9:ii*10] == 10'b0001010111 | indata[ii*10 + 9:ii*10] == 10'b1110101000 ? 6'b010111 :
indata[ii*10 + 9:ii*10] == 10'b0001011011 | indata[ii*10 + 9:ii*10] == 10'b1110100100 ? 6'b011011 :
indata[ii*10 + 9:ii*10] == 10'b0001011101 | indata[ii*10 + 9:ii*10] == 10'b1110100010 ? 6'b011101 :
indata[ii*10 + 9:ii*10] == 10'b0001011110 | indata[ii*10 + 9:ii*10] == 10'b1110100001 ? 6'b011110 :
6'b100000)
:
(indata[ii*10 + 5:ii*10] == 6'b111001 | indata[ii*10 + 5:ii*10] == 6'b000110 ? 6'b000000 :// Data VVV
indata[ii*10 + 5:ii*10] == 6'b101110 | indata[ii*10 + 5:ii*10] == 6'b010001 ? 6'b000001 :
indata[ii*10 + 5:ii*10] == 6'b101101 | indata[ii*10 + 5:ii*10] == 6'b010010 ? 6'b000010 :
indata[ii*10 + 5:ii*10] == 6'b100011 | indata[ii*10 + 5:ii*10] == 6'b100011 ? 6'b000011 :
indata[ii*10 + 5:ii*10] == 6'b101011 | indata[ii*10 + 5:ii*10] == 6'b010100 ? 6'b000100 :
indata[ii*10 + 5:ii*10] == 6'b100101 | indata[ii*10 + 5:ii*10] == 6'b100101 ? 6'b000101 :
indata[ii*10 + 5:ii*10] == 6'b100110 | indata[ii*10 + 5:ii*10] == 6'b100110 ? 6'b000110 :
indata[ii*10 + 5:ii*10] == 6'b000111 | indata[ii*10 + 5:ii*10] == 6'b111000 ? 6'b000111 :
indata[ii*10 + 5:ii*10] == 6'b100111 | indata[ii*10 + 5:ii*10] == 6'b011000 ? 6'b001000 :
indata[ii*10 + 5:ii*10] == 6'b101001 | indata[ii*10 + 5:ii*10] == 6'b101001 ? 6'b001001 :
indata[ii*10 + 5:ii*10] == 6'b101010 | indata[ii*10 + 5:ii*10] == 6'b101010 ? 6'b001010 :
indata[ii*10 + 5:ii*10] == 6'b001011 | indata[ii*10 + 5:ii*10] == 6'b001011 ? 6'b001011 :
indata[ii*10 + 5:ii*10] == 6'b101100 | indata[ii*10 + 5:ii*10] == 6'b101100 ? 6'b001100 :
indata[ii*10 + 5:ii*10] == 6'b001101 | indata[ii*10 + 5:ii*10] == 6'b001101 ? 6'b001101 :
indata[ii*10 + 5:ii*10] == 6'b001110 | indata[ii*10 + 5:ii*10] == 6'b001110 ? 6'b001110 :
indata[ii*10 + 5:ii*10] == 6'b111010 | indata[ii*10 + 5:ii*10] == 6'b000101 ? 6'b001111 :
indata[ii*10 + 5:ii*10] == 6'b110110 | indata[ii*10 + 5:ii*10] == 6'b001001 ? 6'b010000 :
indata[ii*10 + 5:ii*10] == 6'b110001 | indata[ii*10 + 5:ii*10] == 6'b110001 ? 6'b010001 :
indata[ii*10 + 5:ii*10] == 6'b110010 | indata[ii*10 + 5:ii*10] == 6'b110010 ? 6'b010010 :
indata[ii*10 + 5:ii*10] == 6'b010011 | indata[ii*10 + 5:ii*10] == 6'b010011 ? 6'b010011 :
indata[ii*10 + 5:ii*10] == 6'b110100 | indata[ii*10 + 5:ii*10] == 6'b110100 ? 6'b010100 :
indata[ii*10 + 5:ii*10] == 6'b010101 | indata[ii*10 + 5:ii*10] == 6'b010101 ? 6'b010101 :
indata[ii*10 + 5:ii*10] == 6'b010110 | indata[ii*10 + 5:ii*10] == 6'b010110 ? 6'b010110 :
indata[ii*10 + 5:ii*10] == 6'b010111 | indata[ii*10 + 5:ii*10] == 6'b101000 ? 6'b010111 :
indata[ii*10 + 5:ii*10] == 6'b110011 | indata[ii*10 + 5:ii*10] == 6'b001100 ? 6'b011000 :
indata[ii*10 + 5:ii*10] == 6'b011001 | indata[ii*10 + 5:ii*10] == 6'b011001 ? 6'b011001 :
indata[ii*10 + 5:ii*10] == 6'b011010 | indata[ii*10 + 5:ii*10] == 6'b011010 ? 6'b011010 :
indata[ii*10 + 5:ii*10] == 6'b011011 | indata[ii*10 + 5:ii*10] == 6'b100100 ? 6'b011011 :
indata[ii*10 + 5:ii*10] == 6'b011100 | indata[ii*10 + 5:ii*10] == 6'b011100 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b011101 | indata[ii*10 + 5:ii*10] == 6'b100010 ? 6'b011101 :
indata[ii*10 + 5:ii*10] == 6'b011110 | indata[ii*10 + 5:ii*10] == 6'b100001 ? 6'b011110 :
indata[ii*10 + 5:ii*10] == 6'b110101 | indata[ii*10 + 5:ii*10] == 6'b001010 ? 6'b011111 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :// Controls VVV
/* indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b111100 | indata[ii*10 + 5:ii*10] == 6'b000011 ? 6'b011100 :
indata[ii*10 + 5:ii*10] == 6'b010111 | indata[ii*10 + 5:ii*10] == 6'b101000 ? 6'b010111 :
indata[ii*10 + 5:ii*10] == 6'b011011 | indata[ii*10 + 5:ii*10] == 6'b100100 ? 6'b011011 :
indata[ii*10 + 5:ii*10] == 6'b011101 | indata[ii*10 + 5:ii*10] == 6'b100010 ? 6'b011101 :
indata[ii*10 + 5:ii*10] == 6'b011110 | indata[ii*10 + 5:ii*10] == 6'b100001 ? 6'b011110 :*/
6'b100000); // not in a table
//4/3 decoding
assign data[ii*10+ 9:ii*10+ 6] = RXCHARISK[ii] ? (
indata[ii*10 + 9:ii*10] == 10'b0010111100 | indata[ii*10 + 9:ii*10] == 10'b1101000011 ? 4'b0000 :
indata[ii*10 + 9:ii*10] == 10'b1001111100 | indata[ii*10 + 9:ii*10] == 10'b0110000011 ? 4'b0001 :
indata[ii*10 + 9:ii*10] == 10'b1010111100 | indata[ii*10 + 9:ii*10] == 10'b0101000011 ? 4'b0010 :
indata[ii*10 + 9:ii*10] == 10'b1100111100 | indata[ii*10 + 9:ii*10] == 10'b0011000011 ? 4'b0011 :
indata[ii*10 + 9:ii*10] == 10'b0100111100 | indata[ii*10 + 9:ii*10] == 10'b1011000011 ? 4'b0100 :
indata[ii*10 + 9:ii*10] == 10'b0101111100 | indata[ii*10 + 9:ii*10] == 10'b1010000011 ? 4'b0101 :
indata[ii*10 + 9:ii*10] == 10'b0110111100 | indata[ii*10 + 9:ii*10] == 10'b1001000011 ? 4'b0110 :
indata[ii*10 + 9:ii*10] == 10'b0001111100 | indata[ii*10 + 9:ii*10] == 10'b1110000011 ? 4'b0111 :
indata[ii*10 + 9:ii*10] == 10'b0001010111 | indata[ii*10 + 9:ii*10] == 10'b1110101000 ? 4'b0111 :
indata[ii*10 + 9:ii*10] == 10'b0001011011 | indata[ii*10 + 9:ii*10] == 10'b1110100100 ? 4'b0111 :
indata[ii*10 + 9:ii*10] == 10'b0001011101 | indata[ii*10 + 9:ii*10] == 10'b1110100010 ? 4'b0111 :
indata[ii*10 + 9:ii*10] == 10'b0001011110 | indata[ii*10 + 9:ii*10] == 10'b1110100001 ? 4'b0111 :
4'b1000)
:
(indata[ii*10 + 9:ii*10 + 6] == 4'b1101 | indata[ii*10 + 9:ii*10 + 6] == 4'b0010 ? 4'b0000 : // Data VVV
indata[ii*10 + 9:ii*10 + 6] == 4'b1001 | indata[ii*10 + 9:ii*10 + 6] == 4'b1001 ? 4'b0001 :
indata[ii*10 + 9:ii*10 + 6] == 4'b1010 | indata[ii*10 + 9:ii*10 + 6] == 4'b1010 ? 4'b0010 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0011 | indata[ii*10 + 9:ii*10 + 6] == 4'b1100 ? 4'b0011 :
indata[ii*10 + 9:ii*10 + 6] == 4'b1011 | indata[ii*10 + 9:ii*10 + 6] == 4'b0100 ? 4'b0100 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0101 | indata[ii*10 + 9:ii*10 + 6] == 4'b0101 ? 4'b0101 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0110 | indata[ii*10 + 9:ii*10 + 6] == 4'b0110 ? 4'b0110 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0111 | indata[ii*10 + 9:ii*10 + 6] == 4'b1110 ? 4'b0111 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0001 | indata[ii*10 + 9:ii*10 + 6] == 4'b1000 ? 4'b0111 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0010 | indata[ii*10 + 9:ii*10 + 6] == 4'b1101 ? 4'b0000 : // Control VVV
/* indata[ii*10 + 9:ii*10 + 6] == 4'b1001 | indata[ii*10 + 9:ii*10 + 6] == 4'b0110 ? 4'b0001 :
indata[ii*10 + 9:ii*10 + 6] == 4'b1010 | indata[ii*10 + 9:ii*10 + 6] == 4'b0101 ? 4'b0010 :
indata[ii*10 + 9:ii*10 + 6] == 4'b1100 | indata[ii*10 + 9:ii*10 + 6] == 4'b0011 ? 4'b0011 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0100 | indata[ii*10 + 9:ii*10 + 6] == 4'b1011 ? 4'b0100 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0101 | indata[ii*10 + 9:ii*10 + 6] == 4'b1010 ? 4'b0101 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0110 | indata[ii*10 + 9:ii*10 + 6] == 4'b1001 ? 4'b0110 :
indata[ii*10 + 9:ii*10 + 6] == 4'b0001 | indata[ii*10 + 9:ii*10 + 6] == 4'b1110 ? 4'b0111 :*/
4'b1000); // not in a table
assign disp_word[ii] = (4'd0 + indata[ii*10] + indata[ii*10 + 1] + indata[ii*10 + 2] + indata[ii*10 + 3] + indata[ii*10 + 4]
+ indata[ii*10 + 5] + indata[ii*10 + 6] + indata[ii*10 + 7] + indata[ii*10 + 8] + indata[ii*10 + 9]) > 5;
assign no_disp_word[ii]= (4'd0 + indata[ii*10] + indata[ii*10 + 1] + indata[ii*10 + 2] + indata[ii*10 + 3] + indata[ii*10 + 4]
+ indata[ii*10 + 5] + indata[ii*10 + 6] + indata[ii*10 + 7] + indata[ii*10 + 8] + indata[ii*10 + 9]) == 5;
assign pure_data[ii*8 + 7:ii*8] = {data[ii*10 + 8:ii*10 + 6], data[ii*10 + 4:ii*10]};
if (add_2out_bits == "TRUE")
assign outdata[ii*10 + 9:ii*10]= {RXDISPERR[ii], RXCHARISK[ii], pure_data[ii*8 + 7:ii*8]};
else
assign outdata[ii*8 + 7:ii*8] = pure_data[ii*8 + 7:ii*8];
end
endgenerate
//disperr[ii] = no_disp_word[ii] ? 1'b0 : ~disp_word[ii] ^ disp[ii-1];
//disp[ii] = no_disp_word[ii] ? disp[ii-1] : disp_word[ii]
assign disp_err = ~no_disp_word & (~disp_word ^ {disp[word_count - 2:0], disp_init});
assign disp = ~no_disp_word & disp_word | no_disp_word & {disp[word_count - 2:0], disp_init};
generate
for (ii = 0; ii < 8; ii = ii + 1)
begin:dfsga
assign RXDATA[ii*8+7:ii*8] = ii >= word_count ? 8'h0 : pure_data[ii*8+7:ii*8];
assign RXNOTINTABLE[ii] = ii >= word_count ? 1'b0 : data[ii*10 + 9] | data[ii*10 + 5];
assign RXDISPERR[ii] = ii >= word_count ? 1'b0 : disp_err[ii];
assign RXCHARISK[ii] = ii >= word_count ? 1'b0 :
indata[ii*10 + 9:ii*10] == 10'b0010111100 | indata[ii*10 + 9:ii*10] == 10'b1101000011 |
indata[ii*10 + 9:ii*10] == 10'b1001111100 | indata[ii*10 + 9:ii*10] == 10'b0110000011 |
indata[ii*10 + 9:ii*10] == 10'b1010111100 | indata[ii*10 + 9:ii*10] == 10'b0101000011 |
indata[ii*10 + 9:ii*10] == 10'b1100111100 | indata[ii*10 + 9:ii*10] == 10'b0011000011 |
indata[ii*10 + 9:ii*10] == 10'b0100111100 | indata[ii*10 + 9:ii*10] == 10'b1011000011 |
indata[ii*10 + 9:ii*10] == 10'b0101111100 | indata[ii*10 + 9:ii*10] == 10'b1010000011 |
indata[ii*10 + 9:ii*10] == 10'b0110111100 | indata[ii*10 + 9:ii*10] == 10'b1001000011 |
indata[ii*10 + 9:ii*10] == 10'b0001111100 | indata[ii*10 + 9:ii*10] == 10'b1110000011 |
indata[ii*10 + 9:ii*10] == 10'b0001010111 | indata[ii*10 + 9:ii*10] == 10'b1110101000 |
indata[ii*10 + 9:ii*10] == 10'b0001011011 | indata[ii*10 + 9:ii*10] == 10'b1110100100 |
indata[ii*10 + 9:ii*10] == 10'b0001011101 | indata[ii*10 + 9:ii*10] == 10'b1110100010 |
indata[ii*10 + 9:ii*10] == 10'b0001011110 | indata[ii*10 + 9:ii*10] == 10'b1110100001;
assign RXCHARISCOMMA[ii] = ii >= word_count ? 1'b0 :
(indata[ii*10 + 9:ii*10] == 10'b1001111100 |
indata[ii*10 + 9:ii*10] == 10'b0101111100 |
indata[ii*10 + 9:ii*10] == 10'b0001111100) & DEC_PCOMMA_DETECT |
(indata[ii*10 + 9:ii*10] == 10'b0110000011 |
indata[ii*10 + 9:ii*10] == 10'b1010000011 |
indata[ii*10 + 9:ii*10] == 10'b1110000011) & DEC_MCOMMA_DETECT;
end
endgenerate
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_rx_align
* Date: 2015-07-06
* Author: Alexey
* Description: reciever's comma-aligner implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_rx_align.v 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.
*
* gtxe2_chnl_rx_align.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
module gtxe2_chnl_rx_align #(
parameter width = 20,
parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011,
parameter ALIGN_MCOMMA_DET = "TRUE",
parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100,
parameter ALIGN_PCOMMA_DET = "TRUE",
parameter [9:0] ALIGN_COMMA_ENABLE = 10'b1111111111,
parameter ALIGN_COMMA_DOUBLE = "FALSE",
parameter ALIGN_COMMA_WORD = 1
)
(
input wire clk,
input wire rst,
input wire [width - 1:0] indata,
output wire [width - 1:0] outdata,
output wire RXBYTEISALIGNED,
output wire RXBYTEREALIGN,
output wire RXCOMMADET,
input wire RXCOMMADETEN,
input wire RXPCOMMAALIGNEN,
input wire RXMCOMMAALIGNEN
);
localparam comma_width = ALIGN_COMMA_DOUBLE == "FALSE" ? 10 : 20;
localparam window_size = width;//comma_width + width;
// prepare a buffer to be scanned on comma matches
reg [width - 1:0] indata_r;
wire [width*2 - 1:0] data;
// looking for matches in all related bit history - in 'data'
assign data = {indata, indata_r};//{indata_r, indata};
always @ (posedge clk)
indata_r <= indata;
// finding matches
wire [comma_width - 1:0] comma_window [window_size - 1:0];
wire [window_size - 1:0] comma_match; // shows all matches
wire [window_size - 1:0] comma_pos; // shows the first match
wire [window_size - 1:0] pcomma_match;
wire [window_size - 1:0] mcomma_match;
genvar ii;
generate
for (ii = 0; ii < window_size; ii = ii + 1)
begin: filter
assign comma_window[ii] = data[comma_width + ii - 1:ii];
assign pcomma_match[ii] = (comma_window[ii] & ALIGN_COMMA_ENABLE) == (ALIGN_PCOMMA_VALUE & ALIGN_COMMA_ENABLE);
assign mcomma_match[ii] = (comma_window[ii] & ALIGN_COMMA_ENABLE) == (ALIGN_MCOMMA_VALUE & ALIGN_COMMA_ENABLE);
assign comma_match[ii] = pcomma_match[ii] & RXPCOMMAALIGNEN | mcomma_match[ii] & RXMCOMMAALIGNEN;
end
endgenerate
// so, comma_match indicates bits, from whose comma/doublecomma (or commas) occurs in the window buffer
// all we need from now is to get one of these bits, [x], and say [x+width-1:x] is an aligned data
// doing it in a hard way
generate
for (ii = 1; ii < window_size; ii = ii + 1)
begin: filter_comma_pos
assign comma_pos[ii] = comma_match[ii] & ~|comma_match[ii - 1:0];
end
endgenerate
assign comma_pos[0] = comma_match[0];
// so, comma_pos's '1' indicates the first comma occurence. there is only one '1' in the vector
function integer clogb2;
input [31:0] value;
begin
value = value - 1;
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) begin
value = value >> 1;
end
end
endfunction
function integer powerof2;
input [31:0] value;
begin
value = 1 << value;
end
endfunction
localparam pwidth = clogb2(width * 2 -1);
// decoding (finding an index, representing '1' in comma_pos)
wire [pwidth - 1:0] pointer;
reg [pwidth - 1:0] pointer_latched;
wire pointer_set;
wire [window_size - 1:0] pbits [pwidth - 1:0];
genvar jj;
generate
for (ii = 0; ii < pwidth; ii = ii + 1)
begin: for_each_pointers_bit
for (jj = 0; jj < window_size; jj = jj + 1)
begin: calculate_encoder_mask
assign pbits[ii][jj] = jj[ii];
end
assign pointer[ii] = |(pbits[ii] & comma_pos);
end
endgenerate
//here we are: pointer = index of a beginning of the required output data
reg is_aligned;
assign outdata = ~RXCOMMADETEN ? indata : pointer_set ? data[pointer + width - 1 -:width] : data[pointer_latched + width - 1 -:width];
assign pointer_set = |comma_pos;
assign RXCOMMADET = RXCOMMADETEN & pointer_set & (|pcomma_match & ALIGN_PCOMMA_DET == "TRUE" | |mcomma_match & ALIGN_MCOMMA_DET == "TRUE");
assign RXBYTEISALIGNED = RXCOMMADETEN & is_aligned;
assign RXBYTEREALIGN = RXCOMMADETEN & is_aligned & pointer_set;
always @ (posedge clk)
begin
is_aligned <= rst ? 1'b0 : ~is_aligned & pointer_set | is_aligned;
pointer_latched <= rst ? 1'b0 : pointer_set ? pointer : pointer_latched;
end
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_rx_des
* Date: 2015-07-06
* Author: Alexey
* Description: 1xwidth deserializer
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_rx_des.v 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.
*
* gtxe2_chnl_rx_des.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "resync_fifo_nonsynt.v"
module gtxe2_chnl_rx_des #(
parameter [31:0] width = 20
)
(
input wire reset,
input wire inclk,
input wire outclk,
input wire indata,
output wire [width - 1:0] outdata
);
reg [31:0] bitcounter;
reg [width - 1:0] inbuffer;
wire empty_rd;
wire full_wr;
wire val_wr;
wire val_rd;
always @ (posedge inclk)
bitcounter <= reset | bitcounter == (width - 1) ? 32'h0 : bitcounter + 1'b1;
genvar ii;
generate
for (ii = 0; ii < width; ii = ii + 1)
begin: splicing
always @ (posedge inclk)
inbuffer[ii] <= reset ? 1'b0 : (bitcounter == ii) ? indata : inbuffer[ii];
end
endgenerate
assign val_rd = ~empty_rd & ~almost_empty_rd;
assign val_wr = ~full_wr & bitcounter == (width - 1);
always @ (posedge inclk)
if (full_wr)
begin
$display("FIFO in %m is full, that is not an appropriate behaviour");
$finish;
end
resync_fifo_nonsynt #(
.width (width),
.log_depth (3)
)
fifo(
.rst_rd (reset),
.rst_wr (reset),
.clk_wr (inclk),
.val_wr (val_wr),
.data_wr ({indata, inbuffer[width - 2:0]}),
.clk_rd (outclk),
.val_rd (val_rd),
.data_rd (outdata),
.empty_rd (empty_rd),
.full_wr (full_wr),
.almost_empty_rd (almost_empty_rd)
);
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_rx_oob
* Date: 2015-07-06
* Author: Alexey
* Description: oob detector
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_rx_oob.v 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.
*
* gtxe2_chnl_rx_oob.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
// doesnt support global parameters for now. instead uses localparams
// in case global parameters are needed, have to translate them in terms of localparams
module gtxe2_chnl_rx_oob #(
parameter width = 20,
// parameters are not used for now
parameter [2:0] SATA_BURST_VAL = 3'b100,
parameter [2:0] SATA_EIDLE_VAL = 3'b100,
parameter SATA_MIN_INIT = 12,
parameter SATA_MIN_WAKE = 4,
parameter SATA_MAX_BURST = 8,
parameter SATA_MIN_BURST = 4,
parameter SATA_MAX_INIT = 21,
parameter SATA_MAX_WAKE = 7
)
(
input wire reset,
input wire clk,
input wire RXN,
input wire RXP,
input wire [1:0] RXELECIDLEMODE,
output wire RXELECIDLE,
output wire RXCOMINITDET,
output wire RXCOMWAKEDET
);
localparam burst_min_len = 150;
localparam burst_max_len = 340;
localparam wake_idle_min_len = 150;
localparam wake_idle_max_len = 340;
localparam init_idle_min_len = 450;
localparam init_idle_max_len = 990;
localparam wake_bursts_cnt = 5;
localparam init_bursts_cnt = 5;
wire idle;
assign idle = RXN == RXP;
wire state_notrans;
wire state_error; //nostrans substate
wire state_done; //notrans substate
reg state_idle;
reg state_burst;
wire set_notrans;
wire set_done;
wire set_error;
wire set_idle;
wire set_burst;
wire clr_idle;
wire clr_burst;
assign state_notrans = ~state_idle & ~state_burst;
always @ (posedge clk)
begin
state_idle <= (state_idle | set_idle) & ~reset & ~clr_idle;
state_burst <= (state_burst | set_burst) & ~reset & ~clr_burst;
end
assign set_notrans = set_done | set_error;
assign set_idle = state_burst & clr_burst & idle;
assign set_burst = state_notrans & ~idle | state_idle & clr_idle & ~idle;
assign clr_idle = ~idle | set_notrans;
assign clr_burst = idle | set_notrans;
reg [31:0] burst_len;
reg [31:0] idle_len;
reg [31:0] bursts_cnt;
always @ (posedge clk)
begin
burst_len <= reset | ~state_burst ? 0 : burst_len + 1;
idle_len <= reset | ~state_idle ? 0 : idle_len + 1;
bursts_cnt <= reset | state_notrans ? 0 : state_burst & clr_burst ? bursts_cnt + 1 : bursts_cnt;
end
wire burst_len_violation;
wire idle_len_violation;
wire wake_idle_violation;
wire init_idle_violation;
//reg burst_len_ok;
reg wake_idle_ok;
reg init_idle_ok;
reg burst_len_curr_ok;
reg init_idle_curr_ok;
reg wake_idle_curr_ok;
wire done_wake;
wire done_init;
always @ (posedge clk)
begin
wake_idle_ok <= reset | state_notrans ? 1'b1 : wake_idle_violation ? 1'b0 : wake_idle_ok;
init_idle_ok <= reset | state_notrans ? 1'b1 : init_idle_violation ? 1'b0 : init_idle_ok;
// burst_len_ok <= reset | state_notrans ? 1'b1 : burst_len_violation ? 1'b0 : burst_len_ok;
wake_idle_curr_ok <= reset | ~state_idle ? 1'b0 : idle_len == wake_idle_min_len ? 1'b1 : wake_idle_curr_ok;
init_idle_curr_ok <= reset | ~state_idle ? 1'b0 : idle_len == init_idle_min_len ? 1'b1 : init_idle_curr_ok;
burst_len_curr_ok <= reset | ~state_burst? 1'b0 : burst_len == burst_min_len ? 1'b1 : burst_len_curr_ok;
end
assign burst_len_violation = state_burst & set_idle & ~burst_len_curr_ok | state_burst & burst_len == burst_max_len;
assign wake_idle_violation = state_idle & set_burst & ~wake_idle_curr_ok | state_idle & idle_len == wake_idle_max_len;
assign init_idle_violation = state_idle & set_burst & ~init_idle_curr_ok | state_idle & idle_len == init_idle_max_len;
assign idle_len_violation = (~wake_idle_ok | wake_idle_violation) & init_idle_violation | wake_idle_violation & (~init_idle_ok | init_idle_violation);
assign done_wake = state_burst & ~idle & bursts_cnt == (wake_bursts_cnt - 1) & wake_idle_ok;
assign done_init = state_burst & ~idle & bursts_cnt == (init_bursts_cnt - 1)& init_idle_ok;
assign set_error = idle_len_violation | burst_len_violation;
assign set_done = ~set_error & (done_wake | done_init);
assign RXCOMINITDET = done_init;
assign RXCOMWAKEDET = done_wake;
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_tx
* Date: 2015-07-06
* Author: Alexey
* Description: transmitter top-level, includes polarity-inversion, bit-reordering
* and elecidle logic
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_tx.v 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.
*
* gtxe2_chnl_tx.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_chnl_tx_ser.v"
`include "gtxe2_chnl_tx_8x10enc.v"
`include "gtxe2_chnl_tx_oob.v"
module gtxe2_chnl_tx(
input wire reset,
output wire TXP,
output wire TXN,
input wire [63:0] TXDATA,
input wire TXUSRCLK,
input wire TXUSRCLK2,
// 8/10 encoder
input wire [7:0] TX8B10BBYPASS,
input wire TX8B10BEN,
input wire [7:0] TXCHARDISPMODE,
input wire [7:0] TXCHARDISPVAL,
input wire [7:0] TXCHARISK,
// TX Buffer
output wire [1:0] TXBUFSTATUS,
// TX Polarity
input wire TXPOLARITY,
// TX Fabric Clock Control
input wire [2:0] TXRATE,
output wire TXRATEDONE,
// TX OOB
input wire TXCOMINIT,
input wire TXCOMWAKE,
output wire TXCOMFINISH,
// TX Driver Control
input wire TXELECIDLE,
// internal
input wire serial_clk
);
parameter TX_DATA_WIDTH = 20;
parameter TX_INT_DATAWIDTH = 0;
parameter PTX8B10BEN = 1;
parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
function integer calc_idw;
input TX8B10BEN;
// input TX_INT_DATAWIDTH;
// input TX_DATA_WIDTH;
begin
if (TX8B10BEN == 1)
calc_idw = TX_INT_DATAWIDTH == 1 ? 40 : 20;
else
begin
if (TX_INT_DATAWIDTH == 1)
calc_idw = TX_DATA_WIDTH == 32 ? 32
: TX_DATA_WIDTH == 40 ? 40
: TX_DATA_WIDTH == 64 ? 32 : 40;
else
calc_idw = TX_DATA_WIDTH == 16 ? 16
: TX_DATA_WIDTH == 20 ? 20
: TX_DATA_WIDTH == 32 ? 16 : 20;
end
end
endfunction
localparam internal_data_width = calc_idw(PTX8B10BEN);//, TX_INT_DATAWIDTH, TX_DATA_WIDTH);
// TX PMA
// serializer
wire serial_data;
wire line_idle;
wire line_idle_pcs; // line_idle in pcs clock domain
wire [internal_data_width - 1:0] ser_input;
wire oob_active;
assign TXP = ~line_idle & serial_data;
assign TXN = ~line_idle & ~serial_data;
assign line_idle_pcs = TXELECIDLE & ~oob_active | reset;
// Serializer
wire [internal_data_width - 1:0] parallel_data;
wire [internal_data_width - 1:0] inv_parallel_data;
gtxe2_chnl_tx_ser #(
.width (internal_data_width)
)
ser(
.reset (reset),
.inclk (TXUSRCLK),
.outclk (serial_clk),
.indata (inv_parallel_data),
.idle_in (line_idle_pcs),
.outdata (serial_data),
.idle_out (line_idle)
);
// TX PCS
// invert data (get words as [abdceifghj] after 8/10, each word shall be transmitter in a reverse bit order)
genvar ii;
genvar jj;
generate
for (ii = 0; ii < internal_data_width; ii = ii + 10)
begin: select_each_word
for (jj = 0; jj < 10; jj = jj + 1)
begin: reverse_bits
assign inv_parallel_data[ii + jj] = polarized_data[ii + 9 - jj];
end
end
endgenerate
// Polarity:
wire [internal_data_width - 1:0] polarized_data;
assign ser_input = polarized_data;
generate
for (ii = 0; ii < internal_data_width; ii = ii + 1)
begin: invert_dataword
assign polarized_data[ii] = TXPOLARITY == 1'b1 ? ~parallel_data[ii] : parallel_data[ii];
end
endgenerate
// SATA OOB
reg disparity;
wire [internal_data_width - 1:0] oob_data;
wire oob_val;
assign oob_active = oob_val;
gtxe2_chnl_tx_oob #(
.width (internal_data_width)
)
tx_oob(
.TXCOMINIT (TXCOMINIT),
.TXCOMWAKE (TXCOMWAKE),
.TXCOMFINISH (TXCOMFINISH),
.clk (TXUSRCLK),
.reset (reset),
.disparity (disparity),
.outdata (oob_data),
.outval (oob_val)
);
// Disparity control
wire next_disparity;
always @ (posedge TXUSRCLK)
disparity <= reset | line_idle_pcs? 1'b0 : oob_val ? ~disparity : next_disparity;
// 8/10 endoding
wire [internal_data_width - 1:0] encoded_data;
gtxe2_chnl_tx_8x10enc #(
.iwidth (16),//TX_DATA_WIDTH),
.owidth (internal_data_width)
)
encoder_8x10(
.TX8B10BBYPASS (TX8B10BBYPASS),
.TX8B10BEN (TX8B10BEN),
.TXCHARDISPMODE (TXCHARDISPMODE),
.TXCHARDISPVAL (TXCHARDISPVAL),
.TXCHARISK (TXCHARISK),
.disparity (disparity),
.data_in (TXDATA[15:0]),
.data_out (encoded_data),
.next_disparity (next_disparity)
);
// OOB-OrdinaryData Arbiter
assign parallel_data = oob_val ? oob_data : encoded_data;
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_tx_8x10enc
* Date: 2015-07-06
* Author: Alexey
* Description: 8x10 encoder
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_tx_8x10enc.v 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.
*
* gtxe2_chnl_tx_8x10enc.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
// for some reason overall trasmitted disparity is tracked at the top level
module gtxe2_chnl_tx_8x10enc #(
parameter iwidth = 16,
parameter owidth = 20
)
(
input wire [7:0] TX8B10BBYPASS,
input wire TX8B10BEN,
input wire [7:0] TXCHARDISPMODE,
input wire [7:0] TXCHARDISPVAL,
input wire [7:0] TXCHARISK,
input wire disparity,
input wire [iwidth - 1:0] data_in,
output wire [owidth - 1:0] data_out,
output wire next_disparity
);
// only full 8/10 encoding and width=20 case is implemented
localparam word_count = owidth / 10;
wire [word_count - 1:0] word_disparity;
wire [word_count - 1:0] interm_disparity;
wire [5:0] six [word_count - 1:0];
wire [3:0] four [word_count - 1:0];
wire [owidth - 1:0] oword [word_count - 1:0];
wire [iwidth - 1:0] iword [word_count - 1:0];
wire [word_count - 1:0] is_control;
// typical approach: 8x10 = 5x6 + 3x4
// word disparity[i] = calculated disparity for the i-th 8-bit word
// interm_disparity[i] - disparity after 5x6 encoding for the i-th word
genvar ii;
generate
for (ii = 0; ii < 2; ii = ii + 1)
begin: encode_by_word
assign is_control[ii] = TXCHARISK[ii];
assign iword[ii] = data_in[ii*8 + 7:ii*8];
assign interm_disparity[ii]= ^six[ii] ? word_disparity[ii] : ~word_disparity[ii];
assign word_disparity[ii] = (ii == 0) ? disparity :
(^oword[ii - 1] ? ~word_disparity[ii - 1] : word_disparity[ii - 1]);
assign six[ii] = iword[ii][4:0] == 5'b00000 ? (~word_disparity[ii] ? 6'b100111 : 6'b011000)
: iword[ii][4:0] == 5'b00001 ? (~word_disparity[ii] ? 6'b011101 : 6'b100010)
: iword[ii][4:0] == 5'b00010 ? (~word_disparity[ii] ? 6'b101101 : 6'b010010)
: iword[ii][4:0] == 5'b00011 ? (~word_disparity[ii] ? 6'b110001 : 6'b110001)
: iword[ii][4:0] == 5'b00100 ? (~word_disparity[ii] ? 6'b110101 : 6'b001010)
: iword[ii][4:0] == 5'b00101 ? (~word_disparity[ii] ? 6'b101001 : 6'b101001)
: iword[ii][4:0] == 5'b00110 ? (~word_disparity[ii] ? 6'b011001 : 6'b011001)
: iword[ii][4:0] == 5'b00111 ? (~word_disparity[ii] ? 6'b111000 : 6'b000111)
: iword[ii][4:0] == 5'b01000 ? (~word_disparity[ii] ? 6'b111001 : 6'b000110)
: iword[ii][4:0] == 5'b01001 ? (~word_disparity[ii] ? 6'b100101 : 6'b100101)
: iword[ii][4:0] == 5'b01010 ? (~word_disparity[ii] ? 6'b010101 : 6'b010101)
: iword[ii][4:0] == 5'b01011 ? (~word_disparity[ii] ? 6'b110100 : 6'b110100)
: iword[ii][4:0] == 5'b01100 ? (~word_disparity[ii] ? 6'b001101 : 6'b001101)
: iword[ii][4:0] == 5'b01101 ? (~word_disparity[ii] ? 6'b101100 : 6'b101100)
: iword[ii][4:0] == 5'b01110 ? (~word_disparity[ii] ? 6'b011100 : 6'b011100)
: iword[ii][4:0] == 5'b01111 ? (~word_disparity[ii] ? 6'b010111 : 6'b101000)
: iword[ii][4:0] == 5'b10000 ? (~word_disparity[ii] ? 6'b011011 : 6'b100100)
: iword[ii][4:0] == 5'b10001 ? (~word_disparity[ii] ? 6'b100011 : 6'b100011)
: iword[ii][4:0] == 5'b10010 ? (~word_disparity[ii] ? 6'b010011 : 6'b010011)
: iword[ii][4:0] == 5'b10011 ? (~word_disparity[ii] ? 6'b110010 : 6'b110010)
: iword[ii][4:0] == 5'b10100 ? (~word_disparity[ii] ? 6'b001011 : 6'b001011)
: iword[ii][4:0] == 5'b10101 ? (~word_disparity[ii] ? 6'b101010 : 6'b101010)
: iword[ii][4:0] == 5'b10110 ? (~word_disparity[ii] ? 6'b011010 : 6'b011010)
: iword[ii][4:0] == 5'b10111 ? (~word_disparity[ii] ? 6'b111010 : 6'b000101)
: iword[ii][4:0] == 5'b11000 ? (~word_disparity[ii] ? 6'b110011 : 6'b001100)
: iword[ii][4:0] == 5'b11001 ? (~word_disparity[ii] ? 6'b100110 : 6'b100110)
: iword[ii][4:0] == 5'b11010 ? (~word_disparity[ii] ? 6'b010110 : 6'b010110)
: iword[ii][4:0] == 5'b11011 ? (~word_disparity[ii] ? 6'b110110 : 6'b001001)
: iword[ii][4:0] == 5'b11100 ? (~word_disparity[ii] ? 6'b001110 : 6'b001110)
: iword[ii][4:0] == 5'b11101 ? (~word_disparity[ii] ? 6'b101110 : 6'b010001)
: iword[ii][4:0] == 5'b11110 ? (~word_disparity[ii] ? 6'b011110 : 6'b100001)
:/*iword[ii][4:0] == 5'b11111*/(~word_disparity[ii] ? 6'b101011 : 6'b010100);
assign four[ii] = iword[ii][7:5] == 3'd0 ? (~interm_disparity[ii] ? 4'b1011 : 4'b0100)
: iword[ii][7:5] == 3'd1 ? (~interm_disparity[ii] ? 4'b1001 : 4'b1001)
: iword[ii][7:5] == 3'd2 ? (~interm_disparity[ii] ? 4'b0101 : 4'b0101)
: iword[ii][7:5] == 3'd3 ? (~interm_disparity[ii] ? 4'b1100 : 4'b0011)
: iword[ii][7:5] == 3'd4 ? (~interm_disparity[ii] ? 4'b1101 : 4'b0010)
: iword[ii][7:5] == 3'd5 ? (~interm_disparity[ii] ? 4'b1010 : 4'b1010)
: iword[ii][7:5] == 3'd6 ? (~interm_disparity[ii] ? 4'b0110 : 4'b0110)
:/*iword[ii][7:5] == 3'd7*/(~interm_disparity[ii] ? (six[ii][1:0] == 2'b00 ? 4'b1110 : 4'b0111)
: (six[ii][1:0] == 2'b00 ? 4'b1000 : 4'b0001));
assign oword[ii] = ~is_control[ii] ? {six[ii], four[ii]}
: iword[ii][7:0] == 8'b00011100 ? (~word_disparity[ii] ? 10'b0011110100 : 10'b1100001011)
: iword[ii][7:0] == 8'b00111100 ? (~word_disparity[ii] ? 10'b0011111001 : 10'b1100000110)
: iword[ii][7:0] == 8'b01011100 ? (~word_disparity[ii] ? 10'b0011110101 : 10'b1100001010)
: iword[ii][7:0] == 8'b01111100 ? (~word_disparity[ii] ? 10'b0011110011 : 10'b1100001100)
: iword[ii][7:0] == 8'b10011100 ? (~word_disparity[ii] ? 10'b0011110010 : 10'b1100001101)
: iword[ii][7:0] == 8'b10111100 ? (~word_disparity[ii] ? 10'b0011111010 : 10'b1100000101)
: iword[ii][7:0] == 8'b11011100 ? (~word_disparity[ii] ? 10'b0011110110 : 10'b1100001001)
: iword[ii][7:0] == 8'b11111100 ? (~word_disparity[ii] ? 10'b0011111000 : 10'b1100000111)
: iword[ii][7:0] == 8'b11110111 ? (~word_disparity[ii] ? 10'b1110101000 : 10'b0001010111)
: iword[ii][7:0] == 8'b11111011 ? (~word_disparity[ii] ? 10'b1101101000 : 10'b0010010111)
: iword[ii][7:0] == 8'b11111101 ? (~word_disparity[ii] ? 10'b1011101000 : 10'b0100010111)
:/*iword[ii][7:0] == 8'b11111110*/(~word_disparity[ii] ? 10'b0111101000 : 10'b1000010111);
assign data_out[ii*10 + 9:ii * 10] = oword[ii];
end
endgenerate
assign next_disparity = ^oword[word_count - 1] ? ~word_disparity[word_count - 1] : word_disparity[word_count - 1];
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_tx_oob
* Date: 2015-07-06
* Author: Alexey
* Description: oob block implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_tx_oob.v 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.
*
* gtxe2_chnl_tx_oob.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
module gtxe2_chnl_tx_oob #(
parameter width = 20
)
(
// top-level ifaces
input wire TXCOMINIT,
input wire TXCOMWAKE,
output wire TXCOMFINISH,
// internal ifaces
input wire clk,
input wire reset,
input wire disparity,
output wire [width - 1:0] outdata,
output wire outval
);
parameter [3:0] SATA_BURST_SEQ_LEN = 4'b0101;
parameter SATA_CPLL_CFG = "VCO_3000MHZ";
localparam burst_len_mult = SATA_CPLL_CFG == "VCO_3000MHZ" ? 4
: SATA_CPLL_CFG == "VCO_1500MHZ" ? 2
: /* VCO_750MHZ */ 1;
localparam burst_len = burst_len_mult * 8; // = 106.7ns; each burst contains 16 SATA Gen1 words
localparam quiet_len_init = burst_len * 3; // = 320ns
localparam quiet_len_wake = burst_len; // = 106.7ns
localparam init_bursts_cnt = SATA_BURST_SEQ_LEN;//3;
localparam wake_bursts_cnt = SATA_BURST_SEQ_LEN;//5;
reg [31:0] bursts_cnt;
reg [31:0] stopwatch;
wire stopwatch_clr;
wire bursts_cnt_inc;
wire bursts_cnt_clr;
wire [31:0] quiet_len;
// FSM Declarations
reg state_burst;
reg state_quiet;
wire state_idle;
wire set_burst;
wire set_quiet;
wire clr_burst;
wire clr_quiet;
// remember what command was issued
reg issued_init;
reg issued_wake;
always @ (posedge clk)
begin
issued_init <= reset | TXCOMFINISH | issued_wake ? 1'b0 : TXCOMINIT ? 1'b1 : state_idle ? 1'b0 : issued_init;
issued_wake <= reset | TXCOMFINISH | issued_init ? 1'b0 : TXCOMWAKE ? 1'b1 : state_idle ? 1'b0 : issued_wake;
end
wire [31:0] bursts_cnt_togo;
assign bursts_cnt_togo = issued_wake ? wake_bursts_cnt : init_bursts_cnt ;
// FSM
assign state_idle = ~state_burst & ~state_quiet;
always @ (posedge clk)
begin
state_burst <= (state_burst | set_burst) & ~reset & ~clr_burst;
state_quiet <= (state_quiet | set_quiet) & ~reset & ~clr_quiet;
end
assign set_burst = state_idle & (TXCOMINIT | TXCOMWAKE) | state_quiet & clr_quiet & ~TXCOMFINISH;
assign set_quiet = state_burst & (bursts_cnt < bursts_cnt_togo - 1) & clr_burst;
assign clr_burst = state_burst & stopwatch == burst_len;
assign clr_quiet = state_quiet & stopwatch == quiet_len;
// bursts timing
assign quiet_len = issued_wake ? quiet_len_wake : quiet_len_init;
assign stopwatch_clr = set_burst | set_quiet | state_idle;
always @ (posedge clk)
stopwatch <= reset | stopwatch_clr ? 0 : stopwatch + burst_len_mult;
// total bursts count
assign bursts_cnt_clr = state_idle;
assign bursts_cnt_inc = state_burst & clr_burst;
always @ (posedge clk)
bursts_cnt <= reset | bursts_cnt_clr ? 0 : bursts_cnt_inc ? bursts_cnt + 1 : bursts_cnt;
// data to serializer
// only datawidth = 20 is supported for now
wire [width - 1:0] outdata_pos;
wire [width - 1:0] outdata_neg;
// outdata = {Align2 + Align1}, disparity always flips
assign outdata_pos = stopwatch[0] == 1'b0 ? {10'b0101010101, 10'b1100000101}
: {10'b1101100011, 10'b0101010101};
assign outdata_neg = stopwatch[0] == 1'b0 ? {10'b0101010101, 10'b0011111010}
: {10'b0010011100, 10'b0101010101};
assign outdata = disparity ? outdata_pos : outdata_neg;
assign outval = state_burst;
assign TXCOMFINISH = bursts_cnt_clr & bursts_cnt == bursts_cnt_togo;
endmodule
/*******************************************************************************
* Module: gtxe2_chnl_tx_ser
* Date: 2015-07-06
* Author: Alexey
* Description: widthx1 serializer
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_chnl_tx_ser.v 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.
*
* gtxe2_chnl_tx_ser.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "resync_fifo_nonsynt.v"
module gtxe2_chnl_tx_ser #(
parameter [31:0] width = 20
)
(
input wire reset,
input wire inclk,
input wire outclk,
input wire [width - 1:0] indata,
input wire idle_in,
output wire outdata,
output wire idle_out
);
reg [31:0] bitcounter;
wire [width - 1:0] data_resynced;
wire almost_empty_rd;
wire empty_rd;
wire full_wr;
wire val_rd;
always @ (posedge outclk)
bitcounter <= reset | bitcounter == (width - 1) ? 32'h0 : bitcounter + 1'b1;
assign outdata = data_resynced[bitcounter];
assign val_rd = ~almost_empty_rd & ~empty_rd & bitcounter == (width - 1);
resync_fifo_nonsynt #(
.width (width + 1), // +1 is for a flag of an idle line (both TXP and TXN = 0)
.log_depth (3)
)
fifo(
.rst_rd (reset),
.rst_wr (reset),
.clk_wr (inclk),
.val_wr (1'b1),
.data_wr ({idle_in, indata}),
.clk_rd (outclk),
.val_rd (val_rd),
.data_rd ({idle_out, data_resynced}),
.empty_rd (empty_rd),
.full_wr (full_wr),
.almost_empty_rd (almost_empty_rd)
);
endmodule
/*******************************************************************************
* Module: resync_fifo_nonsynt
* Date: 2015-07-06
* Author: Alexey
* Description: non-synthesizable resyncronization fifo
*
* Copyright (c) 2015 Elphel, Inc.
* resync_fifo_nonsynt.v 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.
*
* resync_fifo_nonsynt.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
// simplified resynchronisation fifo, could cause metastability
// because of that shall not be syntesisable
// TODO add shift registers and gray code to fix that
`ifndef RESYNC_FIFO_NOSYNT_V
`define RESYNC_FIFO_NOSYNT_V
module resync_fifo_nonsynt #(
parameter [31:0] width = 20,
//parameter [31:0] depth = 7
parameter [31:0] log_depth = 3
)
(
input wire rst_rd,
input wire rst_wr,
input wire clk_wr,
input wire val_wr,
input wire [width - 1:0] data_wr,
input wire clk_rd,
input wire val_rd,
output wire [width - 1:0] data_rd,
output wire empty_rd,
output wire almost_empty_rd,
output wire full_wr
);
/*
function integer clogb2;
input [31:0] value;
begin
value = value - 1;
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1) begin
value = value >> 1;
end
end
endfunction
localparam log_depth = clogb2(depth);
*/
localparam depth = 1 << log_depth;
reg [width -1:0] fifo [depth - 1:0];
// wr_clk domain
reg [log_depth - 1:0] cnt_wr;
// rd_clk domain
reg [log_depth - 1:0] cnt_rd;
assign data_rd = fifo[cnt_rd];
assign empty_rd = cnt_wr == cnt_rd;
assign full_wr = (cnt_wr + 1'b1) == cnt_rd;
assign almost_empty_rd = (cnt_rd + 1'b1) == cnt_wr;
always @ (posedge clk_wr)
fifo[cnt_wr] <= val_wr ? data_wr : fifo[cnt_wr];
always @ (posedge clk_wr)
cnt_wr <= rst_wr ? 0 : val_wr ? cnt_wr + 1'b1 : cnt_wr;
always @ (posedge clk_rd)
cnt_rd <= rst_rd ? 0 : val_rd ? cnt_rd + 1'b1 : cnt_rd;
endmodule
`endif
/*******************************************************************************
* Module: gtxe2_comm_clocking
* Date: 2015-07-06
* Author: Alexey
* Description: qpll top-level, for now
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_comm_clocking.v 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.
*
* gtxe2_comm_clocking.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_comm_qpll_inmux.v"
`include "gtxe2_comm_qpll.v"
module gtxe2_comm_clocking(
// top-level interfaces
input wire [2:0] QPLLREFCLKSEL,
input wire GTREFCLK0,
input wire GTREFCLK1,
input wire GTNORTHREFCLK0,
input wire GTNORTHREFCLK1,
input wire GTSOUTHREFCLK0,
input wire GTSOUTHREFCLK1,
input wire GTGREFCLK,
output wire QPLLOUTCLK,
output wire QPLLOUTREFCLK,
output wire REFCLKOUTMONITOR,
input wire QPLLLOCKDETCLK,
input wire QPLLLOCKEN,
input wire QPLLPD,
input wire QPLLRESET,
output wire QPLLFBCLKLOST,
output wire QPLLLOCK,
output wire QPLLREFCLKLOST
);
wire clk_mux_out;
wire qpll_clk_out; //TODO
assign REFCLKOUTMONITOR = clk_mux_out;
assign QPLLOUTREFCLK = clk_mux_out;
assign QPLLOUTCLK = qpll_clk_out;
gtxe2_comm_qpll_inmux clk_mux(
.QPLLREFCLKSEL (QPLLREFCLKSEL),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.GTGREFCLK (GTGREFCLK),
.QPLL_MUX_CLK_OUT (clk_mux_out)
);
gtxe2_comm_qpll qpll(
.QPLLLOCKDETCLK (QPLLLOCKDETCLK),
.QPLLLOCKEN (QPLLLOCKEN),
.QPLLPD (QPLLPD),
.QPLLRESET (QPLLRESET),
.QPLLFBCLKLOST (QPLLFBCLKLOST),
.QPLLLOCK (QPLLLOCK),
.QPLLREFCLKLOST (QPLLREFCLKLOST),
.GTRSVD (GTRSVD),
.PCSRSVDIN (PCSRSVDIN),
.PCSRSVDIN2 (PCSRSVDIN2),
.PMARSVDIN (PMARSVDIN),
.PMARSVDIN2 (PMARSVDIN2),
.TSTIN (TSTIN),
.TSTOUT (TSTOUT),
.ref_clk (clk_mux_out),
.clk_out (qpll_clk_out),
.pll_locked (pll_locked)
);
endmodule
/*******************************************************************************
* Module: gtxe2_comm_qpll
* Date: 2015-07-06
* Author: Alexey
* Description: qpll non-synthesizable implementation
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_comm_qpll.v 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.
*
* gtxe2_comm_qpll.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`include "gtxe2_comm_qpll_def.v"
module gtxe2_comm_qpll(
// top-level interfaces
input wire QPLLLOCKDETCLK, // shall not be used here
input wire QPLLLOCKEN,
input wire QPLLPD,
input wire QPLLRESET, // active high
output wire QPLLFBCLKLOST,
output wire QPLLLOCK,
output wire QPLLREFCLKLOST,
input wire GTRSVD,
input wire PCSRSVDIN,
input wire PCSRSVDIN2,
input wire PMARSVDIN,
input wire PMARSVDIN2,
input wire TSTIN,
output wire TSTOUT,
// internal
input wire ref_clk,
output wire clk_out,
output wire pll_locked // equals QPLLLOCK
);
parameter [23:0] QPLL_CFG = 27'h04801C7;
parameter integer QPLL_FBDIV = 10'b0000100000;
parameter integer QPLL_FBDIV_45 = 1;
parameter [23:0] QPLL_INIT_CFG = 24'h000006;
parameter [15:0] QPLL_LOCK_CFG = 16'h05E8;
parameter integer QPLL_REFCLK_DIV = 1;
parameter integer RXOUT_DIV = 1;
parameter integer TXOUT_DIV = 1;
parameter SATA_QPLL_CFG = "VCO_3000MHZ";
parameter [1:0] PMA_RSV3 = 1;
localparam multiplier = QPLL_FBDIV * QPLL_FBDIV_45;
localparam divider = QPLL_REFCLK_DIV;
assign QPLLLOCK = pll_locked;
wire fb_clk_out;
wire reset;
reg mult_clk;
reg mult_dev_clk;
assign clk_out = mult_dev_clk;
// generate internal async reset
assign reset = QPLLPD | QPLLRESET;
// apply multipliers
time last_edge; // reference clock edge's absolute time
time period; // reference clock's period
integer locked_f;
reg locked;
initial
begin
last_edge = 0;
period = 0;
forever @ (posedge ref_clk or posedge reset)
begin
period = reset ? 0 : $time - last_edge;
last_edge = reset ? 0 : $time;
end
end
initial
forever @ (posedge ref_clk)
begin
if (period > 0)
begin
locked_f = 1;
mult_clk = 1'b1;
repeat (multiplier * 2 - 1)
begin
#(period/multiplier/2)
mult_clk = ~mult_clk;
end
end
else
locked_f = 0;
end
// apply dividers
initial
begin
mult_dev_clk = 1'b1;
forever
begin
repeat (divider)
@ (mult_clk);
mult_dev_clk = ~mult_dev_clk;
end
end
// show if 'pll' is locked
always @ (posedge ref_clk or posedge reset)
begin
if (locked_f == 1 && ~reset)
begin
#`GTXE2_COMM_QPLL_LOCK_TIME;
locked <= 1'b1;
end
else
locked <= 1'b0;
end
endmodule
/*******************************************************************************
* Module: gtxe2_comm_qpll_inmux
* Date: 2015-07-06
* Author: Alexey
* Description: non-synthesizable clock multiplexer
*
* Copyright (c) 2015 Elphel, Inc.
* gtxe2_comm_qpll_inmux.v 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.
*
* gtxe2_comm_qpll_inmux.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
module gtxe2_comm_qpll_inmux(
input wire [2:0] QPLLREFCLKSEL,
input wire GTREFCLK0,
input wire GTREFCLK1,
input wire GTNORTHREFCLK0,
input wire GTNORTHREFCLK1,
input wire GTSOUTHREFCLK0,
input wire GTSOUTHREFCLK1,
input wire GTGREFCLK,
output wire QPLL_MUX_CLK_OUT
);
// clock multiplexer - pre-syntesis simulation only
assign QPLL_MUX_CLK_OUT = QPLLREFCLKSEL == 3'b000 ? 1'b0 // reserved
: QPLLREFCLKSEL == 3'b001 ? GTREFCLK0
: QPLLREFCLKSEL == 3'b010 ? GTREFCLK1
: QPLLREFCLKSEL == 3'b011 ? GTNORTHREFCLK0
: QPLLREFCLKSEL == 3'b100 ? GTNORTHREFCLK1
: QPLLREFCLKSEL == 3'b101 ? GTSOUTHREFCLK0
: QPLLREFCLKSEL == 3'b110 ? GTSOUTHREFCLK1
: /*CPLLREFCLKSEL == 3'b111 ?*/ GTGREFCLK;
endmodule
/*******************************************************************************
* Module: tb
* Date: 2015-07-06
* Author: Alexey
* Description: testbench module = gtx_channel as a DUT + test payload module
*
* Copyright (c) 2015 Elphel, Inc.
* tb.v 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.
*
* tb.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale 1ps/1ps
`include "GTXE2_CHANNEL_GPL.v"
`include "test.v"
module tb();
wire reset;
wire TXP;
wire TXN;
wire [63:0] TXDATA;
wire TXUSRCLK;
wire TXUSRCLK2;
wire [7:0] TX8B10BBYPASS;
wire TX8B10BEN;
wire [7:0] TXCHARDISPMODE;
wire [7:0] TXCHARDISPVAL;
wire [7:0] TXCHARISK;
wire [1:0] TXBUFSTATUS;
wire TXPOLARITY;
wire [2:0] TXRATE;
wire [2:0] RXRATE;
wire TXRATEDONE;
wire TXCOMINIT;
wire TXCOMWAKE;
wire TXCOMFINISH;
wire TXELECIDLE;
wire RXP;
wire RXN;
wire RXUSRCLK;
wire RXUSRCLK2;
wire [63:0] RXDATA;
wire [1:0] RXELECIDLEMODE;
wire RXELECIDLE;
wire RXCOMINITDET;
wire RXCOMWAKEDET;
wire RXPOLARITY;
wire RXBYTEISALIGNED;
wire RXBYTEREALIGN;
wire RXCOMMADET;
wire RXCOMMADETEN;
wire RXPCOMMAALIGNEN;
wire RXMCOMMAALIGNEN;
wire RX8B10BEN;
wire [7:0] RXCHARISCOMMA;
wire [7:0] RXCHARISK;
wire [7:0] RXDISPERR;
wire [7:0] RXNOTINTABLE;
wire [2:0] CPLLREFCLKSEL;
wire GTREFCLK0;
wire GTREFCLK1;
wire GTNORTHREFCLK0;
wire GTNORTHREFCLK1;
wire GTSOUTHREFCLK0;
wire GTSOUTHREFCLK1;
wire GTGREFCLK;
wire [1:0] RXSYSCLKSEL;
wire [1:0] TXSYSCLKSEL;
wire [2:0] TXOUTCLKSEL;
wire [2:0] RXOUTCLKSEL;
wire TXDLYBYPASS;
wire GTREFCLKMONITOR;
wire CPLLLOCKDETCLK;
wire CPLLLOCKEN;
wire CPLLPD;
wire CPLLRESET;
wire CPLLFBCLKLOST;
wire CPLLLOCK;
wire CPLLREFCLKLOST;
wire TXOUTCLKPMA;
wire TXOUTCLKPCS;
wire TXOUTCLK;
wire TXOUTCLKFABRIC;
wire tx_serial_clk;
wire RXOUTCLKPMA;
wire RXOUTCLKPCS;
wire RXOUTCLK;
wire RXOUTCLKFABRIC;
wire rx_serial_clk;
wire [2:0] QPLLREFCLKSEL;
wire QPLLOUTCLK;
wire QPLLOUTREFCLK;
wire QPLLLOCKDETCLK;
wire QPLLLOCKEN;
wire QPLLPD;
wire QPLLRESET;
wire QPLLFBCLKLOST;
wire QPLLLOCK;
wire QPLLREFCLKLOST;
wire TXUSERRDY;
wire RXUSERRDY;
wire RXDFELFHOLD;
wire RXDFEAGCHOLD;
wire RXRESETDONE;
wire TXRESETDONE;
test test(
.reset (reset),
.TXP (TXP),
.TXN (TXN),
.TXDATA (TXDATA),
.TXUSRCLK (TXUSRCLK),
.TXUSRCLK2 (TXUSRCLK2),
.TX8B10BBYPASS (TX8B10BBYPASS),
.TX8B10BEN (TX8B10BEN),
.TXCHARDISPMODE (TXCHARDISPMODE),
.TXCHARDISPVAL (TXCHARDISPVAL),
.TXCHARISK (TXCHARISK),
.TXBUFSTATUS (TXBUFSTATUS),
.TXPOLARITY (TXPOLARITY),
.TXRATE (TXRATE),
.RXRATE (RXRATE),
.TXRATEDONE (TXRATEDONE),
.TXCOMINIT (TXCOMINIT),
.TXCOMWAKE (TXCOMWAKE),
.TXCOMFINISH (TXCOMFINISH),
.TXELECIDLE (TXELECIDLE),
.RXP (RXP),
.RXN (RXN),
.RXUSRCLK (RXUSRCLK),
.RXUSRCLK2 (RXUSRCLK2),
.RXDATA (RXDATA),
.RXELECIDLEMODE (RXELECIDLEMODE),
.RXELECIDLE (RXELECIDLE),
.RXCOMINITDET (RXCOMINITDET),
.RXCOMWAKEDET (RXCOMWAKEDET),
.RXPOLARITY (RXPOLARITY),
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (RXBYTEREALIGN),
.RXCOMMADET (RXCOMMADET),
.RXCOMMADETEN (RXCOMMADETEN),
.RXPCOMMAALIGNEN (RXPCOMMAALIGNEN),
.RXMCOMMAALIGNEN (RXMCOMMAALIGNEN),
.RX8B10BEN (RX8B10BEN),
.RXCHARISCOMMA (RXCHARISCOMMA),
.RXCHARISK (RXCHARISK),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.RXUSERRDY (RXUSERRDY),
.TXUSERRDY (TXUSERRDY),
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (GTREFCLK1),
.GTNORTHREFCLK0 (GTNORTHREFCLK0),
.GTNORTHREFCLK1 (GTNORTHREFCLK1),
.GTSOUTHREFCLK0 (GTSOUTHREFCLK0),
.GTSOUTHREFCLK1 (GTSOUTHREFCLK1),
.GTGREFCLK (GTGREFCLK),
.RXSYSCLKSEL (RXSYSCLKSEL),
.TXSYSCLKSEL (TXSYSCLKSEL),
.TXOUTCLKSEL (TXOUTCLKSEL),
.RXOUTCLKSEL (RXOUTCLKSEL),
.TXDLYBYPASS (TXDLYBYPASS),
.GTREFCLKMONITOR (GTREFCLKMONITOR),
.CPLLLOCKDETCLK (CPLLLOCKDETCLK ),
.CPLLLOCKEN (CPLLLOCKEN),
.CPLLPD (CPLLPD),
.CPLLRESET (CPLLRESET),
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.TXOUTCLKPMA (TXOUTCLKPMA),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXOUTCLK (TXOUTCLK),
.TXOUTCLKFABRIC (TXOUTCLKFABRIC),
.tx_serial_clk (tx_serial_clk),
.RXOUTCLKPMA (RXOUTCLKPMA),
.RXOUTCLKPCS (RXOUTCLKPCS),
.RXOUTCLK (RXOUTCLK),
.RXOUTCLKFABRIC (RXOUTCLKFABRIC),
.rx_serial_clk (rx_serial_clk),
.QPLLREFCLKSEL (QPLLREFCLKSEL),
.QPLLOUTCLK (QPLLOUTCLK),
.QPLLOUTREFCLK (QPLLOUTREFCLK),
.QPLLLOCKDETCLK (QPLLLOCKDETCLK ),
.QPLLLOCKEN (QPLLLOCKEN),
.QPLLPD (QPLLPD),
.QPLLRESET (QPLLRESET),
.QPLLFBCLKLOST (QPLLFBCLKLOST),
.QPLLLOCK (QPLLLOCK),
.QPLLREFCLKLOST (QPLLREFCLKLOST),
.RXDFELFHOLD (RXDFELFHOLD),
.RXDFEAGCHOLD (RXDFEAGCHOLD),
.TXRESETDONE (TXRESETDONE),
.RXRESETDONE (RXRESETDONE)
);
GTXE2_CHANNEL #
(
.SIM_RECEIVER_DETECT_PASS ("TRUE"),
.SIM_TX_EIDLE_DRIVE_LEVEL ("X"),
.SIM_RESET_SPEEDUP ("FALSE"),
.SIM_CPLLREFCLK_SEL (3'b001),
.SIM_VERSION ("4.0"),
.ALIGN_COMMA_DOUBLE ("FALSE"),
.ALIGN_COMMA_ENABLE (10'b1111111111),
.ALIGN_COMMA_WORD (1),
.ALIGN_MCOMMA_DET ("TRUE"),
.ALIGN_MCOMMA_VALUE (10'b1010000011),
.ALIGN_PCOMMA_DET ("TRUE"),
.ALIGN_PCOMMA_VALUE (10'b0101111100),
.SHOW_REALIGN_COMMA ("TRUE"),
.RXSLIDE_AUTO_WAIT (7),
.RXSLIDE_MODE ("OFF"),
.RX_SIG_VALID_DLY (10),
.RX_DISPERR_SEQ_MATCH ("TRUE"),
.DEC_MCOMMA_DETECT ("TRUE"),
.DEC_PCOMMA_DETECT ("TRUE"),
.DEC_VALID_COMMA_ONLY ("FALSE"),
.CBCC_DATA_SOURCE_SEL ("DECODED"),
.CLK_COR_SEQ_2_USE ("FALSE"),
.CLK_COR_KEEP_IDLE ("FALSE"),
.CLK_COR_MAX_LAT (9),
.CLK_COR_MIN_LAT (7),
.CLK_COR_PRECEDENCE ("TRUE"),
.CLK_COR_REPEAT_WAIT (0),
.CLK_COR_SEQ_LEN (1),
.CLK_COR_SEQ_1_ENABLE (4'b1111),
.CLK_COR_SEQ_1_1 (10'b0100000000),
.CLK_COR_SEQ_1_2 (10'b0000000000),
.CLK_COR_SEQ_1_3 (10'b0000000000),
.CLK_COR_SEQ_1_4 (10'b0000000000),
.CLK_CORRECT_USE ("FALSE"),
.CLK_COR_SEQ_2_ENABLE (4'b1111),
.CLK_COR_SEQ_2_1 (10'b0100000000),
.CLK_COR_SEQ_2_2 (10'b0000000000),
.CLK_COR_SEQ_2_3 (10'b0000000000),
.CLK_COR_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_KEEP_ALIGN ("FALSE"),
.CHAN_BOND_MAX_SKEW (1),
.CHAN_BOND_SEQ_LEN (1),
.CHAN_BOND_SEQ_1_1 (10'b0000000000),
.CHAN_BOND_SEQ_1_2 (10'b0000000000),
.CHAN_BOND_SEQ_1_3 (10'b0000000000),
.CHAN_BOND_SEQ_1_4 (10'b0000000000),
.CHAN_BOND_SEQ_1_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_1 (10'b0000000000),
.CHAN_BOND_SEQ_2_2 (10'b0000000000),
.CHAN_BOND_SEQ_2_3 (10'b0000000000),
.CHAN_BOND_SEQ_2_4 (10'b0000000000),
.CHAN_BOND_SEQ_2_ENABLE (4'b1111),
.CHAN_BOND_SEQ_2_USE ("FALSE"),
.FTS_DESKEW_SEQ_ENABLE (4'b1111),
.FTS_LANE_DESKEW_CFG (4'b1111),
.FTS_LANE_DESKEW_EN ("FALSE"),
.ES_CONTROL (6'b000000),
.ES_ERRDET_EN ("FALSE"),
.ES_EYE_SCAN_EN ("TRUE"),
.ES_HORZ_OFFSET (12'h000),
.ES_PMA_CFG (10'b0000000000),
.ES_PRESCALE (5'b00000),
.ES_QUALIFIER (80'h00000000000000000000),
.ES_QUAL_MASK (80'h00000000000000000000),
.ES_SDATA_MASK (80'h00000000000000000000),
.ES_VERT_OFFSET (9'b000000000),
.RX_DATA_WIDTH (20),
.OUTREFCLK_SEL_INV (2'b11),
.PMA_RSV (32'h00018480),
.PMA_RSV2 (16'h2050),
.PMA_RSV3 (2'b00),
.PMA_RSV4 (32'h00000000),
.RX_BIAS_CFG (12'b000000000100),
.DMONITOR_CFG (24'h000A00),
.RX_CM_SEL (2'b11),
.RX_CM_TRIM (3'b010),
.RX_DEBUG_CFG (12'b000000000000),
.RX_OS_CFG (13'b0000010000000),
.TERM_RCAL_CFG (5'b10000),
.TERM_RCAL_OVRD (1'b0),
.TST_RSV (32'h00000000),
.RX_CLK25_DIV (6),
.TX_CLK25_DIV (6),
.UCODEER_CLR (1'b0),
.PCS_PCIE_EN ("FALSE"),
.PCS_RSVD_ATTR (48'h0100),
.RXBUF_ADDR_MODE ("FAST"),
.RXBUF_EIDLE_HI_CNT (4'b1000),
.RXBUF_EIDLE_LO_CNT (4'b0000),
.RXBUF_EN ("TRUE"),
.RX_BUFFER_CFG (6'b000000),
.RXBUF_RESET_ON_CB_CHANGE ("TRUE"),
.RXBUF_RESET_ON_COMMAALIGN ("FALSE"),
.RXBUF_RESET_ON_EIDLE ("FALSE"),
.RXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.RXBUFRESET_TIME (5'b00001),
.RXBUF_THRESH_OVFLW (61),
.RXBUF_THRESH_OVRD ("FALSE"),
.RXBUF_THRESH_UNDFLW (4),
.RXDLY_CFG (16'h001F),
.RXDLY_LCFG (9'h030),
.RXDLY_TAP_CFG (16'h0000),
.RXPH_CFG (24'h000000),
.RXPHDLY_CFG (24'h084020),
.RXPH_MONITOR_SEL (5'b00000),
.RX_XCLK_SEL ("RXREC"),
.RX_DDI_SEL (6'b000000),
.RX_DEFER_RESET_BUF_EN ("TRUE"),
.RXCDR_CFG (72'h03000023ff10200020),
.RXCDR_FR_RESET_ON_EIDLE (1'b0),
.RXCDR_HOLD_DURING_EIDLE (1'b0),
.RXCDR_PH_RESET_ON_EIDLE (1'b0),
.RXCDR_LOCK_CFG (6'b010101),
.RXCDRFREQRESET_TIME (5'b00001),
.RXCDRPHRESET_TIME (5'b00001),
.RXISCANRESET_TIME (5'b00001),
.RXPCSRESET_TIME (5'b00001),
.RXPMARESET_TIME (5'b00011),
.RXOOB_CFG (7'b0000110),
.RXGEARBOX_EN ("FALSE"),
.GEARBOX_MODE (3'b000),
.RXPRBS_ERR_LOOPBACK (1'b0),
.PD_TRANS_TIME_FROM_P2 (12'h03c),
.PD_TRANS_TIME_NONE_P2 (8'h3c),
.PD_TRANS_TIME_TO_P2 (8'h64),
.SAS_MAX_COM (64),
.SAS_MIN_COM (36),
.SATA_BURST_SEQ_LEN (4'b0111),
.SATA_BURST_VAL (3'b110),
.SATA_EIDLE_VAL (3'b110),
.SATA_MAX_BURST (8),
.SATA_MAX_INIT (21),
.SATA_MAX_WAKE (7),
.SATA_MIN_BURST (4),
.SATA_MIN_INIT (12),
.SATA_MIN_WAKE (4),
.TRANS_TIME_RATE (8'h0E),
.TXBUF_EN ("TRUE"),
.TXBUF_RESET_ON_RATE_CHANGE ("TRUE"),
.TXDLY_CFG (16'h001F),
.TXDLY_LCFG (9'h030),
.TXDLY_TAP_CFG (16'h0000),
.TXPH_CFG (16'h0780),
.TXPHDLY_CFG (24'h084020),
.TXPH_MONITOR_SEL (5'b00000),
.TX_XCLK_SEL ("TXOUT"),
.TX_DATA_WIDTH (20),
.TX_DEEMPH0 (5'b00000),
.TX_DEEMPH1 (5'b00000),
.TX_EIDLE_ASSERT_DELAY (3'b110),
.TX_EIDLE_DEASSERT_DELAY (3'b100),
.TX_LOOPBACK_DRIVE_HIZ ("FALSE"),
.TX_MAINCURSOR_SEL (1'b0),
.TX_DRIVE_MODE ("DIRECT"),
.TX_MARGIN_FULL_0 (7'b1001110),
.TX_MARGIN_FULL_1 (7'b1001001),
.TX_MARGIN_FULL_2 (7'b1000101),
.TX_MARGIN_FULL_3 (7'b1000010),
.TX_MARGIN_FULL_4 (7'b1000000),
.TX_MARGIN_LOW_0 (7'b1000110),
.TX_MARGIN_LOW_1 (7'b1000100),
.TX_MARGIN_LOW_2 (7'b1000010),
.TX_MARGIN_LOW_3 (7'b1000000),
.TX_MARGIN_LOW_4 (7'b1000000),
.TXGEARBOX_EN ("FALSE"),
.TXPCSRESET_TIME (5'b00001),
.TXPMARESET_TIME (5'b00001),
.TX_RXDETECT_CFG (14'h1832),
.TX_RXDETECT_REF (3'b100),
.CPLL_CFG (24'hBC07DC),
.CPLL_FBDIV (4),
.CPLL_FBDIV_45 (5),
.CPLL_INIT_CFG (24'h00001E),
.CPLL_LOCK_CFG (16'h01E8),
.CPLL_REFCLK_DIV (1),
.RXOUT_DIV (2),
.TXOUT_DIV (2),
.SATA_CPLL_CFG ("VCO_3000MHZ"),
.RXDFELPMRESET_TIME (7'b0001111),
.RXLPM_HF_CFG (14'b00000011110000),
.RXLPM_LF_CFG (14'b00000011110000),
.RX_DFE_GAIN_CFG (23'h020FEA),
.RX_DFE_H2_CFG (12'b000000000000),
.RX_DFE_H3_CFG (12'b000001000000),
.RX_DFE_H4_CFG (11'b00011110000),
.RX_DFE_H5_CFG (11'b00011100000),
.RX_DFE_KL_CFG (13'b0000011111110),
.RX_DFE_LPM_CFG (16'h0954),
.RX_DFE_LPM_HOLD_DURING_EIDLE (1'b0),
.RX_DFE_UT_CFG (17'b10001111000000000),
.RX_DFE_VP_CFG (17'b00011111100000011),
.RX_CLKMUX_PD (1'b1),
.TX_CLKMUX_PD (1'b1),
.RX_INT_DATAWIDTH (0),
.TX_INT_DATAWIDTH (0),
.TX_QPI_STATUS_EN (1'b0),
.RX_DFE_KL_CFG2 (32'h301148AC),
.RX_DFE_XYD_CFG (13'b0000000000000),
.TX_PREDRIVER_MODE (1'b0)
)
dut
(
.CPLLFBCLKLOST (CPLLFBCLKLOST),
.CPLLLOCK (CPLLLOCK),
.CPLLLOCKDETCLK (CPLLLOCKDETCLK),
.CPLLLOCKEN (1'b1),
.CPLLPD (CPLLPD),
.CPLLREFCLKLOST (CPLLREFCLKLOST),
.CPLLREFCLKSEL (CPLLREFCLKSEL),
.CPLLRESET (CPLLRESET),
.GTRSVD (1'b0),
.PCSRSVDIN (1'b0),
.PCSRSVDIN2 (1'b0),
.PMARSVDIN (1'b0),
.PMARSVDIN2 (1'b0),
.TSTIN (1'b1),
.TSTOUT (),
.CLKRSVD (4'b0000),
.GTGREFCLK (1'b0),
.GTNORTHREFCLK0 (1'b0),
.GTNORTHREFCLK1 (1'b0),
.GTREFCLK0 (GTREFCLK0),
.GTREFCLK1 (1'b0),
.GTSOUTHREFCLK0 (1'b0),
.GTSOUTHREFCLK1 (1'b0),
.DRPADDR (9'b0),
.DRPCLK (CPLLLOCKDETCKL),
.DRPDI (16'b0),
.DRPDO (),
.DRPEN (1'b0),
.DRPRDY (),
.DRPWE (1'b0),
.GTREFCLKMONITOR (),
.QPLLCLK (GTREFCLK0),
.QPLLREFCLK (GTREFCLK0),
.RXSYSCLKSEL (2'b00),
.TXSYSCLKSEL (2'b00),
.DMONITOROUT (),
.TX8B10BEN (1'b1),
.LOOPBACK (3'd0),
.PHYSTATUS (),
.RXRATE (3'd0),
.RXVALID (),
.RXPD (2'b00),
.TXPD (2'b00),
.SETERRSTATUS (1'b0),
.EYESCANRESET (reset),
.RXUSERRDY (RXUSERRDY),
.EYESCANDATAERROR (EYESCANDATAERROR),
.EYESCANMODE (1'b0),
.EYESCANTRIGGER (1'b0),
.RXCDRFREQRESET (1'b0),
.RXCDRHOLD (1'b0),
.RXCDRLOCK (),
.RXCDROVRDEN (1'b0),
.RXCDRRESET (1'b0),
.RXCDRRESETRSV (1'b0),
.RXCLKCORCNT (),
.RX8B10BEN (1'b1),
.RXUSRCLK (RXUSRCLK),
.RXUSRCLK2 (RXUSRCLK2),
.RXDATA (RXDATA),
.RXPRBSERR (),
.RXPRBSSEL (3'd0),
.RXPRBSCNTRESET (1'b0),
.RXDFEXYDEN (1'b1),
.RXDFEXYDHOLD (1'b0),
.RXDFEXYDOVRDEN (1'b0),
.RXDISPERR (RXDISPERR),
.RXNOTINTABLE (RXNOTINTABLE),
.GTXRXP (RXP),
.GTXRXN (RXN),
.RXBUFRESET (1'b0),
.RXBUFSTATUS (),
.RXDDIEN (1'b0),
.RXDLYBYPASS (1'b1),
.RXDLYEN (1'b0),
.RXDLYOVRDEN (1'b0),
.RXDLYSRESET (1'b0),
.RXDLYSRESETDONE (),
.RXPHALIGN (1'b0),
.RXPHALIGNDONE (),
.RXPHALIGNEN (1'b0),
.RXPHDLYPD (1'b0),
.RXPHDLYRESET (1'b0),
.RXPHMONITOR (),
.RXPHOVRDEN (1'b0),
.RXPHSLIPMONITOR (),
.RXSTATUS (),
.RXBYTEISALIGNED (RXBYTEISALIGNED),
.RXBYTEREALIGN (),
.RXCOMMADET (),
.RXCOMMADETEN (1'b1),
.RXMCOMMAALIGNEN (1'b1),
.RXPCOMMAALIGNEN (1'b1),
.RXCHANBONDSEQ (),
.RXCHBONDEN (1'b0),
.RXCHBONDLEVEL (3'd0),
.RXCHBONDMASTER (1'b0),
.RXCHBONDO (),
.RXCHBONDSLAVE (1'b0),
.RXCHANISALIGNED (),
.RXCHANREALIGN (),
.RXLPMHFHOLD (1'b0),
.RXLPMHFOVRDEN (1'b0),
.RXLPMLFHOLD (1'b0),
.RXDFEAGCHOLD (RXDFEAGCHOLD),
.RXDFEAGCOVRDEN (1'b0),
.RXDFECM1EN (1'b0),
.RXDFELFHOLD (RXDFELFHOLD),
.RXDFELFOVRDEN (1'b1),
.RXDFELPMRESET (reset),
.RXDFETAP2HOLD (1'b0),
.RXDFETAP2OVRDEN (1'b0),
.RXDFETAP3HOLD (1'b0),
.RXDFETAP3OVRDEN (1'b0),
.RXDFETAP4HOLD (1'b0),
.RXDFETAP4OVRDEN (1'b0),
.RXDFETAP5HOLD (1'b0),
.RXDFETAP5OVRDEN (1'b0),
.RXDFEUTHOLD (1'b0),
.RXDFEUTOVRDEN (1'b0),
.RXDFEVPHOLD (1'b0),
.RXDFEVPOVRDEN (1'b0),
// .RXDFEVSEN (1'b0),
.RXLPMLFKLOVRDEN (1'b0),
.RXMONITOROUT (),
.RXMONITORSEL (),
.RXOSHOLD (1'b0),
.RXOSOVRDEN (1'b0),
.RXRATEDONE (),
.RXOUTCLK (RXOUTCLK),
.RXOUTCLKFABRIC (),
.RXOUTCLKPCS (),
.RXOUTCLKSEL (3'b010),
.RXDATAVALID (),
.RXHEADER (),
.RXHEADERVALID (),
.RXSTARTOFSEQ (),
.RXGEARBOXSLIP (1'b0),
.GTRXRESET (reset),
.RXOOBRESET (1'b0),
.RXPCSRESET (1'b0),
.RXPMARESET (reset),
.RXLPMEN (1'b0),
.RXCOMSASDET (),
.RXCOMWAKEDET (RXCOMWAKEDET),
.RXCOMINITDET (RXCOMINITDET),
.RXELECIDLE (RXELECIDLE),
.RXELECIDLEMODE (2'b00),
.RXPOLARITY (1'b0),
.RXSLIDE (1'b0),
.RXCHARISCOMMA (),
.RXCHARISK (RXCHARISK),
.RXCHBONDI (5'b00000),
.RXRESETDONE (RXRESETDONE),
.RXQPIEN (1'b0),
.RXQPISENN (),
.RXQPISENP (),
.TXPHDLYTSTCLK (1'b0),
.TXPOSTCURSOR (5'b00000),
.TXPOSTCURSORINV (1'b0),
.TXPRECURSOR (5'd0),
.TXPRECURSORINV (1'b0),
.TXQPIBIASEN (1'b0),
.TXQPISTRONGPDOWN (1'b0),
.TXQPIWEAKPUP (1'b0),
.CFGRESET (1'b0),
.GTTXRESET (reset),
.PCSRSVDOUT (),
.TXUSERRDY (TXUSERRDY),
.GTRESETSEL (1'b0),
.RESETOVRD (1'b0),
.TXCHARDISPMODE (8'd0),
.TXCHARDISPVAL (8'd0),
.TXUSRCLK (TXUSRCLK),
.TXUSRCLK2 (TXUSRCLK2),
.TXELECIDLE (TXELECIDLE),
.TXMARGIN (3'd0),
.TXRATE (3'd0),
.TXSWING (1'b0),
.TXPRBSFORCEERR (1'b0),
.TXDLYBYPASS (1'b1),
.TXDLYEN (1'b0),
.TXDLYHOLD (1'b0),
.TXDLYOVRDEN (1'b0),
.TXDLYSRESET (1'b0),
.TXDLYSRESETDONE (),
.TXDLYUPDOWN (1'b0),
.TXPHALIGN (1'b0),
.TXPHALIGNDONE (),
.TXPHALIGNEN (1'b0),
.TXPHDLYPD (1'b0),
.TXPHDLYRESET (1'b0),
.TXPHINIT (1'b0),
.TXPHINITDONE (),
.TXPHOVRDEN (1'b0),
.TXBUFSTATUS (),
.TXBUFDIFFCTRL (3'b100),
.TXDEEMPH (1'b0),
.TXDIFFCTRL (4'b1000),
.TXDIFFPD (1'b0),
.TXINHIBIT (1'b0),
.TXMAINCURSOR (7'b0000000),
.TXPISOPD (1'b0),
.TXDATA (TXDATA),
.GTXTXN (TXN),
.GTXTXP (TXP),
.TXOUTCLK (TXOUTCLK),
.TXOUTCLKFABRIC (TXOUTCLKFABRIC),
.TXOUTCLKPCS (TXOUTCLKPCS),
.TXOUTCLKSEL (3'b010),
.TXRATEDONE (),
.TXCHARISK (TXCHARISK),
.TXGEARBOXREADY (),
.TXHEADER (3'd0),
.TXSEQUENCE (7'd0),
.TXSTARTSEQ (1'b0),
.TXPCSRESET (1'b0),
.TXPMARESET (1'b0),
.TXRESETDONE (TXRESETDONE),
.TXCOMFINISH (TXCOMFINISH),
.TXCOMINIT (TXCOMINIT),
.TXCOMSAS (1'b0),
.TXCOMWAKE (TXCOMWAKE),
.TXPDELECIDLEMODE (1'b0),
.TXPOLARITY (1'b0),
.TXDETECTRX (1'b0),
.TX8B10BBYPASS (8'd0),
.TXPRBSSEL (3'd0),
.TXQPISENN (),
.TXQPISENP ()
);
endmodule
/*******************************************************************************
* Module: test
* Date: 2015-07-06
* Author: Alexey
* Description: Generates test payload for GTXE2_CHANNEL
*
* Copyright (c) 2015 Elphel, Inc.
* test.v 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.
*
* test.v file 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. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
/*
* simple aligner test + oob + checking for a corrent decoding
*/
module test(
output wire reset,
output wire rx_early_reset,
input wire TXRESETDONE,
input wire RXRESETDONE,
/*
* TX
*/
input wire TXP,
input wire TXN,
output wire [63:0] TXDATA,
output wire TXUSRCLK,
output wire TXUSRCLK2,
output wire TXUSERRDY,
// 8/10 encoder
output wire [7:0] TX8B10BBYPASS,
output wire TX8B10BEN,
output wire [7:0] TXCHARDISPMODE,
output wire [7:0] TXCHARDISPVAL,
output wire [7:0] TXCHARISK,
// TX Buffer
input wire [1:0] TXBUFSTATUS,
// TX Polarity
output wire TXPOLARITY,
// TX Fabric Clock Control
output wire [2:0] TXRATE,
input wire TXRATEDONE,
// TX OOB
output wire TXCOMINIT,
output wire TXCOMWAKE,
input wire TXCOMFINISH,
// TX Driver Control
output wire TXELECIDLE,
/*
* RX
*/
output wire RXP,
output wire RXN,
output wire RXUSRCLK,
output wire RXUSRCLK2,
output wire RXUSERRDY,
input wire [63:0] RXDATA,
output wire [2:0] RXRATE,
// oob
output wire [1:0] RXELECIDLEMODE,
input wire RXELECIDLE,
input wire RXCOMINITDET,
input wire RXCOMWAKEDET,
// polarity
output wire RXPOLARITY,
// aligner
input wire RXBYTEISALIGNED,
input wire RXBYTEREALIGN,
input wire RXCOMMADET,
output wire RXCOMMADETEN,
output wire RXPCOMMAALIGNEN,
output wire RXMCOMMAALIGNEN,
// 10/8 decoder
output wire RX8B10BEN,
input wire [7:0] RXCHARISCOMMA,
input wire [7:0] RXCHARISK,
input wire [7:0] RXDISPERR,
input wire [7:0] RXNOTINTABLE,
/*
* Clocking
*/
// top-level interfaces
output wire [2:0] CPLLREFCLKSEL,
output wire GTREFCLK0,
output wire GTREFCLK1,
output wire GTNORTHREFCLK0,
output wire GTNORTHREFCLK1,
output wire GTSOUTHREFCLK0,
output wire GTSOUTHREFCLK1,
output wire GTGREFCLK,
output wire [1:0] RXSYSCLKSEL,
output wire [1:0] TXSYSCLKSEL,
output wire [2:0] TXOUTCLKSEL,
output wire [2:0] RXOUTCLKSEL,
output wire TXDLYBYPASS,
input wire GTREFCLKMONITOR,
output wire CPLLLOCKDETCLK,
output wire CPLLLOCKEN,
output wire CPLLPD,
output wire CPLLRESET,
input wire CPLLFBCLKLOST,
input wire CPLLLOCK,
input wire CPLLREFCLKLOST,
// phy-level interfaces
input wire TXOUTCLKPMA,
input wire TXOUTCLKPCS,
input wire TXOUTCLK,
input wire TXOUTCLKFABRIC,
input wire tx_serial_clk,
input wire RXOUTCLKPMA,
input wire RXOUTCLKPCS,
input wire RXOUTCLK,
input wire RXOUTCLKFABRIC,
input wire rx_serial_clk,
output wire RXDFELFHOLD,
output wire RXDFEAGCHOLD,
/*
* GTXE2_COMMON
*/
output wire [2:0] QPLLREFCLKSEL,
input wire QPLLOUTCLK,
input wire QPLLOUTREFCLK,
output wire QPLLLOCKDETCLK,
output wire QPLLLOCKEN,
output wire QPLLPD,
output wire QPLLRESET,
input wire QPLLFBCLKLOST,
input wire QPLLLOCK,
input wire QPLLREFCLKLOST
);
reg gtxreset;
reg hard_rst;
initial #1 $display("HI THERE");
initial
begin
$dumpfile("test.vcd");
$dumpvars(0,tb);
end
// simulation stop condition
initial
// #10000 $stop;
#100000000 $finish;
// ref clock
reg clk = 1'b0;
always #3000
clk = ~clk;
// reset
initial
begin
hard_rst = 1'b0;
#1000000;
hard_rst <= 1'b1;
#1000000;
hard_rst <= 1'b0;
end
initial
begin
gtxreset = 1'b0;
@ (negedge hard_rst);
gtxreset <= 1'b1;
#1000000;
gtxreset <= 1'b0;
end
// data
reg [15:0] data;
reg align_switch = 0;
reg [7:0] control = 0;
assign TXDATA = {47'h0, data};
initial
begin
data = 16'h0;
@ (negedge reset);
// @ (negedge reset);
//#2000000;
@ (posedge RXCOMWAKEDET or posedge TXCOMFINISH);
@ (posedge RXCOMWAKEDET or posedge TXCOMFINISH);
/* repeat (30)
@ (posedge clk);
@ (posedge clk) data <= 16'hde;
@ (posedge clk) data <= 16'had;
@ (posedge clk) data <= 16'hbe;
@ (posedge clk) data <= 16'hef;*/
repeat (30)
@ (posedge clk);
align_switch <= 1'b1;
@ (posedge clk) data <= 16'hde;
@ (posedge clk) data <= 16'had;
@ (posedge clk) data <= 16'hbe;
@ (posedge clk) data <= 16'hef;
@ (posedge clk) data <= 16'hbc; //comma
control <= 8'b01;
@ (posedge clk) data <= 16'hde;
control <= 8'b00;
@ (posedge clk) data <= 16'had;
@ (posedge clk) data <= 16'hbe;
@ (posedge clk) data <= 16'hef;
@ (posedge clk) data <= 16'hbc; //comma
control <= 8'b01;
@ (posedge clk) data <= 16'hde;
control <= 8'b00;
@ (posedge clk) data <= 16'had;
@ (posedge clk) data <= 16'hbe;
@ (posedge clk) data <= 16'hef;
end
assign TXCHARISK = control;
// oob
reg oob_idle;
reg oob_init;
reg oob_wake;
assign TXELECIDLE = oob_idle;
assign TXCOMINIT = oob_init;
assign TXCOMWAKE = oob_wake;
initial
begin
oob_idle = 0;
oob_init = 0;
oob_wake = 0;
#1000000;
// @ (negedge reset);
// @ (negedge reset);
@ (posedge RXRESETDONE or TXRESETDONE);
@ (posedge RXRESETDONE or TXRESETDONE);
#2000000;
repeat (10)
@ (posedge clk);
@ (posedge clk) oob_idle <= 1'b1;
@ (posedge clk) oob_init <= 1'b1;
@ (posedge clk) oob_init <= 1'b0;
@ (posedge RXCOMINITDET or posedge TXCOMFINISH);
@ (posedge RXCOMINITDET or posedge TXCOMFINISH);
@ (posedge clk);
@ (posedge clk) oob_wake <= 1'b1;
@ (posedge clk) oob_wake <= 1'b0;
@ (posedge RXCOMWAKEDET or posedge TXCOMFINISH);
@ (posedge RXCOMWAKEDET or posedge TXCOMFINISH);
repeat (5)
@ (posedge clk);
@ (posedge clk) oob_idle <= 1'b0;
end
/*
* TXUSERRDY/RXUSERRDY
*/
reg rx_userrdy = 1'b0;
reg tx_userrdy = 1'b0;
initial
begin
@ (negedge gtxreset);
repeat (100)
@ (posedge RXUSRCLK);
rx_userrdy <= 1'b1;
end
initial
begin
@ (negedge gtxreset);
repeat (100)
@ (posedge TXUSRCLK);
tx_userrdy <= 1'b1;
end
/*
* Make some disalignments
*/
/*reg xn;
reg xp;
always @ (posedge rx_serial_clk)
begin
xp <= TXP;
xn <= TXN;
end*/
reg [10:0] xn;
reg [10:0] xp;
always #300 //every serial clk
begin
xn[0] <= TXN;
xp[0] <= TXP;
xp[10:1] <= xp[9:0];
xn[10:1] <= xn[9:0];
end
assign RXN = align_switch ? xn[10] : TXN;
assign RXP = align_switch ? xp[10] : TXP;
/*
* loopbacks
*/
assign CPLLRESET = hard_rst;
assign QPLLRESET = hard_rst;
assign reset = ~CPLLLOCK | gtxreset | hard_rst;
assign TXUSERRDY = tx_userrdy;
assign RXUSERRDY = rx_userrdy;
assign CPLLPD = 1'b0;
assign QPLLPD = 1'b0;
assign GTREFCLK0 = clk; // 150Mhz
assign TXUSRCLK = TXOUTCLK;
assign TXUSRCLK2 = TXOUTCLK;
assign RXUSRCLK = TXOUTCLK;
assign RXUSRCLK2 = TXOUTCLK;
assign TXSYSCLKSEL = 2'b00;
assign RXSYSCLKSEL = 2'b00;
assign CPLLREFCLKSEL = 3'b001;
assign RXOUTCLKSEL = 3'b011;
assign TXOUTCLKSEL = 3'b011;
assign TXPOLARITY = 1'b0;
assign RXPOLARITY = 1'b0;
assign RXPCOMMAALIGNEN = 1'b1;
assign RXMCOMMAALIGNEN = 1'b1;
assign RXCOMMADETEN = 1'b1;
assign TXRATE = 3'b010;
assign RXRATE = 3'b010;
assign RXDFELFHOLD = 1'b0;
assign RXDFEAGCHOLD = 1'b0;
/*
* IP only : cplllockdetclk
*/
reg cplldetclk = 0;
assign CPLLLOCKDETCLK = cplldetclk;
always #8000
cplldetclk = ~cplldetclk;
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment