Commit 886f1771 authored by Alexey Grebenkin's avatar Alexey Grebenkin

initial v0.1 files

parent 10d25413
This diff is collapsed.
`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
`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
`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
`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
`define GTXE2_CHNL_CPLL_LOCK_TIME 60
// 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_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
`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)
);
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
This diff is collapsed.
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;
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];
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);
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
// 20-bit width only, for now
// assuming inclk and outclk are completely aligned (have the same source)
`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,
// input wire idle_in,
output wire [width - 1:0] outdata
// output wire idle_out
);
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 #(
parameter width = 20,
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
);
// parameters are not used for now
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
`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 #(
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;
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 #(
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
// 20-bit width only, for now
// assuming inclk and outclk are completely aligned (have the same source)
`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
// 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
`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
`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
`define GTXE2_COMM_QPLL_LOCK_TIME 100
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
This diff is collapsed.
/*
* simple align test
*/
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