From 4b97ec74f89fdeb5d0f429f508fe79dce32b74d7 Mon Sep 17 00:00:00 2001 From: "Matthew.Blanton" Date: Mon, 8 Jan 2024 10:22:21 -0500 Subject: [PATCH 1/2] Changes to help with timing --- library/common/ad_mem_dist.v | 33 +++ .../axi_jesd204_common/jesd204_up_sysref.v | 6 +- .../jesd204/axi_jesd204_common/up_clock_mon.v | 146 +++++++++++ .../up_clock_mon_constr.xdc | 9 + .../jesd204/axi_jesd204_rx/axi_jesd204_rx.v | 15 +- .../axi_jesd204_rx/axi_jesd204_rx_constr.xdc | 55 ++-- .../jesd204/axi_jesd204_rx/jesd204_up_rx.v | 7 +- .../jesd204/axi_jesd204_tx/axi_jesd204_tx.v | 6 +- .../axi_jesd204_tx/axi_jesd204_tx_constr.xdc | 65 +++-- library/jesd204/jesd204_common/up_axi.v | 239 ++++++++++++++++++ .../jesd204_rx/jesd204_lane_latency_monitor.v | 2 +- library/jesd204/jesd204_rx/jesd204_rx.xdc | 2 + .../jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v | 34 +-- .../jesd204/jesd204_rx/jesd204_rx_lane_64b.v | 34 ++- library/jesd204/jesd204_tx/jesd204_tx.v | 56 +++- library/jesd204/jesd204_tx/jesd204_tx.xdc | 2 + .../jesd204/jesd204_tx/jesd204_tx_lane_64b.v | 2 +- 17 files changed, 624 insertions(+), 89 deletions(-) create mode 100755 library/common/ad_mem_dist.v create mode 100644 library/jesd204/axi_jesd204_common/up_clock_mon.v create mode 100644 library/jesd204/axi_jesd204_common/up_clock_mon_constr.xdc mode change 100644 => 100755 library/jesd204/axi_jesd204_tx/axi_jesd204_tx_constr.xdc create mode 100644 library/jesd204/jesd204_common/up_axi.v create mode 100755 library/jesd204/jesd204_rx/jesd204_rx.xdc mode change 100644 => 100755 library/jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v mode change 100644 => 100755 library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v create mode 100755 library/jesd204/jesd204_tx/jesd204_tx.xdc mode change 100644 => 100755 library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v diff --git a/library/common/ad_mem_dist.v b/library/common/ad_mem_dist.v new file mode 100755 index 0000000000..29d8ee7955 --- /dev/null +++ b/library/common/ad_mem_dist.v @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////////// +// Company: Analog Devices, Inc. +// Engineer: MBB +// Simple dual-port distributed RAM with non-registered output +////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ps / 1ps +`default_nettype none + +module dual_port_dist_ram #( + parameter RAM_WIDTH = 32, + parameter RAM_ADDR_BITS = 4 +)( + output wire [RAM_WIDTH-1:0] rd_data, + input wire clk, + input wire wr_en, + input wire [RAM_ADDR_BITS-1:0] wr_addr, + input wire [RAM_WIDTH-1:0] wr_data, + input wire [RAM_ADDR_BITS-1:0] rd_addr +); + + (* ram_style="distributed" *) + reg [RAM_WIDTH-1:0] ram [(2**RAM_ADDR_BITS)-1:0]; + + always @(posedge clk) + if (wr_en) + ram[wr_addr] <= wr_data; + + assign rd_data = ram[rd_addr]; + +endmodule + +`default_nettype wire diff --git a/library/jesd204/axi_jesd204_common/jesd204_up_sysref.v b/library/jesd204/axi_jesd204_common/jesd204_up_sysref.v index 1415889191..88b1ce07ee 100755 --- a/library/jesd204/axi_jesd204_common/jesd204_up_sysref.v +++ b/library/jesd204/axi_jesd204_common/jesd204_up_sysref.v @@ -44,7 +44,9 @@ `timescale 1ns/100ps -module jesd204_up_sysref ( +module jesd204_up_sysref #( + parameter DATA_PATH_WIDTH_LOG2 = 0 +) ( input up_clk, input up_reset, @@ -127,7 +129,7 @@ module jesd204_up_sysref ( end 12'h041: begin /* Must be aligned to data path width */ - up_cfg_lmfc_offset <= up_wdata; + up_cfg_lmfc_offset <= up_wdata[9:DATA_PATH_WIDTH_LOG2]; end endcase end diff --git a/library/jesd204/axi_jesd204_common/up_clock_mon.v b/library/jesd204/axi_jesd204_common/up_clock_mon.v new file mode 100644 index 0000000000..01a8258c64 --- /dev/null +++ b/library/jesd204/axi_jesd204_common/up_clock_mon.v @@ -0,0 +1,146 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. +// +// In this HDL repository, there are many different and unique modules, consisting +// of various HDL (Verilog or VHDL) components. The individual modules are +// developed independently, and may be accompanied by separate and unique license +// terms. +// +// The user should read each of these license terms, and understand the +// freedoms and responsibilities that he or she has by using this source/core. +// +// This core 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. +// +// Redistribution and use of source or resulting binaries, with or without modification +// of this file, are permitted under one of the following two license terms: +// +// 1. The GNU General Public License version 2 as published by the +// Free Software Foundation, which can be found in the top level directory +// of this repository (LICENSE_GPL2), and also online at: +// +// +// OR +// +// 2. An ADI specific BSD license, which can be found in the top level directory +// of this repository (LICENSE_ADIBSD), and also on-line at: +// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD +// This will allow to generate bit files and not release the source code, +// as long as it attaches to an ADI device. +// +// *************************************************************************** +// *************************************************************************** + +`timescale 1ns/100ps + +module up_clock_mon #( + parameter TOTAL_WIDTH = 32 +) ( + + // processor interface + + input up_rstn, + input up_clk, + output reg [TOTAL_WIDTH-1:0] up_d_count, + + // device interface + + input d_rst, + input d_clk); + + // internal registers + + reg [15:0] up_count = 'd1; + reg up_count_run = 'd0; + reg up_count_running_m1 = 'd0; + reg up_count_running_m2 = 'd0; + reg up_count_running_m3 = 'd0; + reg d_count_run_m1 = 'd0; + reg d_count_run_m2 = 'd0; + reg d_count_run_m3 = 'd0; + reg [TOTAL_WIDTH:0] d_count = 'd0; + + // internal signals + + wire up_count_capture_s; + wire d_count_reset_s; + + // processor reference + + // Capture on the falling edge of running + assign up_count_capture_s = up_count_running_m3 == 1'b1 && up_count_running_m2 == 1'b0; + + always @(posedge up_clk) begin + if (up_rstn == 0) begin + up_count_running_m1 <= 1'b0; + up_count_running_m2 <= 1'b0; + up_count_running_m3 <= 1'b0; + end else begin + up_count_running_m1 <= d_count_run_m3; + up_count_running_m2 <= up_count_running_m1; + up_count_running_m3 <= up_count_running_m2; + end + end + + always @(posedge up_clk) begin + if (up_rstn == 0) begin + up_d_count <= 'd0; + up_count_run <= 1'b0; + end else begin + if (up_count_running_m3 == 1'b0) begin + up_count_run <= 1'b1; + end else if (up_count == 'h00) begin + up_count_run <= 1'b0; + end + + if (up_count_capture_s == 1'b1) begin + up_d_count <= d_count[TOTAL_WIDTH-1:0]; + end else if (up_count == 'h00 && up_count_run != up_count_running_m3) begin + up_d_count <= 'h00; + end + end + end + + always @(posedge up_clk) begin + if (up_count_run == 1'b0 && up_count_running_m3 == 1'b0) begin + up_count <= 'h01; + end else begin + up_count <= up_count + 1'b1; + end + end + + // device free running + + // Reset on the rising edge of run + assign d_count_reset_s = d_count_run_m3 == 1'b0 && d_count_run_m2 == 1'b1; + + always @(posedge d_clk or posedge d_rst) begin + if (d_rst == 1'b1) begin + d_count_run_m1 <= 1'b0; + d_count_run_m2 <= 1'b0; + d_count_run_m3 <= 1'b0; + end else begin + d_count_run_m1 <= up_count_run; + d_count_run_m2 <= d_count_run_m1; + d_count_run_m3 <= d_count_run_m2; + end + end + + always @(posedge d_clk) begin + if (d_count_reset_s == 1'b1) begin + d_count <= 'h00; + end else if (d_count_run_m3 == 1'b1) begin + if (d_count[TOTAL_WIDTH] == 1'b0) begin + d_count <= d_count + 1'b1; + end else begin + d_count <= {TOTAL_WIDTH+1{1'b1}}; + end + end + end + +endmodule + +// *************************************************************************** +// *************************************************************************** diff --git a/library/jesd204/axi_jesd204_common/up_clock_mon_constr.xdc b/library/jesd204/axi_jesd204_common/up_clock_mon_constr.xdc new file mode 100644 index 0000000000..71e73a9277 --- /dev/null +++ b/library/jesd204/axi_jesd204_common/up_clock_mon_constr.xdc @@ -0,0 +1,9 @@ + +set_property ASYNC_REG true [get_cells -hierarchical -filter {name =~ *up_count_running_m*}] +set_property ASYNC_REG true [get_cells -hierarchical -filter {name =~ *d_count_run_m*}] +set_property ASYNC_REG true [get_cells -hierarchical -filter {name =~ *up_d_count_reg*}] + +set_false_path -from [get_cells -hierarchical -filter {name =~ *d_count_run_m3_reg* && IS_SEQUENTIAL}] -to [get_cells -hierarchical -filter {name =~ *up_count_running_m1_reg* && IS_SEQUENTIAL}] +set_false_path -from [get_cells -hierarchical -filter {name =~ *up_count_run_reg* && IS_SEQUENTIAL}] -to [get_cells -hierarchical -filter {name =~ *d_count_run_m1_reg* && IS_SEQUENTIAL}] +set_false_path -from [get_cells -hierarchical -filter {name =~ *d_count_reg* && IS_SEQUENTIAL}] -to [get_cells -hierarchical -filter {name =~ *up_d_count_reg* && IS_SEQUENTIAL}] + diff --git a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v index 899d14aa54..d5e87e4bb4 100755 --- a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v +++ b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v @@ -129,7 +129,9 @@ module axi_jesd204_rx #( localparam PCORE_VERSION = 32'h00010761; // 1.07.a localparam PCORE_MAGIC = 32'h32303452; // 204R - + + localparam DATA_PATH_WIDTH_LOG2 = (DATA_PATH_WIDTH == 8) ? 3 : 2; + /* Register interface signals */ reg [31:0] up_rdata = 'h0; reg up_wack = 1'b0; @@ -277,9 +279,11 @@ module axi_jesd204_rx #( .status_synth_params1(status_synth_params1), .status_synth_params2(status_synth_params2)); - jesd204_up_sysref i_up_sysref ( - .up_clk(s_axi_aclk), - .up_reset(up_reset), + jesd204_up_sysref #( + .DATA_PATH_WIDTH_LOG2(DATA_PATH_WIDTH_LOG2) + ) i_up_sysref ( + .up_clk(s_axi_aclk), + .up_reset(up_reset), .core_clk(core_clk), .device_clk(device_clk), @@ -300,7 +304,8 @@ module axi_jesd204_rx #( jesd204_up_rx #( .NUM_LANES(NUM_LANES), - .DATA_PATH_WIDTH(DATA_PATH_WIDTH) + .DATA_PATH_WIDTH(DATA_PATH_WIDTH), + .DATA_PATH_WIDTH_LOG2(DATA_PATH_WIDTH_LOG2) ) i_up_rx ( .up_clk(s_axi_aclk), .up_reset(up_reset), diff --git a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx_constr.xdc b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx_constr.xdc index 64016d7728..45d773d472 100755 --- a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx_constr.xdc +++ b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx_constr.xdc @@ -57,6 +57,11 @@ set_property ASYNC_REG TRUE \ [get_cells -hier {up_reset_synchronizer_vector_reg*}] \ [get_cells -hier {up_core_reset_ext_synchronizer_vector_reg*}] +set_false_path \ + -to [get_cells i_up_rx/gen_lane[*].i_up_rx_lane/up_status_latency_reg[*]] + # -to [get_cells -hierarchical * -filter {NAME=~datapath/datapath_rx/jesd204_rx_link_layer/link_gen[*].jesd204c_rx/axi_jesd204_rx/i_up_rx/gen_lane[*].i_up_rx_lane/up_status_latency_reg[*] && IS_SEQUENTIAL}] + + set_false_path \ -from [get_pins {i_up_rx/i_cdc_status/in_toggle_d1_reg/C}] \ -to [get_pins {i_up_rx/i_cdc_status/i_sync_out/cdc_sync_stage1_reg[0]/D}] @@ -98,19 +103,27 @@ set_false_path \ -to [get_pins {i_sync_frame_align_err/out_event_reg*/D}] # Don't place them too far appart -set_max_delay -datapath_only \ +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_rx/i_cdc_status/cdc_hold_reg[*]/C}] \ +# -to [get_pins {i_up_rx/i_cdc_status/out_data_reg[*]/D}] \ +# [get_property -min PERIOD $axi_clk] + +set_false_path \ -from [get_pins {i_up_rx/i_cdc_status/cdc_hold_reg[*]/C}] \ - -to [get_pins {i_up_rx/i_cdc_status/out_data_reg[*]/D}] \ - [get_property -min PERIOD $axi_clk] + -to [get_pins {i_up_rx/i_cdc_status/out_data_reg[*]/D}] set_false_path \ -from $core_clk \ -to [get_pins {i_up_rx/*i_up_rx_lane/i_cdc_status_ready/cdc_sync_stage1_reg*/D}] -set_max_delay -datapath_only \ +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_rx/i_cdc_cfg/cdc_hold_reg[*]/C}] \ +# -to [get_pins {i_up_rx/i_cdc_cfg/out_data_reg[*]/D}] \ +# [get_property -min PERIOD $core_clk] + +set_false_path \ -from [get_pins {i_up_rx/i_cdc_cfg/cdc_hold_reg[*]/C}] \ - -to [get_pins {i_up_rx/i_cdc_cfg/out_data_reg[*]/D}] \ - [get_property -min PERIOD $core_clk] + -to [get_pins {i_up_rx/i_cdc_cfg/out_data_reg[*]/D}] set_max_delay -datapath_only \ -from $core_clk \ @@ -142,27 +155,27 @@ set_false_path \ set_false_path \ -to [get_pins {i_up_common/up_core_reset_ext_synchronizer_vector_reg[*]/PRE}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/core_cfg_*_reg*/D}] \ - [get_property -min PERIOD $core_clk] + -to [get_pins {i_up_common/core_cfg_*_reg*/D}] + # [get_property -min PERIOD $core_clk] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_cfg_*_reg*/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_cfg_*_reg*/D}] + # [get_property -min PERIOD $device_clk] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_rx/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/core_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $core_clk] + -to [get_pins {i_up_common/core_extra_cfg_reg[*]/D}] + # [get_property -min PERIOD $core_clk] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_rx/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] + # [get_property -min PERIOD $device_clk] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_sysref/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] + # [get_property -min PERIOD $device_clk] diff --git a/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v b/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v index 499bfe91b3..75178ff3d3 100755 --- a/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v +++ b/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v @@ -46,7 +46,8 @@ module jesd204_up_rx #( parameter NUM_LANES = 1, - parameter DATA_PATH_WIDTH = 4 + parameter DATA_PATH_WIDTH = 4, + parameter DATA_PATH_WIDTH_LOG2 = 2 ) ( input up_clk, input up_reset, @@ -142,7 +143,7 @@ module jesd204_up_rx #( /* 17-31 */ 15'h00, /* Reserved for future additions */ /* 16 */ up_cfg_buffer_early_release, /* Release buffer as soon as all lanes are ready. */ /* 10-15 */ 6'b0000, /* Reserved for future extensions of buffer_delay */ - /* 02-09 */ up_cfg_buffer_delay, /* Buffer release delay */ + /* 02-09 */ up_cfg_buffer_delay << (DATA_PATH_WIDTH_LOG2-2), /* Buffer release delay */ /* 00-01 */ 2'b00 /* Data path width alignment */ }; 12'h91: up_rdata = { @@ -187,7 +188,7 @@ module jesd204_up_rx #( /* JESD RX configuraton */ 12'h090: begin up_cfg_buffer_early_release <= up_wdata[16]; - up_cfg_buffer_delay <= up_wdata[7:0]; + up_cfg_buffer_delay <= up_wdata[9:DATA_PATH_WIDTH_LOG2]; end endcase end else if (up_wreq == 1'b1) begin diff --git a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v index 7953c49544..6b7b9602a4 100755 --- a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v +++ b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v @@ -122,6 +122,8 @@ module axi_jesd204_tx #( localparam PCORE_VERSION = 32'h00010661; // 1.06.a localparam PCORE_MAGIC = 32'h32303454; // 204T + localparam DATA_PATH_WIDTH_LOG2 = (DATA_PATH_WIDTH == 8) ? 3 : 2; + wire up_reset; /* Register interface signals */ @@ -257,7 +259,9 @@ module axi_jesd204_tx #( .status_synth_params1(status_synth_params1), .status_synth_params2(status_synth_params2)); - jesd204_up_sysref i_up_sysref ( + jesd204_up_sysref #( + .DATA_PATH_WIDTH_LOG2 (DATA_PATH_WIDTH_LOG2) + ) i_up_sysref ( .up_clk(s_axi_aclk), .up_reset(up_reset), diff --git a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx_constr.xdc b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx_constr.xdc old mode 100644 new mode 100755 index 63fb3fe17a..4b51380ac8 --- a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx_constr.xdc +++ b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx_constr.xdc @@ -102,35 +102,64 @@ set_false_path \ set_false_path \ -to [get_pins {i_up_common/up_core_reset_ext_synchronizer_vector_reg[*]/PRE}] -set_max_delay -datapath_only \ +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ +# -to [get_pins {i_up_common/core_cfg_*_reg*/D}] \ +# [get_property -min PERIOD $core_clk] + +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ +# -to [get_pins {i_up_common/device_cfg_*_reg*/D}] \ +# [get_property -min PERIOD $device_clk] + +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_tx/up_cfg_ilas_data_*_reg*/C}] \ +# -to [get_cells {i_up_tx/*core_ilas_config_data_reg*}] \ +# [get_property -min PERIOD $core_clk] + +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_tx/up_cfg_*_reg*/C}] \ +# -to [get_pins {i_up_common/core_extra_cfg_reg[*]/D}] \ +# [get_property -min PERIOD $core_clk] + +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_tx/up_cfg_*_reg*/C}] \ +# -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ +# [get_property -min PERIOD $device_clk] + +# set_max_delay -datapath_only \ +# -from [get_pins {i_up_sysref/up_cfg_*_reg*/C}] \ +# -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ +# [get_property -min PERIOD $device_clk] + + + + +set_false_path \ -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/core_cfg_*_reg*/D}] \ - [get_property -min PERIOD $core_clk] + -to [get_pins {i_up_common/core_cfg_*_reg*/D}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_common/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_cfg_*_reg*/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_cfg_*_reg*/D}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_tx/up_cfg_ilas_data_*_reg*/C}] \ - -to [get_cells {i_up_tx/*core_ilas_config_data_reg*}] \ - [get_property -min PERIOD $core_clk] + -to [get_cells {i_up_tx/*core_ilas_config_data_reg*}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_tx/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/core_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $core_clk] + -to [get_pins {i_up_common/core_extra_cfg_reg[*]/D}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_tx/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] -set_max_delay -datapath_only \ +set_false_path \ -from [get_pins {i_up_sysref/up_cfg_*_reg*/C}] \ - -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] \ - [get_property -min PERIOD $device_clk] + -to [get_pins {i_up_common/device_extra_cfg_reg[*]/D}] + + set_false_path \ -from [get_pins {i_up_tx/i_cdc_manual_sync_request/out_toggle_d1_reg/C}] \ diff --git a/library/jesd204/jesd204_common/up_axi.v b/library/jesd204/jesd204_common/up_axi.v new file mode 100644 index 0000000000..40acb17bd4 --- /dev/null +++ b/library/jesd204/jesd204_common/up_axi.v @@ -0,0 +1,239 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. +// +// In this HDL repository, there are many different and unique modules, consisting +// of various HDL (Verilog or VHDL) components. The individual modules are +// developed independently, and may be accompanied by separate and unique license +// terms. +// +// The user should read each of these license terms, and understand the +// freedoms and responsibilities that he or she has by using this source/core. +// +// This core 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. +// +// Redistribution and use of source or resulting binaries, with or without modification +// of this file, are permitted under one of the following two license terms: +// +// 1. The GNU General Public License version 2 as published by the +// Free Software Foundation, which can be found in the top level directory +// of this repository (LICENSE_GPL2), and also online at: +// +// +// OR +// +// 2. An ADI specific BSD license, which can be found in the top level directory +// of this repository (LICENSE_ADIBSD), and also on-line at: +// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD +// This will allow to generate bit files and not release the source code, +// as long as it attaches to an ADI device. +// +// *************************************************************************** +// *************************************************************************** + +`timescale 1ns/100ps + +module up_axi #( + + parameter AXI_ADDRESS_WIDTH = 16) ( + + // reset and clocks + + input up_rstn, + input up_clk, + + // axi4 interface + + input up_axi_awvalid, + input [(AXI_ADDRESS_WIDTH-1):0] up_axi_awaddr, + output up_axi_awready, + input up_axi_wvalid, + input [31:0] up_axi_wdata, + input [ 3:0] up_axi_wstrb, + output up_axi_wready, + output up_axi_bvalid, + output [ 1:0] up_axi_bresp, + input up_axi_bready, + input up_axi_arvalid, + input [(AXI_ADDRESS_WIDTH-1):0] up_axi_araddr, + output up_axi_arready, + output up_axi_rvalid, + output [ 1:0] up_axi_rresp, + output [31:0] up_axi_rdata, + input up_axi_rready, + + // pcore interface + + output up_wreq, + output [(AXI_ADDRESS_WIDTH-3):0] up_waddr, + output [31:0] up_wdata, + input up_wack, + output up_rreq, + output [(AXI_ADDRESS_WIDTH-3):0] up_raddr, + input [31:0] up_rdata, + input up_rack); + + // internal registers + + reg up_axi_awready_int = 'd0; + reg up_axi_wready_int = 'd0; + reg up_axi_bvalid_int = 'd0; + reg up_wack_d = 'd0; + reg up_wsel = 'd0; + reg up_wreq_int = 'd0; + reg [(AXI_ADDRESS_WIDTH-3):0] up_waddr_int = 'd0; + reg [31:0] up_wdata_int = 'd0; + reg [ 4:0] up_wcount = 'd0; + reg up_axi_arready_int = 'd0; + reg up_axi_rvalid_int = 'd0; + reg [31:0] up_axi_rdata_int = 'd0; + reg up_rack_d = 'd0; + reg [31:0] up_rdata_d = 'd0; + reg up_rsel = 'd0; + reg up_rreq_int = 'd0; + reg [(AXI_ADDRESS_WIDTH-3):0] up_raddr_int = 'd0; + reg [ 4:0] up_rcount = 'd0; + + // internal signals + + wire up_wack_s; + wire up_rack_s; + wire [31:0] up_rdata_s; + + // write channel interface + + assign up_axi_awready = up_axi_awready_int; + assign up_axi_wready = up_axi_wready_int; + assign up_axi_bvalid = up_axi_bvalid_int; + assign up_axi_bresp = 2'd0; + + always @(posedge up_clk) begin + if (up_rstn == 1'b0) begin + up_axi_awready_int <= 'd0; + up_axi_wready_int <= 'd0; + up_axi_bvalid_int <= 'd0; + end else begin + if (up_axi_awready_int == 1'b1) begin + up_axi_awready_int <= 1'b0; + end else if (up_wack_s == 1'b1) begin + up_axi_awready_int <= 1'b1; + end + if (up_axi_wready_int == 1'b1) begin + up_axi_wready_int <= 1'b0; + end else if (up_wack_s == 1'b1) begin + up_axi_wready_int <= 1'b1; + end + if ((up_axi_bready == 1'b1) && (up_axi_bvalid_int == 1'b1)) begin + up_axi_bvalid_int <= 1'b0; + end else if (up_wack_d == 1'b1) begin + up_axi_bvalid_int <= 1'b1; + end + end + end + + assign up_wreq = up_wreq_int; + assign up_waddr = up_waddr_int; + assign up_wdata = up_wdata_int; + assign up_wack_s = (up_wcount == 5'h1f) ? 1'b1 : (up_wcount[4] & up_wack); + + always @(posedge up_clk) begin + if (up_rstn == 1'b0) begin + up_wack_d <= 'd0; + up_wsel <= 'd0; + up_wreq_int <= 'd0; + up_waddr_int <= 'd0; + up_wdata_int <= 'd0; + up_wcount <= 'd0; + end else begin + up_wack_d <= up_wack_s; + if (up_wsel == 1'b1) begin + if ((up_axi_bready == 1'b1) && (up_axi_bvalid_int == 1'b1)) begin + up_wsel <= 1'b0; + end + up_wreq_int <= 1'b0; + end else begin + up_wsel <= up_axi_awvalid & up_axi_wvalid; + up_wreq_int <= up_axi_awvalid & up_axi_wvalid; + up_waddr_int <= up_axi_awaddr[(AXI_ADDRESS_WIDTH-1):2]; + up_wdata_int <= up_axi_wdata; + end + if (up_wack_s == 1'b1) begin + up_wcount <= 5'h00; + end else if (up_wcount[4] == 1'b1) begin + up_wcount <= up_wcount + 1'b1; + end else if (up_wreq_int == 1'b1) begin + up_wcount <= 5'h10; + end + end + end + + // read channel interface + + assign up_axi_arready = up_axi_arready_int; + assign up_axi_rvalid = up_axi_rvalid_int; + assign up_axi_rdata = up_axi_rdata_int; + assign up_axi_rresp = 2'd0; + + always @(posedge up_clk) begin + if (up_rstn == 1'b0) begin + up_axi_arready_int <= 'd0; + up_axi_rvalid_int <= 'd0; + up_axi_rdata_int <= 'd0; + end else begin + if (up_axi_arready_int == 1'b1) begin + up_axi_arready_int <= 1'b0; + end else if (up_rack_s == 1'b1) begin + up_axi_arready_int <= 1'b1; + end + if ((up_axi_rready == 1'b1) && (up_axi_rvalid_int == 1'b1)) begin + up_axi_rvalid_int <= 1'b0; + up_axi_rdata_int <= 32'd0; + end else if (up_rack_d == 1'b1) begin + up_axi_rvalid_int <= 1'b1; + up_axi_rdata_int <= up_rdata_d; + end + end + end + + assign up_rreq = up_rreq_int; + assign up_raddr = up_raddr_int; + assign up_rack_s = (up_rcount == 5'h1f) ? 1'b1 : (up_rcount[4] & up_rack); + assign up_rdata_s = (up_rcount == 5'h1f) ? {2{16'hdead}} : up_rdata; + + always @(posedge up_clk) begin + if (up_rstn == 1'b0) begin + up_rack_d <= 'd0; + up_rdata_d <= 'd0; + up_rsel <= 'd0; + up_rreq_int <= 'd0; + up_raddr_int <= 'd0; + up_rcount <= 'd0; + end else begin + up_rack_d <= up_rack_s; + up_rdata_d <= up_rdata_s; + if (up_rsel == 1'b1) begin + if ((up_axi_rready == 1'b1) && (up_axi_rvalid_int == 1'b1)) begin + up_rsel <= 1'b0; + end + up_rreq_int <= 1'b0; + end else begin + up_rsel <= up_axi_arvalid; + up_rreq_int <= up_axi_arvalid; + up_raddr_int <= up_axi_araddr[(AXI_ADDRESS_WIDTH-1):2]; + end + if (up_rack_s == 1'b1) begin + up_rcount <= 5'h00; + end else if (up_rcount[4] == 1'b1) begin + up_rcount <= up_rcount + 1'b1; + end else if (up_rreq_int == 1'b1) begin + up_rcount <= 5'h10; + end + end + end + +endmodule + +// *************************************************************************** +// *************************************************************************** diff --git a/library/jesd204/jesd204_rx/jesd204_lane_latency_monitor.v b/library/jesd204/jesd204_rx/jesd204_lane_latency_monitor.v index 93db35b762..5efb9612ce 100755 --- a/library/jesd204/jesd204_rx/jesd204_lane_latency_monitor.v +++ b/library/jesd204/jesd204_rx/jesd204_lane_latency_monitor.v @@ -88,7 +88,7 @@ module jesd204_lane_latency_monitor #( end end - assign lane_latency[i*14+13:i*14] = {lane_latency_mem[i],lane_frame_align[(i*3)+DPW_LOG2-1:i*3]}; + assign lane_latency[i*14+13:i*14] = {lane_latency_mem[i],lane_frame_align[(i*DPW_LOG2)+DPW_LOG2-1:i*DPW_LOG2]}; assign lane_latency_ready[i] = lane_captured[i]; end endgenerate diff --git a/library/jesd204/jesd204_rx/jesd204_rx.xdc b/library/jesd204/jesd204_rx/jesd204_rx.xdc new file mode 100755 index 0000000000..eacdf94b8b --- /dev/null +++ b/library/jesd204/jesd204_rx/jesd204_rx.xdc @@ -0,0 +1,2 @@ +set_false_path -through [get_ports {cfg_*}] +set_false_path -through [get_ports {core_cfg_*}] \ No newline at end of file diff --git a/library/jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v b/library/jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v old mode 100644 new mode 100755 index 0e5f89738b..7f765286a2 --- a/library/jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_ctrl_64b.v @@ -56,7 +56,7 @@ module jesd204_rx_ctrl_64b #( input [NUM_LANES-1:0] emb_lock, - output all_emb_lock, + output reg all_emb_lock, input buffer_release_n, output [1:0] status_state, @@ -74,24 +74,24 @@ module jesd204_rx_ctrl_64b #( reg rst_good_cnt; reg event_unexpected_lane_state_error_nx; - wire [NUM_LANES-1:0] phy_block_sync_masked; - wire [NUM_LANES-1:0] emb_lock_masked; - wire all_block_sync; - - reg [NUM_LANES-1:0] emb_lock_d = {NUM_LANES{1'b0}}; - reg buffer_release_d_n = 1'b1; + reg [NUM_LANES-1:0] phy_block_sync_masked; + reg [NUM_LANES-1:0] emb_lock_masked; + reg all_block_sync; always @(posedge clk) begin - emb_lock_d <= emb_lock; - buffer_release_d_n <= buffer_release_n; + if (reset == 1'b1) begin + phy_block_sync_masked <= {NUM_LANES{1'b0}}; + emb_lock_masked <= {NUM_LANES{1'b0}}; + all_block_sync <= 1'b0; + all_emb_lock <= 1'b0; + end else begin + phy_block_sync_masked <= phy_block_sync | cfg_lanes_disable; + emb_lock_masked <= emb_lock | cfg_lanes_disable; + all_block_sync <= &phy_block_sync_masked; + all_emb_lock <= &emb_lock_masked; + end end - assign phy_block_sync_masked = phy_block_sync | cfg_lanes_disable; - assign emb_lock_masked = emb_lock_d | cfg_lanes_disable; - - assign all_block_sync = &phy_block_sync_masked; - assign all_emb_lock = &emb_lock_masked; - always @(*) begin next_state = state; rst_good_cnt = 1'b1; @@ -109,7 +109,7 @@ module jesd204_rx_ctrl_64b #( STATE_BLOCK_SYNC: if (~all_block_sync) begin next_state = STATE_WAIT_BS; - end else if (all_emb_lock & ~buffer_release_d_n) begin + end else if (all_emb_lock & ~buffer_release_n) begin rst_good_cnt = 1'b0; if (&good_cnt) begin next_state = STATE_DATA; @@ -119,7 +119,7 @@ module jesd204_rx_ctrl_64b #( if (~all_block_sync) begin next_state = STATE_WAIT_BS; event_unexpected_lane_state_error_nx = 1'b1; - end else if (~all_emb_lock | buffer_release_d_n) begin + end else if (~all_emb_lock | buffer_release_n) begin next_state = STATE_BLOCK_SYNC; event_unexpected_lane_state_error_nx = 1'b1; end diff --git a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v old mode 100644 new mode 100755 index 17736d940a..4d893eced2 --- a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v @@ -83,6 +83,8 @@ module jesd204_rx_lane_64b #( reg [11:0] crc12_calculated_prev; + wire [63:0] eomb_r; + wire [63:0] phy_data_r; wire [63:0] data_descrambled_s; wire [63:0] data_descrambled; wire [63:0] data_descrambled_reordered; @@ -114,7 +116,7 @@ module jesd204_rx_lane_64b #( .cfg_beats_per_multiframe(cfg_beats_per_multiframe), .emb_lock(emb_lock), - + .valid_eomb(eomb), .valid_eoemb(eoemb), .crc12(crc12_received), @@ -128,18 +130,34 @@ module jesd204_rx_lane_64b #( .event_unexpected_eomb(event_unexpected_eomb), .event_unexpected_eoemb(event_unexpected_eoemb)); + pipeline_stage #( + .WIDTH(65), + .REGISTERED(1) + ) i_pipeline_crc12 ( + .clk(clk), + .in({ + eomb, + phy_data + }), + .out({ + eomb_r, + phy_data_r + }) + ); + + jesd204_crc12 i_crc12 ( .clk(clk), - .reset(1'b0), - .init(eomb), - .data_in(phy_data), + .reset(reset), + .init(eomb_r), + .data_in(phy_data_r), .crc12(crc12_calculated)); reg crc12_on = 'b0; always @(posedge clk) begin if (reset == 1'b1) begin crc12_on <= 1'b0; - end else if (eomb) begin + end else if (eomb_r) begin crc12_on <= 1'b1; end end @@ -148,18 +166,18 @@ module jesd204_rx_lane_64b #( always @(posedge clk) begin if (reset == 1'b1) begin crc12_rdy <= 1'b0; - end else if (crc12_on && eomb) begin + end else if (crc12_on && eomb_r) begin crc12_rdy <= 1'b1; end end always @(posedge clk) begin - if (eomb) begin + if (eomb_r) begin crc12_calculated_prev <= crc12_calculated; end end - assign event_crc12_mismatch = crc12_rdy && eomb && (crc12_calculated_prev != crc12_received); + assign event_crc12_mismatch = crc12_rdy && eomb_r && (crc12_calculated_prev != crc12_received); assign err_cnt_rst = reset || ctrl_err_statistics_reset; diff --git a/library/jesd204/jesd204_tx/jesd204_tx.v b/library/jesd204/jesd204_tx/jesd204_tx.v index 73d323bcbf..23cc9ca077 100755 --- a/library/jesd204/jesd204_tx/jesd204_tx.v +++ b/library/jesd204/jesd204_tx/jesd204_tx.v @@ -47,6 +47,7 @@ module jesd204_tx #( parameter NUM_LANES = 1, parameter NUM_LINKS = 1, + parameter NUM_INPUT_PIPELINE = 0, parameter NUM_OUTPUT_PIPELINE = 0, parameter LINK_MODE = 1, // 2 - 64B/66B; 1 - 8B/10B /* Only 4 is supported at the moment for 8b/10b and 8 for 64b */ @@ -133,11 +134,17 @@ module jesd204_tx #( localparam DW = DATA_PATH_WIDTH * 8 * NUM_LANES; localparam CW = DATA_PATH_WIDTH * NUM_LANES; localparam HW = 2 * NUM_LANES; + localparam INPUT_PIPELINE_WIDTH = (LINK_MODE[0] == 1) ? (1+(NUM_LANES*(1+(DATA_PATH_WIDTH*19)))) : (4+(64*NUM_LANES)); + +wire [DW-1:0] tx_data_r; +wire tx_ready_r; wire [DW-1:0] phy_data_r; wire [CW-1:0] phy_charisk_r; wire [HW-1:0] phy_header_r; + wire [INPUT_PIPELINE_WIDTH-1:0] input_pipeline_in; + wire [INPUT_PIPELINE_WIDTH-1:0] input_pipeline_out; wire eof_gen_reset; wire tx_ready_64b_next; reg tx_ready_64b = 1'b0; @@ -353,6 +360,15 @@ module jesd204_tx #( tx_eomf_fm_d2 <= tx_eomf_fm_d1; end +pipeline_stage #( + .WIDTH(INPUT_PIPELINE_WIDTH), + .REGISTERED(NUM_INPUT_PIPELINE) +) i_input_pipeline_stage ( + .clk(clk), + .in(input_pipeline_in), + .out(input_pipeline_out) +); + generate genvar i; @@ -364,8 +380,17 @@ module jesd204_tx #( wire [DW-1:0] ilas_data; wire [DATA_PATH_WIDTH*NUM_LANES-1:0] ilas_charisk; + wire [DATA_PATH_WIDTH-1:0] tx_eof_fm_d3_r; + wire [DATA_PATH_WIDTH-1:0] tx_eomf_fm_d3_r; + wire [NUM_LANES-1:0] lane_cgs_enable_r; + wire [DW-1:0] ilas_data_r; + wire [DATA_PATH_WIDTH*NUM_LANES-1:0] ilas_charisk_r; + wire cfg_generate_eomf = 1'b1; + assign input_pipeline_in = {tx_ready, gearbox_data, ilas_charisk, ilas_data, lane_cgs_enable, tx_eomf_fm_d3, tx_eof_fm_d3}; + assign {tx_ready_r, tx_data_r, ilas_charisk_r, ilas_data_r, lane_cgs_enable_r, tx_eomf_fm_d3_r, tx_eof_fm_d3_r} = input_pipeline_out; + always @(posedge clk) begin tx_eof_fm_d3 <= tx_eof_fm_d2; tx_eomf_fm_d3 <= tx_eomf_fm_d2; @@ -424,16 +449,16 @@ module jesd204_tx #( ) i_lane ( .clk(clk), - .eof(tx_eof_fm_d3), - .eomf(tx_eomf_fm_d3), + .eof(tx_eof_fm_d3_r), + .eomf(tx_eomf_fm_d3_r), - .cgs_enable(lane_cgs_enable[i]), + .cgs_enable(lane_cgs_enable_r[i]), - .ilas_data(ilas_data[D_STOP:D_START]), - .ilas_charisk(ilas_charisk[C_STOP:C_START]), + .ilas_data(ilas_data_r[D_STOP:D_START]), + .ilas_charisk(ilas_charisk_r[C_STOP:C_START]), - .tx_data(gearbox_data[D_STOP:D_START]), - .tx_ready(link_tx_ready), + .tx_data(tx_data_r[D_STOP:D_START]), + .tx_ready(tx_ready_r), .phy_data(phy_data_r[D_STOP:D_START]), .phy_charisk(phy_charisk_r[C_STOP:C_START]), @@ -448,6 +473,13 @@ module jesd204_tx #( end if (LINK_MODE[1] == 1) begin : mode_64b66b + wire lmc_edge_r; + wire lmc_quarter_edge_r; + wire eoemb_r; + wire tx_ready_64b_r; + + assign input_pipeline_in = {eoemb, lmc_quarter_edge, lmc_edge, tx_ready_64b, gearbox_data}; + assign {eoemb_r, lmc_quarter_edge_r, lmc_edge_r, tx_ready_64b_r, tx_data_r} = input_pipeline_out; for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane localparam D_START = i * DATA_PATH_WIDTH*8; @@ -458,15 +490,15 @@ module jesd204_tx #( .clk(clk), .reset(reset), - .tx_data(gearbox_data[D_STOP:D_START]), - .tx_ready(tx_ready_64b), + .tx_data(tx_data_r[D_STOP:D_START]), + .tx_ready(tx_ready_64b_r), .phy_data(phy_data_r[D_STOP:D_START]), .phy_header(phy_header_r[H_STOP:H_START]), - .lmc_edge(lmc_edge), - .lmc_quarter_edge(lmc_quarter_edge), - .eoemb(eoemb), + .lmc_edge(lmc_edge_r), + .lmc_quarter_edge(lmc_quarter_edge_r), + .eoemb(eoemb_r), .cfg_disable_scrambler(cfg_disable_scrambler), .cfg_header_mode(2'b0), diff --git a/library/jesd204/jesd204_tx/jesd204_tx.xdc b/library/jesd204/jesd204_tx/jesd204_tx.xdc new file mode 100755 index 0000000000..eacdf94b8b --- /dev/null +++ b/library/jesd204/jesd204_tx/jesd204_tx.xdc @@ -0,0 +1,2 @@ +set_false_path -through [get_ports {cfg_*}] +set_false_path -through [get_ports {core_cfg_*}] \ No newline at end of file diff --git a/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v b/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v old mode 100644 new mode 100755 index 289d8c1137..1422c05b35 --- a/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v +++ b/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v @@ -88,7 +88,7 @@ module jesd204_tx_lane_64b ( .DESCRAMBLE(0) ) i_scrambler ( .clk(clk), - .reset(1'b0), + .reset(reset), .enable(~cfg_disable_scrambler), .data_in(tx_data_msb_s), .data_out(scrambled_data_r)); From ec0b477e3c8abae56c3a73f0961c59621d1202c8 Mon Sep 17 00:00:00 2001 From: "Matthew.Blanton" Date: Mon, 12 Feb 2024 12:41:07 -0500 Subject: [PATCH 2/2] Added support for JESD204C FEC meta mode for RX and TX. --- library/common/ad_mem_dist.v | 41 +- .../axi_jesd204_common/jesd204_up_common.v | 8 +- .../jesd204/axi_jesd204_rx/axi_jesd204_rx.v | 4 +- .../jesd204/axi_jesd204_rx/jesd204_up_rx.v | 14 +- .../jesd204/axi_jesd204_tx/axi_jesd204_tx.v | 2 + library/jesd204/jesd204_common/lfsr_input.sv | 129 ++++++ .../jesd204/jesd204_rx/jesd204_fec_decode.sv | 347 +++++++++++++++ library/jesd204/jesd204_rx/jesd204_rx.v | 9 +- .../jesd204/jesd204_rx/jesd204_rx_fec_lfsr.sv | 145 ++++++ .../jesd204/jesd204_rx/jesd204_rx_header.v | 16 +- .../jesd204/jesd204_rx/jesd204_rx_lane_64b.v | 87 +++- .../jesd204_rx_static_config.v | 3 + .../jesd204/jesd204_tx/jesd204_fec_encode.sv | 95 ++++ library/jesd204/jesd204_tx/jesd204_tx.v | 8 +- .../jesd204/jesd204_tx/jesd204_tx_lane_64b.v | 44 +- .../jesd204_tx_static_config.v | 3 + library/jesd204/tb/sim_jesd204_fec.sh | 16 + library/jesd204/tb/sim_jesd204_fec_encode.sh | 12 + library/jesd204/tb/sim_lfsr_input.sh | 11 + library/jesd204/tb/sim_link_layer_fec.sh | 51 +++ library/jesd204/tb/tb_jesd204_fec.sv | 151 +++++++ library/jesd204/tb/tb_jesd204_fec_encode.v | 67 +++ library/jesd204/tb/tb_lfsr_input.sv | 95 ++++ library/jesd204/tb/tb_link_layer_fec.sv | 420 ++++++++++++++++++ 24 files changed, 1736 insertions(+), 42 deletions(-) create mode 100755 library/jesd204/jesd204_common/lfsr_input.sv create mode 100755 library/jesd204/jesd204_rx/jesd204_fec_decode.sv create mode 100755 library/jesd204/jesd204_rx/jesd204_rx_fec_lfsr.sv create mode 100755 library/jesd204/jesd204_tx/jesd204_fec_encode.sv create mode 100755 library/jesd204/tb/sim_jesd204_fec.sh create mode 100755 library/jesd204/tb/sim_jesd204_fec_encode.sh create mode 100755 library/jesd204/tb/sim_lfsr_input.sh create mode 100755 library/jesd204/tb/sim_link_layer_fec.sh create mode 100755 library/jesd204/tb/tb_jesd204_fec.sv create mode 100755 library/jesd204/tb/tb_jesd204_fec_encode.v create mode 100755 library/jesd204/tb/tb_lfsr_input.sv create mode 100755 library/jesd204/tb/tb_link_layer_fec.sv diff --git a/library/common/ad_mem_dist.v b/library/common/ad_mem_dist.v index 29d8ee7955..955decb8e6 100755 --- a/library/common/ad_mem_dist.v +++ b/library/common/ad_mem_dist.v @@ -1,13 +1,42 @@ -////////////////////////////////////////////////////////////////////////////////// -// Company: Analog Devices, Inc. -// Engineer: MBB -// Simple dual-port distributed RAM with non-registered output -////////////////////////////////////////////////////////////////////////////////// +// *************************************************************************** +// *************************************************************************** +// Copyright (C) 2014-2023 Analog Devices, Inc. All rights reserved. +// +// In this HDL repository, there are many different and unique modules, consisting +// of various HDL (Verilog or VHDL) components. The individual modules are +// developed independently, and may be accompanied by separate and unique license +// terms. +// +// The user should read each of these license terms, and understand the +// freedoms and responsibilities that he or she has by using this source/core. +// +// This core 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. +// +// Redistribution and use of source or resulting binaries, with or without modification +// of this file, are permitted under one of the following two license terms: +// +// 1. The GNU General Public License version 2 as published by the +// Free Software Foundation, which can be found in the top level directory +// of this repository (LICENSE_GPL2), and also online at: +// +// +// OR +// +// 2. An ADI specific BSD license, which can be found in the top level directory +// of this repository (LICENSE_ADIBSD), and also on-line at: +// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD +// This will allow to generate bit files and not release the source code, +// as long as it attaches to an ADI device. +// +// *************************************************************************** +// *************************************************************************** `timescale 1ps / 1ps `default_nettype none -module dual_port_dist_ram #( +module ad_mem_dist #( parameter RAM_WIDTH = 32, parameter RAM_ADDR_BITS = 4 )( diff --git a/library/jesd204/axi_jesd204_common/jesd204_up_common.v b/library/jesd204/axi_jesd204_common/jesd204_up_common.v index c0f6c58e8d..c67730bfc1 100755 --- a/library/jesd204/axi_jesd204_common/jesd204_up_common.v +++ b/library/jesd204/axi_jesd204_common/jesd204_up_common.v @@ -91,6 +91,7 @@ module jesd204_up_common #( output reg [7:0] core_cfg_octets_per_frame = 'h00, output reg core_cfg_disable_scrambler = 'h00, output reg core_cfg_disable_char_replacement = 'h00, + output reg [1:0] core_cfg_header_mode = 'h00, output reg [EXTRA_CFG_WIDTH-1:0] core_extra_cfg = 'h00, output reg [DEV_EXTRA_CFG_WIDTH-1:0] device_extra_cfg = 'h00, @@ -112,6 +113,7 @@ module jesd204_up_common #( reg [NUM_LANES-1:0] up_cfg_lanes_disable = {NUM_LANES{1'b0}}; reg [NUM_LINKS-1:0] up_cfg_links_disable = {NUM_LINKS{1'b0}}; reg up_cfg_disable_char_replacement = 1'b0; + reg [1:0] up_cfg_header_mode = 1'b0; reg up_cfg_disable_scrambler = 1'b0; /* Reset for the register map */ @@ -201,6 +203,7 @@ module jesd204_up_common #( core_cfg_links_disable <= up_cfg_links_disable; core_cfg_disable_scrambler <= up_cfg_disable_scrambler; core_cfg_disable_char_replacement <= up_cfg_disable_char_replacement; + core_cfg_header_mode <= up_cfg_header_mode; core_extra_cfg <= up_extra_cfg; end end @@ -328,7 +331,8 @@ module jesd204_up_common #( /* 00-09 */ up_cfg_octets_per_multiframe }; 12'h85: up_rdata = { - /* 02-31 */ 30'h00, /* Reserved for future additions */ + /* 04-31 */ 30'h00, /* Reserved for future additions */ + /* 03-02 */ up_cfg_header_mode, /* 0 - CRC12 ; 1 - CRC3; 2 - FEC; 3 - CMD */ /* 01 */ up_cfg_disable_char_replacement, /* Disable character replacement */ /* 00 */ up_cfg_disable_scrambler /* Disable scrambler */ }; @@ -372,6 +376,7 @@ module jesd204_up_common #( up_cfg_beats_per_multiframe <= 'h00; up_cfg_disable_char_replacement <= 1'b0; + up_cfg_header_mode <= 2'b0; up_cfg_disable_scrambler <= 1'b0; end else if (up_wreq == 1'b1) begin case (up_waddr) @@ -401,6 +406,7 @@ module jesd204_up_common #( {DATA_PATH_WIDTH_LOG2{1'b1}}}; end 12'h085: begin + up_cfg_header_mode <= up_wdata[3:2]; up_cfg_disable_char_replacement <= up_wdata[1]; up_cfg_disable_scrambler <= up_wdata[0]; end diff --git a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v index d5e87e4bb4..b7dd8328f5 100755 --- a/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v +++ b/library/jesd204/axi_jesd204_rx/axi_jesd204_rx.v @@ -90,6 +90,7 @@ module axi_jesd204_rx #( output [7:0] core_cfg_octets_per_frame, output core_cfg_disable_scrambler, output core_cfg_disable_char_replacement, + output [1:0] core_cfg_header_mode, output [7:0] core_cfg_frame_align_err_threshold, output [9:0] device_cfg_octets_per_multiframe, @@ -110,7 +111,7 @@ module axi_jesd204_rx #( input core_event_frame_alignment_error, input core_event_unexpected_lane_state_error, - output [6:0] core_ctrl_err_statistics_mask, + output [8:0] core_ctrl_err_statistics_mask, output core_ctrl_err_statistics_reset, input [32*NUM_LANES-1:0] core_status_err_statistics_cnt, @@ -248,6 +249,7 @@ module axi_jesd204_rx #( .core_cfg_links_disable(core_cfg_links_disable), .core_cfg_disable_scrambler(core_cfg_disable_scrambler), .core_cfg_disable_char_replacement(core_cfg_disable_char_replacement), + .core_cfg_header_mode(core_cfg_header_mode), .up_extra_cfg({ /* 00-07 */ up_cfg_frame_align_err_threshold diff --git a/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v b/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v index 75178ff3d3..8287312951 100755 --- a/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v +++ b/library/jesd204/axi_jesd204_rx/jesd204_up_rx.v @@ -75,7 +75,7 @@ module jesd204_up_rx #( input [8*NUM_LANES-1:0] core_status_lane_frame_align_err_cnt, input [32*NUM_LANES-1:0] core_status_err_statistics_cnt, - output [6:0] core_ctrl_err_statistics_mask, + output [8:0] core_ctrl_err_statistics_mask, output core_ctrl_err_statistics_reset, input up_cfg_is_writeable, @@ -95,7 +95,7 @@ module jesd204_up_rx #( wire [32*NUM_LANES-1:0] up_status_err_statistics_cnt; reg up_ctrl_err_statistics_reset = 0; - reg [6:0] up_ctrl_err_statistics_mask = 7'h0; + reg [8:0] up_ctrl_err_statistics_mask = 7'h0; sync_data #( .NUM_OF_BITS(2+NUM_LANES*(3+2+32+8)) @@ -118,7 +118,7 @@ module jesd204_up_rx #( })); sync_data #( - .NUM_OF_BITS(8) + .NUM_OF_BITS(10) ) i_cdc_cfg ( .in_clk(up_clk), .in_data({ @@ -146,9 +146,9 @@ module jesd204_up_rx #( /* 02-09 */ up_cfg_buffer_delay << (DATA_PATH_WIDTH_LOG2-2), /* Buffer release delay */ /* 00-01 */ 2'b00 /* Data path width alignment */ }; - 12'h91: up_rdata = { - /* 15-31 */ 17'h00, /* Reserved for future additions */ - /* 08-14 */ up_ctrl_err_statistics_mask, + 12'h91: up_rdata <= { + /* 17-31 */ 15'h00, /* Reserved for future additions */ + /* 08-16 */ up_ctrl_err_statistics_mask, /* 01-07 */ 7'h0, /* 00 */ up_ctrl_err_statistics_reset }; @@ -194,7 +194,7 @@ module jesd204_up_rx #( end else if (up_wreq == 1'b1) begin case (up_waddr) 12'h91: begin - up_ctrl_err_statistics_mask <= up_wdata[14:8]; + up_ctrl_err_statistics_mask <= up_wdata[16:8]; up_ctrl_err_statistics_reset <= up_wdata[0]; end 12'h92: begin diff --git a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v index 6b7b9602a4..fd629bca88 100755 --- a/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v +++ b/library/jesd204/axi_jesd204_tx/axi_jesd204_tx.v @@ -93,6 +93,7 @@ module axi_jesd204_tx #( output core_cfg_skip_ilas, output [7:0] core_cfg_mframes_per_ilas, output core_cfg_disable_char_replacement, + output [1:0] core_cfg_header_mode, output core_cfg_disable_scrambler, output [9:0] device_cfg_octets_per_multiframe, @@ -226,6 +227,7 @@ module axi_jesd204_tx #( .core_cfg_links_disable(core_cfg_links_disable), .core_cfg_disable_scrambler(core_cfg_disable_scrambler), .core_cfg_disable_char_replacement(core_cfg_disable_char_replacement), + .core_cfg_header_mode(core_cfg_header_mode), .up_extra_cfg({ /* 10 */ up_cfg_continuous_cgs, diff --git a/library/jesd204/jesd204_common/lfsr_input.sv b/library/jesd204/jesd204_common/lfsr_input.sv new file mode 100755 index 0000000000..da13af0e2a --- /dev/null +++ b/library/jesd204/jesd204_common/lfsr_input.sv @@ -0,0 +1,129 @@ +// +// The ADI JESD204 Core is released under the following license, which is +// different than all other HDL cores in this repository. +// +// Please read this, and understand the freedoms and responsibilities you have +// by using this source code/core. +// +// The JESD204 HDL, is copyright © 2016-2017 Analog Devices Inc. +// +// This core is free software, you can use run, copy, study, change, ask +// questions about and improve this core. Distribution of source, or resulting +// binaries (including those inside an FPGA or ASIC) require you to release the +// source of the entire project (excluding the system libraries provide by the +// tools/compiler/FPGA vendor). These are the terms of the GNU General Public +// License version 2 as published by the Free Software Foundation. +// +// This core 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 version 2 +// along with this source code, and binary. If not, see +// . +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + + +`timescale 1ns / 100ps +`default_nettype none + +// LFSR with input +module lfsr_input #( + parameter LFSR_WIDTH = 32, + parameter [LFSR_WIDTH:1] RESET_VAL = {LFSR_WIDTH{1'b0}}, + // LFSR_POLYNOMIAL[0] must be 1 and is omitted + parameter [LFSR_WIDTH:1] LFSR_POLYNOMIAL = {LFSR_WIDTH{1'b0}}, + parameter MAX_SHIFT_CNT = 64 +)( + // One cycle after shift_en = 1, + // data_out[shift_cnt:0] contains the next shift_cnt + 1 output bits + // data_out[MAX_SHIFT_CNT-1:shift_cnt+1] is undefined + output logic [MAX_SHIFT_CNT-1:0] data_out, + // Value of the shift register updated one cycle after shift_en is asserted + output logic [LFSR_WIDTH:1] shift_reg, + // Value of the shift register if shift_en is asserted for each value of shift_cnt from 1 to MAX_SHIFT_CNT + output logic [LFSR_WIDTH:1] shift_reg_next[MAX_SHIFT_CNT-1:0], + input wire clk, + input wire rst, + input wire shift_reg_reset, + input wire shift_en, + // Number of bits to shift - 1 + input wire [$clog2(MAX_SHIFT_CNT)-1:0] shift_cnt, + input wire [MAX_SHIFT_CNT-1:0] data_in +); + + function automatic [LFSR_WIDTH:1] lfsr_galois_next(input [LFSR_WIDTH:1] cur, input next_data_in); + int ii; + reg next_msb; + next_msb = cur[1] ^ next_data_in; + lfsr_galois_next[LFSR_WIDTH] = next_msb; + for(ii = LFSR_WIDTH-1; ii > 0; ii=ii-1) begin : shift_reg_gen + lfsr_galois_next[ii] = cur[ii+1] ^ (next_msb & LFSR_POLYNOMIAL[ii]); + end + endfunction + + wire [MAX_SHIFT_CNT-1:0] data_out_next; + reg [LFSR_WIDTH:1] shift_reg_in_start; + wire [LFSR_WIDTH:1] shift_reg_in_next[MAX_SHIFT_CNT-1:0]; + genvar jj; + + + + // Generate shift register values for each number of shifts + for(jj = 0; jj < MAX_SHIFT_CNT; jj = jj + 1) begin : shift_gen + // Shift register input is output of previous shift register value + if(jj == 0) begin : zero_gen + assign shift_reg_in_next[jj] = shift_reg_in_start; + end else begin : non_zero_gen + assign shift_reg_in_next[jj] = shift_reg_next[jj-1]; + end + + // Output bit is the LSb of the shift register + assign data_out_next[jj] = shift_reg_in_next[jj][1]; + + assign shift_reg_next[jj] = lfsr_galois_next(shift_reg_in_next[jj], data_in[jj]); + end + + always @(posedge clk) begin + if(shift_reg_reset || rst) begin + shift_reg_in_start <= RESET_VAL; + end else if(shift_en) begin + shift_reg_in_start <= shift_reg_next[shift_cnt]; + end + end + + always @(posedge clk) begin + if(rst) begin + shift_reg <= RESET_VAL; + end else begin + if(shift_en) begin + shift_reg <= shift_reg_next[shift_cnt]; + data_out <= data_out_next; + end else if(shift_reg_reset) begin + shift_reg <= RESET_VAL; + end + end + end + +endmodule + +`default_nettype wire diff --git a/library/jesd204/jesd204_rx/jesd204_fec_decode.sv b/library/jesd204/jesd204_rx/jesd204_fec_decode.sv new file mode 100755 index 0000000000..9e1c584184 --- /dev/null +++ b/library/jesd204/jesd204_rx/jesd204_fec_decode.sv @@ -0,0 +1,347 @@ +// +// The ADI JESD204 Core is released under the following license, which is +// different than all other HDL cores in this repository. +// +// Please read this, and understand the freedoms and responsibilities you have +// by using this source code/core. +// +// The JESD204 HDL, is copyright © 2016-2017 Analog Devices Inc. +// +// This core is free software, you can use run, copy, study, change, ask +// questions about and improve this core. Distribution of source, or resulting +// binaries (including those inside an FPGA or ASIC) require you to release the +// source of the entire project (excluding the system libraries provide by the +// tools/compiler/FPGA vendor). These are the terms of the GNU General Public +// License version 2 as published by the Free Software Foundation. +// +// This core 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 version 2 +// along with this source code, and binary. If not, see +// . +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + + +`timescale 1ns / 100ps + +// JESD204C FEC decoder +module jesd204_fec_decode #( + parameter DATA_WIDTH = 64 +)( + output logic [DATA_WIDTH-1:0] data_out, + output logic data_out_valid, + output logic trapped_error_flag, + output logic untrapped_error_flag, + input wire clk, + input wire rst, + input wire eomb, + input wire fec_in_valid, + input wire [25:0] fec_in, + input wire [DATA_WIDTH-1:0] data_in +); + + localparam DATA_WIDTH_WIDTH=$clog2(DATA_WIDTH); + localparam FEC_WIDTH = 26; + localparam FEC_WIDTH_WIDTH = $clog2(FEC_WIDTH); + localparam [FEC_WIDTH:1] RESET_VAL = {FEC_WIDTH{1'b0}}; + localparam BLOCK_LENGTH = 2048; + localparam MAX_BURST_LEN = 9; // Max correctable error burst length + localparam BUFFER_NUM_BLOCKS = 2; + localparam BLOCK_CYCLE_CNT = BLOCK_LENGTH/DATA_WIDTH; + localparam BUFFER_DEPTH = BLOCK_CYCLE_CNT*BUFFER_NUM_BLOCKS; + localparam BUFFER_ADDR_WIDTH = $clog2(BUFFER_DEPTH); + localparam NUM_BLOCKS_WIDTH = $clog2(BUFFER_NUM_BLOCKS); + localparam CYCLE_WIDTH = $clog2(BLOCK_CYCLE_CNT); + + logic [FEC_WIDTH-1:0] fec_in_reversed; + logic [FEC_WIDTH:1] data_in_syndrome; + logic [FEC_WIDTH:1] data_in_syndrome_saved; + logic [FEC_WIDTH:1] codeword_syndrome; + logic [FEC_WIDTH:1] error_syndrome_next[DATA_WIDTH-1:0]; + logic [FEC_WIDTH:1] error_syndrome_next_d[DATA_WIDTH-1:0]; + logic [DATA_WIDTH+MAX_BURST_LEN-1:0] error_syndrome_next_shifted[DATA_WIDTH-1:0]; + logic [DATA_WIDTH+MAX_BURST_LEN-1:0] error_bits; + logic [MAX_BURST_LEN-1:0] error_bits_prev; + logic [NUM_BLOCKS_WIDTH-1:0] buf_wr_block; + logic [NUM_BLOCKS_WIDTH-1:0] buf_rd_block; + logic [CYCLE_WIDTH-1:0] buf_wr_cycle; + logic [CYCLE_WIDTH-1:0] buf_rd_cycle; + logic buf_wr_en; + logic [BUFFER_ADDR_WIDTH-1:0] buf_wr_addr; + logic [BUFFER_ADDR_WIDTH-1:0] buf_rd_addr; + logic [DATA_WIDTH-1:0] buf_wr_data; + logic [DATA_WIDTH-1:0] buf_rd_data; + logic [DATA_WIDTH-1:0] buf_rd_data_d; + logic [3:1] eomb_d; + logic data_in_en; + logic fec_in_en; + logic data_out_en; + logic [2:1] data_out_en_d; + logic data_in_syndrome_avail; + logic [DATA_WIDTH-1:0] error_trapped; + logic [DATA_WIDTH-1:0] error; + logic any_error_trapped; + logic any_error; + logic trapped_error_sticky; + logic error_sticky; + logic trapped_error_sticky_comb; + logic error_sticky_comb; + int jj; + genvar ii; + + // Reverse order of FEC bits so that bit 25 is shifted in first + for(ii = 0; ii < 26; ii = ii + 1) begin : fec_reverse_gen + assign fec_in_reversed[ii] = fec_in[25-ii]; + end + + // Data input enabled after first EoMB + // FEC input enabled after next EoMB + // Data output enabled after next EoMB + always @(posedge clk) begin + if(rst) begin + data_in_en <= 1'b0; + fec_in_en <= 1'b0; + data_out_en <= 1'b0; + end else begin + if(eomb) begin + data_in_en <= 1'b1; + fec_in_en <= data_in_en; + data_out_en <= fec_in_en; + end + end + end + + // Data buffer + ad_mem_dist #( + .RAM_WIDTH (DATA_WIDTH), + .RAM_ADDR_BITS (BUFFER_ADDR_WIDTH) + ) data_buffer ( + .rd_data (buf_rd_data), + .clk (clk), + .wr_en (buf_wr_en), + .wr_addr (buf_wr_addr), + .wr_data (buf_wr_data), + .rd_addr (buf_rd_addr) + ); + + assign buf_wr_en = data_in_en; + assign buf_wr_data = data_in; + assign buf_wr_addr = {buf_wr_block, buf_wr_cycle}; + assign buf_rd_addr = {buf_rd_block, buf_rd_cycle}; + + // Keep track of read and write block counts and block cycle counts + // in case link goes down then up, causing partial blocks + always @(posedge clk) begin + if(rst) begin + buf_wr_block <= '0; + buf_wr_cycle <= '0; + end else begin + if(data_in_en) begin + if(eomb) begin + if(buf_wr_block == (BUFFER_NUM_BLOCKS-1)) begin + buf_wr_block <= '0; + end else begin + buf_wr_block <= buf_wr_block + 1'b1; + end + + buf_wr_cycle <= '0; + end else begin + buf_wr_cycle <= buf_wr_cycle + 1'b1; + end + end + end + end + + always @(posedge clk) begin + if(rst) begin + buf_rd_block <= '0; + buf_rd_cycle <= '0; + end else begin + if(data_out_en) begin + if(eomb) begin + if(buf_rd_block == (BUFFER_NUM_BLOCKS-1)) begin + buf_rd_block <= '0; + end else begin + buf_rd_block <= buf_rd_block + 1'b1; + end + + buf_rd_cycle <= '0; + end else begin + buf_rd_cycle <= buf_rd_cycle + 1'b1; + end + end + end + end + + // Input data syndrome computation + jesd204_rx_fec_lfsr #( + .MAX_SHIFT_CNT (DATA_WIDTH) + ) data_in_lfsr ( + .data_out (), + .shift_reg (data_in_syndrome), + .shift_reg_next (), + .clk (clk), + .rst (rst), + .load_en (eomb), + .load_data ('0), + .shift_en (data_in_en), + .shift_cnt (DATA_WIDTH_WIDTH'(DATA_WIDTH-1)), + .data_in (data_in) + ); + + // Save codeword_lfsr after the input data syndrome is computed + always @(posedge clk) begin + if(rst) begin + data_in_syndrome_avail <= 1'b0; + end else begin + data_in_syndrome_avail <= data_in_en && eomb_d[1]; + end + end + + always @(posedge clk) begin + if(eomb_d[1]) begin + data_in_syndrome_saved <= data_in_syndrome; + end + end + + // Codeword syndrome computation using received FEC + jesd204_rx_fec_lfsr #( + .MAX_SHIFT_CNT (FEC_WIDTH) + ) codeword_lfsr ( + .data_out (), + .shift_reg (codeword_syndrome), + .shift_reg_next (), + .clk (clk), + .rst (rst), + .load_en (data_in_syndrome_avail), + .load_data (data_in_syndrome_saved), + .shift_en (fec_in_valid), + .shift_cnt (FEC_WIDTH_WIDTH'(FEC_WIDTH-1)), + .data_in (fec_in_reversed) + ); + + // Error syndrome computation + jesd204_rx_fec_lfsr #( + .MAX_SHIFT_CNT (DATA_WIDTH) + ) error_lfsr ( + .data_out (), + .shift_reg (), + .shift_reg_next (error_syndrome_next), + .clk (clk), + .rst (rst), + .load_en (eomb), + .load_data (codeword_syndrome), + .shift_en (data_out_en), + .shift_cnt (DATA_WIDTH_WIDTH'(DATA_WIDTH-1)), + .data_in ({DATA_WIDTH{1'b0}}) + ); + + always_ff @(posedge clk) begin + error_syndrome_next_d <= error_syndrome_next; + buf_rd_data_d <= buf_rd_data; + end + + // Error is trapped if the MSb of the syndrome is 1 and bits 16:0 of the syndrome are 0 + // MSb (bit S25) of the syndrome is in the rightmost bit of error_syndrome_next_d[ii] + for(ii = 0; ii < DATA_WIDTH; ii = ii + 1) begin : error_trap_gen + assign error_trapped[ii] = error_syndrome_next_d[ii][1] && ~|(error_syndrome_next_d[ii][26:10]); + assign error[ii] = error_syndrome_next_d[ii][1]; + end + + always @(posedge clk) begin + any_error_trapped <= |error_trapped; + any_error <= |error; + end + + // Shift syndromes to align with data + for(ii = 0; ii < DATA_WIDTH; ii = ii + 1) begin : syndrome_shift_gen + assign error_syndrome_next_shifted[ii] = {error_syndrome_next_d[ii][MAX_BURST_LEN:1], {(ii+1){1'b0}}}; + end + + // Determine error bits by checking for trapped error + always @(*) begin + error_bits = '0; + for(jj = 0; jj < DATA_WIDTH; jj = jj + 1'b1) begin : correct_gen + if(error_trapped[jj]) begin + error_bits = error_bits ^ error_syndrome_next_shifted[jj]; + end + end + end + + // Save remaining error bits to use next cycle + always @(posedge clk) begin + if(eomb_d[1]) begin + error_bits_prev <= '0; + end else begin + error_bits_prev <= error_bits[DATA_WIDTH+:MAX_BURST_LEN]; + end + end + + // Correct data by XORing with FEC syndrome + // Output corrected data + always_ff @(posedge clk) begin + data_out <= buf_rd_data_d ^ error_bits[DATA_WIDTH-1:0] ^ error_bits_prev; + data_out_valid <= data_out_en_d[1]; + end + + // Flag trapped and untrapped errors, once per-block + assign trapped_error_sticky_comb = (eomb_d[3] ? 1'b0 : trapped_error_sticky) || any_error_trapped; + assign error_sticky_comb = (eomb_d[3] ? 1'b0 : error_sticky) || any_error; + + always @(posedge clk) begin + if(rst) begin + trapped_error_flag <= 1'b0; + untrapped_error_flag <= 1'b0; + trapped_error_sticky <= 1'b0; + error_sticky <= 1'b0; + end else begin + trapped_error_flag <= 1'b0; + untrapped_error_flag <= 1'b0; + + if(data_out_en_d[2]) begin + trapped_error_sticky <= trapped_error_sticky_comb; + error_sticky <= error_sticky_comb; + if(eomb_d[2]) begin + trapped_error_flag <= trapped_error_sticky_comb; + untrapped_error_flag <= !trapped_error_sticky_comb && error_sticky_comb; + end + end else begin + trapped_error_sticky <= 1'b0; + error_sticky <= 1'b0; + end + end + end + + // Delay registers + always @(posedge clk) begin + if(rst) begin + eomb_d <= 3'b0; + data_out_en_d <= 2'b0; + end else begin + eomb_d <= {eomb_d[2:1], eomb}; + data_out_en_d <= {data_out_en_d[1], data_out_en}; + end + end + +endmodule diff --git a/library/jesd204/jesd204_rx/jesd204_rx.v b/library/jesd204/jesd204_rx/jesd204_rx.v index 37990979ca..99ecd3573a 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx.v +++ b/library/jesd204/jesd204_rx/jesd204_rx.v @@ -55,6 +55,7 @@ module jesd204_rx #( parameter ENABLE_FRAME_ALIGN_CHECK = 1, parameter ENABLE_FRAME_ALIGN_ERR_RESET = 0, parameter ENABLE_CHAR_REPLACE = 0, + parameter ENABLE_FEC = 0, parameter ASYNC_CLK = 1, parameter TPL_DATA_PATH_WIDTH = LINK_MODE == 2 ? 8 : 4 ) ( @@ -96,6 +97,7 @@ module jesd204_rx #( input [9:0] cfg_octets_per_multiframe, input [7:0] cfg_octets_per_frame, input cfg_disable_scrambler, + input [1:0] cfg_header_mode, input cfg_disable_char_replacement, input [7:0] cfg_frame_align_err_threshold, @@ -109,7 +111,7 @@ module jesd204_rx #( input [7:0] device_cfg_buffer_delay, input ctrl_err_statistics_reset, - input [6:0] ctrl_err_statistics_mask, + input [8:0] ctrl_err_statistics_mask, output [32*NUM_LANES-1:0] status_err_statistics_cnt, @@ -538,6 +540,7 @@ module jesd204_rx #( jesd204_rx_lane_64b #( .ELASTIC_BUFFER_SIZE(ELASTIC_BUFFER_SIZE), + .ENABLE_FEC(ENABLE_FEC), .TPL_DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH), .ASYNC_CLK(ASYNC_CLK) ) i_lane ( @@ -552,7 +555,7 @@ module jesd204_rx #( .phy_block_sync(phy_block_sync_r[i]), .cfg_disable_scrambler(cfg_disable_scrambler), - .cfg_header_mode(2'b0), + .cfg_header_mode(cfg_header_mode), .cfg_rx_thresh_emb_err(5'd8), .cfg_beats_per_multiframe(cfg_beats_per_multiframe), @@ -566,7 +569,7 @@ module jesd204_rx #( .emb_lock(emb_lock[i]), .ctrl_err_statistics_reset(ctrl_err_statistics_reset), - .ctrl_err_statistics_mask(ctrl_err_statistics_mask[6:3]), + .ctrl_err_statistics_mask(ctrl_err_statistics_mask[8:3]), .status_err_statistics_cnt(status_err_statistics_cnt[32*i+31:32*i]), .status_lane_emb_state(status_lane_emb_state[3*i+2:3*i]), diff --git a/library/jesd204/jesd204_rx/jesd204_rx_fec_lfsr.sv b/library/jesd204/jesd204_rx/jesd204_rx_fec_lfsr.sv new file mode 100755 index 0000000000..8dead64bfe --- /dev/null +++ b/library/jesd204/jesd204_rx/jesd204_rx_fec_lfsr.sv @@ -0,0 +1,145 @@ +// +// The ADI JESD204 Core is released under the following license, which is +// different than all other HDL cores in this repository. +// +// Please read this, and understand the freedoms and responsibilities you have +// by using this source code/core. +// +// The JESD204 HDL, is copyright © 2016-2017 Analog Devices Inc. +// +// This core is free software, you can use run, copy, study, change, ask +// questions about and improve this core. Distribution of source, or resulting +// binaries (including those inside an FPGA or ASIC) require you to release the +// source of the entire project (excluding the system libraries provide by the +// tools/compiler/FPGA vendor). These are the terms of the GNU General Public +// License version 2 as published by the Free Software Foundation. +// +// This core 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 version 2 +// along with this source code, and binary. If not, see +// . +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + + +`timescale 1ns / 100ps + +// JESD204C RX FEC DECODER LFSR +module jesd204_rx_fec_lfsr #( + localparam LFSR_WIDTH = 26, + parameter MAX_SHIFT_CNT = 64 +)( + // One cycle after shift_en = 1, + // data_out[shift_cnt:0] contains the next shift_cnt + 1 output bits + // data_out[MAX_SHIFT_CNT-1:shift_cnt+1] is undefined + output logic [MAX_SHIFT_CNT-1:0] data_out, + // Value of the shift register updated one cycle after shift_en is asserted + output logic [LFSR_WIDTH:1] shift_reg, + // Value of the shift register if shift_en is asserted for each value of shift_cnt from 1 to MAX_SHIFT_CNT + output logic [LFSR_WIDTH:1] shift_reg_next[MAX_SHIFT_CNT-1:0], + input wire clk, + input wire rst, + input wire load_en, + input wire [LFSR_WIDTH:1] load_data, + input wire shift_en, + // Number of bits to shift - 1 + input wire [$clog2(MAX_SHIFT_CNT)-1:0] shift_cnt, + input wire [MAX_SHIFT_CNT-1:0] data_in +); + + localparam [LFSR_WIDTH:1] RESET_VAL = {LFSR_WIDTH{1'b0}}; + + // 𝑥^26 + 𝑥^21 + 𝑥^17 + 𝑥^9 + 𝑥^4 + 1 + // 100001000100000001000010001 + // Remove the MSb (x^26) term because it corresponds to one shift past the end of the LFSR, + // and represents feedback from the x^26 term to the other taps + // 0000 1000 1000 0000 1000 0100 01 + // Reverse the order of the taps because the LSb of the LFSR contains the MSb of the FEC data + // 10 0010 0001 0000 0001 0001 0000 + localparam [LFSR_WIDTH:1] FEC_POLYNOMIAL_1 = 26'h2210110; + + // 𝑥^24 + 𝑥^21 + 𝑥^19 + 𝑥^18 + 𝑥^17 + 𝑥^9 + 𝑥^7 + 𝑥^4 + 𝑥^2 + 𝑥 + 1 + // 001001011100000001010010111 + // Remove the MSb (x^26) term because it corresponds to one shift past the end of the LFSR + // 0100 1011 1000 0000 1010 0101 11 + // Reverse the order of the taps because the LSb of the LFSR contains the MSb of the FEC data + // 11 1010 0101 0000 0001 1101 0010 + localparam [LFSR_WIDTH:1] FEC_POLYNOMIAL_2 = 26'h3A501D2; + + function automatic [LFSR_WIDTH:1] fec_decode_galois_next(input [LFSR_WIDTH:1] cur, input next_data_in); + int ii; + reg x_26 = cur[1]; + fec_decode_galois_next[LFSR_WIDTH] = next_data_in ^ x_26; + for(ii = LFSR_WIDTH-1; ii > 0; ii=ii-1) begin : shift_reg_gen + fec_decode_galois_next[ii] = cur[ii+1] ^ (x_26 & FEC_POLYNOMIAL_1[ii]) ^ (next_data_in & FEC_POLYNOMIAL_2[ii]); + end + endfunction + + logic [MAX_SHIFT_CNT-1:0] data_out_next; + logic [LFSR_WIDTH:1] shift_reg_in_start; + logic [LFSR_WIDTH:1] shift_reg_in_next[MAX_SHIFT_CNT-1:0]; + genvar jj; + + // Generate shift register values for each number of shifts + for(jj = 0; jj < MAX_SHIFT_CNT; jj = jj + 1) begin : shift_gen + if(jj == 0) begin : zero_gen + assign shift_reg_in_next[jj] = shift_reg_in_start; + end else begin : non_zero_gen + assign shift_reg_in_next[jj] = shift_reg_next[jj-1]; + end + + // Output bit is the LSb of the shift register + assign data_out_next[jj] = shift_reg_in_next[jj][1]; + + assign shift_reg_next[jj] = fec_decode_galois_next(shift_reg_in_next[jj], data_in[jj]); + end + + // Shift register input is output of previous shift register value, + // or load value if load enabled + always @(posedge clk) begin + if(rst) begin + shift_reg_in_start <= RESET_VAL; + end else begin + if(load_en) begin + shift_reg_in_start <= load_data; + end else if(shift_en) begin + shift_reg_in_start <= shift_reg_next[shift_cnt]; + end + end + end + + always @(posedge clk) begin + if(rst) begin + shift_reg <= RESET_VAL; + end else begin + if(shift_en) begin + shift_reg <= shift_reg_next[shift_cnt]; + data_out <= data_out_next; + end else if(load_en) begin + shift_reg <= load_data; + end + end + end + +endmodule diff --git a/library/jesd204/jesd204_rx/jesd204_rx_header.v b/library/jesd204/jesd204_rx/jesd204_rx_header.v index 3fd1e6d9f9..357ebc7338 100644 --- a/library/jesd204/jesd204_rx/jesd204_rx_header.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_header.v @@ -59,6 +59,7 @@ module jesd204_rx_header ( output valid_eomb, output valid_eoemb, + output reg valid_fec, // Received header data qualified by valid_eomb output [11:0] crc12, output [2:0] crc3, @@ -118,7 +119,7 @@ module jesd204_rx_header ( cfg_header_mode == 1 ? {12'b0,cmd1} : cfg_header_mode == 3 ? cmd3 : 'b0; - assign fec = {sync_word[31:10],sync_word[8:5]}; + assign fec = {sync_word[26:5],sync_word[3:0]}; assign eomb = sync_word[4:0] == 5'b00001; assign eoemb = sync_word[9] & eomb; @@ -176,11 +177,20 @@ module jesd204_rx_header ( assign invalid_eoemb = (sh_count == 0 && ~eoemb); assign invalid_eomb = (sh_count[4:0] == 0 && ~eomb); - assign valid_eomb = next_state[BIT_EMB_LOCK] && eomb; - assign valid_eoemb = next_state[BIT_EMB_LOCK] && eoemb; + assign valid_eomb = next_state[BIT_EMB_LOCK] && (sh_count == 0) && eomb; + assign valid_eoemb = next_state[BIT_EMB_LOCK] && (sh_count == 0) && eoemb; assign invalid_sequence = (invalid_eoemb || invalid_eomb); +// FEC signal is available before EOMB +always @(posedge clk) begin + if (reset == 1'b1) begin + valid_fec <= 1'b0; + end else begin + valid_fec <= next_state[BIT_EMB_LOCK] && (sh_count[4:0] == 26); + end +end + always @(posedge clk) begin if (reset == 1'b1) begin state <= STATE_EMB_INIT; diff --git a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v index 4d893eced2..390e7c88f5 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v @@ -46,6 +46,7 @@ module jesd204_rx_lane_64b #( parameter ELASTIC_BUFFER_SIZE = 256, + parameter ENABLE_FEC = 1'b0, parameter TPL_DATA_PATH_WIDTH = 8, parameter ASYNC_CLK = 0 ) ( @@ -74,7 +75,7 @@ module jesd204_rx_lane_64b #( input [7:0] cfg_beats_per_multiframe, input ctrl_err_statistics_reset, - input [3:0] ctrl_err_statistics_mask, + input [5:0] ctrl_err_statistics_mask, output [31:0] status_err_statistics_cnt, output [2:0] status_lane_emb_state, @@ -83,7 +84,6 @@ module jesd204_rx_lane_64b #( reg [11:0] crc12_calculated_prev; - wire [63:0] eomb_r; wire [63:0] phy_data_r; wire [63:0] data_descrambled_s; wire [63:0] data_descrambled; @@ -95,12 +95,27 @@ module jesd204_rx_lane_64b #( wire event_unexpected_eomb; wire event_unexpected_eoemb; wire event_crc12_mismatch; + wire event_fec_trapped_error_flag; + wire event_fec_untrapped_error_flag; wire err_cnt_rst; wire [63:0] rx_data_msb_s; wire eomb; wire eoemb; + wire eomb_r; + wire valid_fec; + wire [25:0] fec_received; + wire fec_en; + wire [63:0] fec_data_out; + wire [63:0] scram_data_in; + wire fec_data_out_valid; + wire fec_trapped_error_flag; + wire fec_untrapped_error_flag; + wire buffer_not_ready_next; + wire buffer_ready_next; + reg [2:1] buffer_not_ready_r; + reg [2:1] buffer_ready_r; wire [7:0] sh_count; @@ -119,9 +134,10 @@ module jesd204_rx_lane_64b #( .valid_eomb(eomb), .valid_eoemb(eoemb), + .valid_fec(valid_fec), .crc12(crc12_received), .crc3(), - .fec(), + .fec(fec_received), .cmd(), .sh_count(sh_count), @@ -157,7 +173,7 @@ module jesd204_rx_lane_64b #( always @(posedge clk) begin if (reset == 1'b1) begin crc12_on <= 1'b0; - end else if (eomb_r) begin + end else if ((cfg_header_mode == 2'd0) && eomb_r) begin crc12_on <= 1'b1; end end @@ -181,14 +197,41 @@ module jesd204_rx_lane_64b #( assign err_cnt_rst = reset || ctrl_err_statistics_reset; + assign fec_en = (cfg_header_mode == 2'd2); + + if(ENABLE_FEC) begin : gen_fec + jesd204_fec_decode #( + .DATA_WIDTH (64) + ) jesd204_fec_decode ( + .data_out (fec_data_out), + .data_out_valid (fec_data_out_valid), + .trapped_error_flag (fec_trapped_error_flag), + .untrapped_error_flag (fec_untrapped_error_flag), + .clk (clk), + .rst (reset), + .eomb (eomb), + .fec_in_valid (valid_fec), + .fec_in (fec_received), + .data_in (phy_data) + ); + + assign scram_data_in = fec_en ? fec_data_out : phy_data; + assign event_fec_trapped_error_flag = fec_en && fec_trapped_error_flag; + assign event_fec_untrapped_error_flag = fec_en && fec_untrapped_error_flag; + end else begin : gen_no_fec + assign scram_data_in = phy_data; + end + error_monitor #( - .EVENT_WIDTH(4), + .EVENT_WIDTH(6), .CNT_WIDTH(32) ) i_error_monitor ( .clk(clk), .reset(err_cnt_rst), .active(1'b1), .error_event({ + event_fec_trapped_error_flag, + event_fec_untrapped_error_flag, event_invalid_header, event_unexpected_eomb, event_unexpected_eoemb, @@ -202,9 +245,9 @@ module jesd204_rx_lane_64b #( .DESCRAMBLE(1) ) i_descrambler ( .clk(clk), - .reset(1'b0), + .reset(reset), .enable(~cfg_disable_scrambler), - .data_in(phy_data), + .data_in(scram_data_in), .data_out(data_descrambled_s)); pipeline_stage #( @@ -224,13 +267,33 @@ module jesd204_rx_lane_64b #( // other lanes are not writing in the next half multiblock period stop // writing. // This limits the supported lane skew to half of the multiframe + + assign buffer_not_ready_next = sh_count == {1'b0,cfg_beats_per_multiframe[7:1]} && all_buffer_ready_n; + assign buffer_ready_next = eomb; + always @(posedge clk) begin - if (reset | ~emb_lock) begin - buffer_ready_n <= 1'b1; - end else if (sh_count == {1'b0,cfg_beats_per_multiframe[7:1]} && all_buffer_ready_n) begin + buffer_not_ready_r <= {buffer_not_ready_r[1], buffer_not_ready_next}; + buffer_ready_r <= {buffer_ready_r[1], buffer_ready_next}; + end + + always @(posedge clk) begin + if (reset | ~emb_lock | (fec_en & ~fec_data_out_valid)) begin buffer_ready_n <= 1'b1; - end else if (eoemb) begin - buffer_ready_n <= 1'b0; + end else begin + // FEC data is delayed by 2 cycles + if(fec_en) begin + if(buffer_not_ready_r[2]) begin + buffer_ready_n <= 1'b1; + end else if(buffer_ready_r[2]) begin + buffer_ready_n <= 1'b0; + end + end else begin + if(buffer_not_ready_next) begin + buffer_ready_n <= 1'b1; + end else if(buffer_ready_next) begin + buffer_ready_n <= 1'b0; + end + end end end diff --git a/library/jesd204/jesd204_rx_static_config/jesd204_rx_static_config.v b/library/jesd204/jesd204_rx_static_config/jesd204_rx_static_config.v index 26e9256c52..e426d15631 100755 --- a/library/jesd204/jesd204_rx_static_config/jesd204_rx_static_config.v +++ b/library/jesd204/jesd204_rx_static_config/jesd204_rx_static_config.v @@ -52,6 +52,7 @@ module jesd204_rx_static_config #( parameter SCR = 1, parameter BUFFER_EARLY_RELEASE = 0, parameter LINK_MODE = 1, // 2 - 64B/66B; 1 - 8B/10B + parameter HEADER_MODE = 0, // 0 - CRC12 ; 1 - CRC3; 2 - FEC; 3 - CMD parameter SYSREF_DISABLE = 0, parameter SYSREF_ONE_SHOT = 0, /* Only 4, 8 are supported at the moment for 8b/10b and 8 for 64b */ @@ -66,6 +67,7 @@ module jesd204_rx_static_config #( output [7:0] cfg_octets_per_frame, output cfg_disable_scrambler, output cfg_disable_char_replacement, + output [1:0] cfg_header_mode, output [7:0] cfg_frame_align_err_threshold, output [9:0] device_cfg_octets_per_multiframe, @@ -93,6 +95,7 @@ module jesd204_rx_static_config #( assign cfg_links_disable = {NUM_LINKS{1'b0}}; assign cfg_disable_scrambler = SCR ? 1'b0 : 1'b1; assign cfg_disable_char_replacement = 1'b0; + assign cfg_header_mode = HEADER_MODE; assign cfg_frame_align_err_threshold = 8'd4; endmodule diff --git a/library/jesd204/jesd204_tx/jesd204_fec_encode.sv b/library/jesd204/jesd204_tx/jesd204_fec_encode.sv new file mode 100755 index 0000000000..054d70bf00 --- /dev/null +++ b/library/jesd204/jesd204_tx/jesd204_fec_encode.sv @@ -0,0 +1,95 @@ +// +// The ADI JESD204 Core is released under the following license, which is +// different than all other HDL cores in this repository. +// +// Please read this, and understand the freedoms and responsibilities you have +// by using this source code/core. +// +// The JESD204 HDL, is copyright © 2016-2017 Analog Devices Inc. +// +// This core is free software, you can use run, copy, study, change, ask +// questions about and improve this core. Distribution of source, or resulting +// binaries (including those inside an FPGA or ASIC) require you to release the +// source of the entire project (excluding the system libraries provide by the +// tools/compiler/FPGA vendor). These are the terms of the GNU General Public +// License version 2 as published by the Free Software Foundation. +// +// This core 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 version 2 +// along with this source code, and binary. If not, see +// . +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + + +`timescale 1ns / 100ps + +// JESD204C FEC encoder +module jesd204_fec_encode #( + parameter DATA_WIDTH = 64 +)( + output logic [25:0] fec, + input wire clk, + input wire rst, + input wire shift_en, + input wire eomb, + input wire [DATA_WIDTH-1:0] data_in +); + + localparam [$clog2(DATA_WIDTH)-1:0] SHIFT_CNT = DATA_WIDTH-1; + + // 𝑥^26 + 𝑥^21 + 𝑥^17 + 𝑥^9 + 𝑥^4 + 1 + // 100001000100000001000010001 + // Remove the MSb (x^26) term because it represents the loopback from LSb of the LFSR to the MSb + // 0000 1000 1000 0000 1000 0100 01 + // Reverse the order of the taps because the LSb of the LFSR contains the MSb of the FEC data + // 10 0010 0001 0000 0001 0001 0000 + localparam [26:1] FEC_POLYNOMIAL = 26'h2210110; + + logic [25:0] fec_reversed; + genvar ii; + + // Reverse order of FEC bits so that fec[25:0] matches FEC[25:0] from the JESD204 specification + for(ii = 0; ii < 26; ii = ii + 1) begin : reverse_gen + assign fec[ii] = fec_reversed[25-ii]; + end + + lfsr_input #( + .LFSR_WIDTH (26), + .RESET_VAL ('0), + .LFSR_POLYNOMIAL (FEC_POLYNOMIAL), + .MAX_SHIFT_CNT (DATA_WIDTH) + ) lfsr_input ( + .data_out (), + .shift_reg (fec_reversed), + .shift_reg_next (), + .clk (clk), + .rst (rst), + .shift_en (shift_en), + .shift_reg_reset (eomb), + .shift_cnt (SHIFT_CNT), + .data_in (data_in) + ); + +endmodule diff --git a/library/jesd204/jesd204_tx/jesd204_tx.v b/library/jesd204/jesd204_tx/jesd204_tx.v index 23cc9ca077..fcad8a4f7e 100755 --- a/library/jesd204/jesd204_tx/jesd204_tx.v +++ b/library/jesd204/jesd204_tx/jesd204_tx.v @@ -54,6 +54,7 @@ module jesd204_tx #( parameter DATA_PATH_WIDTH = LINK_MODE[1] ? 8 : 4, parameter TPL_DATA_PATH_WIDTH = LINK_MODE[1] ? 8 : 4, parameter ENABLE_CHAR_REPLACE = 1'b0, + parameter ENABLE_FEC = 0, parameter ASYNC_CLK = 1 ) ( input clk, @@ -89,6 +90,7 @@ module jesd204_tx #( input cfg_skip_ilas, input [7:0] cfg_mframes_per_ilas, input cfg_disable_char_replacement, + input [1:0] cfg_header_mode, input cfg_disable_scrambler, input [9:0] device_cfg_octets_per_multiframe, @@ -486,7 +488,9 @@ pipeline_stage #( localparam D_STOP = D_START + DATA_PATH_WIDTH*8-1; localparam H_START = i * 2; localparam H_STOP = H_START + 2 -1; - jesd204_tx_lane_64b i_lane( + jesd204_tx_lane_64b #( + .ENABLE_FEC(ENABLE_FEC) + ) i_lane( .clk(clk), .reset(reset), @@ -501,7 +505,7 @@ pipeline_stage #( .eoemb(eoemb_r), .cfg_disable_scrambler(cfg_disable_scrambler), - .cfg_header_mode(2'b0), + .cfg_header_mode(cfg_header_mode), .cfg_lane_disable(cfg_lanes_disable[i])); end diff --git a/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v b/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v index 1422c05b35..4c6366cba0 100755 --- a/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v +++ b/library/jesd204/jesd204_tx/jesd204_tx_lane_64b.v @@ -44,7 +44,9 @@ `timescale 1ns/100ps -module jesd204_tx_lane_64b ( +module jesd204_tx_lane_64b #( + parameter ENABLE_FEC = 1'b0 +) ( input clk, input reset, @@ -65,15 +67,22 @@ module jesd204_tx_lane_64b ( ); reg [63:0] scrambled_data; + reg [63:0] scrambled_data_d1; reg lmc_edge_d1 = 'b0; reg lmc_edge_d2 = 'b0; + reg lmc_edge_d3 = 'b0; reg lmc_quarter_edge_d1 = 'b0; reg lmc_quarter_edge_d2 = 'b0; + reg lmc_quarter_edge_d3 = 'b0; reg tx_ready_d1 = 'b0; + reg tx_ready_d2 = 'b0; + reg eoemb_d1 = 'b0; + reg [11:0] crc12_d1 = 'b0; wire [63:0] tx_data_msb_s; wire [63:0] scrambled_data_r; wire [11:0] crc12; + wire [25:0] fec; /* Reorder octets MSB first */ genvar i; @@ -96,17 +105,23 @@ module jesd204_tx_lane_64b ( always @(posedge clk) begin lmc_edge_d1 <= lmc_edge; lmc_edge_d2 <= lmc_edge_d1; + lmc_edge_d3 <= lmc_edge_d2; lmc_quarter_edge_d1 <= lmc_quarter_edge; lmc_quarter_edge_d2 <= lmc_quarter_edge_d1; + lmc_quarter_edge_d3 <= lmc_quarter_edge_d2; end always @(posedge clk) begin scrambled_data <= scrambled_data_r; - phy_data <= scrambled_data; + scrambled_data_d1 <= scrambled_data; + phy_data <= scrambled_data_d1; end always @(posedge clk) begin tx_ready_d1 <= tx_ready; + tx_ready_d2 <= tx_ready_d1; + eoemb_d1 <= eoemb; + crc12_d1 <= crc12; end jesd204_crc12 i_crc12 ( @@ -116,20 +131,35 @@ module jesd204_tx_lane_64b ( .data_in(scrambled_data), .crc12(crc12)); + if(ENABLE_FEC) begin : gen_fec + jesd204_fec_encode #( + .DATA_WIDTH (64) + ) jesd204_fec_encode ( + .fec (fec), + .clk (clk), + .rst (~tx_ready), + .shift_en (tx_ready_d2), + .eomb (lmc_edge_d2), + .data_in (scrambled_data) + ); + end else begin : gen_no_fec + assign fec = 26'b0; + end + jesd204_tx_header i_header_gen ( .clk(clk), .reset(~tx_ready | cfg_lane_disable), .cfg_header_mode(cfg_header_mode), - .lmc_edge(lmc_edge_d2), - .lmc_quarter_edge(lmc_quarter_edge_d2), + .lmc_edge(lmc_edge_d3), + .lmc_quarter_edge(lmc_quarter_edge_d3), // Header content to be sent must be valid during lmc_edge - .eoemb(eoemb), + .eoemb(eoemb_d1), .crc3(3'b0), - .crc12(crc12), - .fec(26'b0), + .crc12(crc12_d1), + .fec(fec), .cmd(19'b0), .header(phy_header)); diff --git a/library/jesd204/jesd204_tx_static_config/jesd204_tx_static_config.v b/library/jesd204/jesd204_tx_static_config/jesd204_tx_static_config.v index 848f90a0a7..22100bf486 100755 --- a/library/jesd204/jesd204_tx_static_config/jesd204_tx_static_config.v +++ b/library/jesd204/jesd204_tx_static_config/jesd204_tx_static_config.v @@ -55,6 +55,7 @@ module jesd204_tx_static_config #( parameter HIGH_DENSITY = 1, parameter SCR = 1, parameter LINK_MODE = 1, // 2 - 64B/66B; 1 - 8B/10B + parameter HEADER_MODE = 0, // 0 - CRC12 ; 1 - CRC3; 2 - FEC; 3 - CMD parameter SYSREF_DISABLE = 0, parameter SYSREF_ONE_SHOT = 0, /* Only 4, 8 are supported at the moment for 8b/10b and 8 for 64b */ @@ -72,6 +73,7 @@ module jesd204_tx_static_config #( output cfg_skip_ilas, output [7:0] cfg_mframes_per_ilas, output cfg_disable_char_replacement, + output [1:0] cfg_header_mode, output cfg_disable_scrambler, output [9:0] device_cfg_octets_per_multiframe, @@ -95,6 +97,7 @@ module jesd204_tx_static_config #( assign cfg_skip_ilas = 1'b0; assign cfg_mframes_per_ilas = 3; assign cfg_disable_char_replacement = 1'b0; + assign cfg_header_mode = HEADER_MODE; assign cfg_disable_scrambler = SCR ? 1'b0 : 1'b1; assign device_cfg_octets_per_multiframe = (FRAMES_PER_MULTIFRAME * OCTETS_PER_FRAME) - 1; diff --git a/library/jesd204/tb/sim_jesd204_fec.sh b/library/jesd204/tb/sim_jesd204_fec.sh new file mode 100755 index 0000000000..ccbf8dc3f6 --- /dev/null +++ b/library/jesd204/tb/sim_jesd204_fec.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# module load xlm + +xmvlog -sv ../jesd204_common/lfsr_input.sv +xmvlog ../../../ad_common/fpga_src/ad_mem_dist.v +xmvlog -sv ../jesd204_tx/jesd204_fec_encode.sv +xmvlog -sv ../jesd204_rx/jesd204_rx_fec_lfsr.sv +xmvlog -sv ../jesd204_rx/jesd204_fec_decode.sv +xmvlog -sv tb_link_layer_fec.v +xmelab -LICQUEUE -access +rwc -timescale 1ns/1ns tb_link_layer_fec + +if [ "$#" -ne 1 ]; then + xmsim -gui tb_link_layer_fec & +fi + diff --git a/library/jesd204/tb/sim_jesd204_fec_encode.sh b/library/jesd204/tb/sim_jesd204_fec_encode.sh new file mode 100755 index 0000000000..baa36224f4 --- /dev/null +++ b/library/jesd204/tb/sim_jesd204_fec_encode.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# module load xlm + +xmvlog -sv ../jesd204_common/lfsr_input.sv +xmvlog -sv ../jesd204_tx/jesd204_fec_encode.sv +xmvlog -sv tb_jesd204_fec_encode.sv +xmelab -access +rwc -timescale 1ns/1ns tb_jesd204_fec_encode + +if [ "$#" -ne 1 ]; then + xmsim -gui tb_jesd204_fec_encode & +fi diff --git a/library/jesd204/tb/sim_lfsr_input.sh b/library/jesd204/tb/sim_lfsr_input.sh new file mode 100755 index 0000000000..0227481e77 --- /dev/null +++ b/library/jesd204/tb/sim_lfsr_input.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# module load xlm + +xmvlog -sv ../jesd204_common/lfsr_input.sv +xmvlog -sv tb_lfsr_input.sv +xmelab -access +rwc -timescale 1ns/1ns tb_lfsr_input + +if [ "$#" -ne 1 ]; then + xmsim -gui tb_lfsr_input & +fi diff --git a/library/jesd204/tb/sim_link_layer_fec.sh b/library/jesd204/tb/sim_link_layer_fec.sh new file mode 100755 index 0000000000..85d12646bb --- /dev/null +++ b/library/jesd204/tb/sim_link_layer_fec.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# module load xlm + +xmvlog ../../../util_cdc/fpga_src/sync_bits.v +xmvlog ../../../util_cdc/fpga_src/sync_event.v + +xmvlog ../jesd204_common/jesd204_lmfc.v +xmvlog ../jesd204_common/jesd204_scrambler.v +xmvlog ../jesd204_common/jesd204_scrambler_64b.v +xmvlog ../jesd204_common/jesd204_crc12.v +xmvlog ../jesd204_common/jesd204_frame_mark.v +xmvlog ../jesd204_common/jesd204_frame_align_replace.v +xmvlog ../jesd204_common/pipeline_stage.v + +xmvlog -sv ../jesd204_common/lfsr_input.sv +xmvlog -sv ../jesd204_tx/jesd204_fec_encode.sv +xmvlog ../jesd204_tx/jesd204_tx_lane.v +xmvlog ../jesd204_tx/jesd204_tx_lane_64b.v +xmvlog ../jesd204_tx/jesd204_tx_gearbox.v +xmvlog ../jesd204_tx/jesd204_tx_header.v +xmvlog ../jesd204_tx/jesd204_tx_ctrl.v +xmvlog ../jesd204_tx/jesd204_tx.v + +xmvlog ../../../ad_common/fpga_src/ad_mem_dist.v +xmvlog -sv ../jesd204_rx/jesd204_rx_fec_lfsr.sv +xmvlog -sv ../jesd204_rx/jesd204_fec_decode.sv +xmvlog ../jesd204_rx/jesd204_rx_lane.v +xmvlog ../jesd204_rx/jesd204_rx_lane_64b.v +xmvlog ../jesd204_rx/jesd204_rx_header.v +xmvlog ../jesd204_rx/jesd204_rx_cgs.v +xmvlog ../jesd204_rx/jesd204_rx_ctrl.v +xmvlog ../jesd204_rx/jesd204_rx_ctrl_64b.v +xmvlog ../jesd204_rx/elastic_buffer.v +xmvlog ../jesd204_rx/error_monitor.v +xmvlog ../jesd204_rx/jesd204_ilas_monitor.v +xmvlog ../jesd204_rx/align_mux.v +xmvlog ../jesd204_rx/jesd204_lane_latency_monitor.v +xmvlog ../jesd204_rx/jesd204_rx_frame_align.v +xmvlog ../jesd204_rx/jesd204_rx.v + +xmvlog ../jesd204_rx_static_config/jesd204_rx_static_config.v +xmvlog ../jesd204_tx_static_config/jesd204_tx_static_config.v +xmvlog ../jesd204_tx_static_config/jesd204_ilas_cfg_static.v + +xmvlog -sv tb_link_layer_fec.sv +xmelab -LICQUEUE -access +rwc -timescale 1ns/1ns tb_link_layer_fec + +if [ "$#" -ne 1 ]; then + xmsim -LICQUEUE -gui tb_link_layer_fec & +fi diff --git a/library/jesd204/tb/tb_jesd204_fec.sv b/library/jesd204/tb/tb_jesd204_fec.sv new file mode 100755 index 0000000000..1e8aa6b322 --- /dev/null +++ b/library/jesd204/tb/tb_jesd204_fec.sv @@ -0,0 +1,151 @@ +`timescale 1ns / 100ps +`default_nettype none + +module tb_jesd204_fec; + + localparam FEC_WIDTH = 26; + localparam DATA_WIDTH = 64; + + // localparam INPUT_DATA_WIDTH = 64; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = 64'h8001020305050423; + localparam INPUT_DATA_WIDTH = 2048*4; + localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {{2048{1'b1}}, 1'b1, 2047'b0, {2048{1'b1}}, 2047'b0, 1'b1}; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {2047'b0, 1'b1}; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {1'b1, 63'b0, 1'b1, 1983'b0}; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {INPUT_DATA_WIDTH{1'b1}}; + localparam ERROR_CYCLE = 33; // Cycle of decoder data input to corrupt + localparam ERROR_BITS = 64'h1FF000; // Bits of decoder input data to corrupt + localparam FEC_ERROR_BITS = '0; // {1'b1, 25'b0}; + + logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE_REVERSED; + logic [INPUT_DATA_WIDTH-1:0] data; + + logic [FEC_WIDTH-1:0] fec; + logic [FEC_WIDTH-1:0] fec_saved; + logic [FEC_WIDTH-1:0] decode_fec_in; + reg clk = 1'b0; + logic rst; + logic fec_in_valid; + logic shift_en; + logic data_in_valid; + logic [DATA_WIDTH-1:0] data_in; + logic [DATA_WIDTH-1:0] decode_data_in; + logic [DATA_WIDTH-1:0] data_out; + logic data_out_valid; + logic trapped_error_flag; + logic untrapped_error_flag; + logic eomb; + logic [27:1] eomb_d; + + int data_in_cnt; + int decode_cnt; + int cycle_cnt; + int ii; + + always #5 clk = ~clk; + + initial begin + // Shift data in MSb-first by reversing the data + for(ii = 0; ii < INPUT_DATA_WIDTH; ii = ii + 1) begin + DATA_VALUE_REVERSED[ii] = DATA_VALUE[INPUT_DATA_WIDTH-1-ii]; + end + rst = 1'b1; + #100ns; + rst = 1'b0; + end + + always_ff @(posedge clk) begin + if(rst) begin + shift_en <= 1'b0; + data <= DATA_VALUE_REVERSED; + data_in_cnt <= '0; + data_in_valid <= 1'b0; + end else begin + data_in_valid <= 1'b1; + if(data_in_cnt < INPUT_DATA_WIDTH) begin + data_in <= data[0+:DATA_WIDTH]; + data <= data >> DATA_WIDTH; + shift_en <= 1'b1; + data_in_cnt <= data_in_cnt + DATA_WIDTH; + end else begin + shift_en <= 1'b0; + end + end + end + + always_ff @(posedge clk) begin + if(rst) begin + cycle_cnt <= '0; + end else begin + if(data_in_valid) begin + if(cycle_cnt == 31) begin + cycle_cnt <= '0; + end else begin + cycle_cnt <= cycle_cnt + 1'b1; + end + end + end + end + + assign eomb = cycle_cnt == 31; + // assign eomb = (data_in_cnt == INPUT_DATA_WIDTH) && shift_en; + + always_ff @(posedge clk) begin + if(rst) begin + decode_cnt <= '0; + end else begin + if(shift_en) begin + decode_cnt <= decode_cnt + 1; + end + end + end + + assign decode_data_in = (decode_cnt == ERROR_CYCLE) ? (data_in ^ ERROR_BITS) : data_in; + assign decode_fec_in = fec_saved ^ FEC_ERROR_BITS; + + jesd204_fec_encode #( + .DATA_WIDTH (DATA_WIDTH) + ) jesd204_fec_encode ( + .fec (fec), + .clk (clk), + .rst (rst), + .shift_en (data_in_valid), + .eomb (eomb), + .data_in (data_in) + ); + + always_ff @(posedge clk) begin + if(rst) begin + eomb_d <= '0; + end else begin + eomb_d <= {eomb_d[26:1], eomb}; + end + end + + always_ff @(posedge clk) begin + if(eomb_d[1]) begin + fec_saved <= fec; + end + end + + assign fec_in_valid = eomb_d[27]; + + jesd204_fec_decode #( + .DATA_WIDTH (DATA_WIDTH) + ) jesd204_fec_decode ( + .data_out (data_out), + .data_out_valid (data_out_valid), + .trapped_error_flag (trapped_error_flag), + .untrapped_error_flag (untrapped_error_flag), + .clk (clk), + .rst (rst), + .eomb (eomb), + .fec_in_valid (fec_in_valid), + .fec_in (decode_fec_in), + .data_in (decode_data_in) + ); + + +endmodule + +`default_nettype wire diff --git a/library/jesd204/tb/tb_jesd204_fec_encode.v b/library/jesd204/tb/tb_jesd204_fec_encode.v new file mode 100755 index 0000000000..bf4352e121 --- /dev/null +++ b/library/jesd204/tb/tb_jesd204_fec_encode.v @@ -0,0 +1,67 @@ +`timescale 1ns / 100ps +`default_nettype none + +module tb_jesd204_fec_encode; + + localparam FEC_WIDTH = 26; + localparam DATA_WIDTH = 64; + + // localparam INPUT_DATA_WIDTH = 64; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = 64'h8001020305050423; + localparam INPUT_DATA_WIDTH = 2048; + localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {1'b1, 2047'b0}; + + logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE_REVERSED; + logic [DATA_WIDTH-1:0] data; + + logic [FEC_WIDTH-1:0] fec; + reg clk = 1'b0; + logic rst; + logic shift_en; + logic [DATA_WIDTH-1:0] data_in; + + int data_in_cnt; + int ii; + + always #5 clk = ~clk; + + initial begin + // Shift data in MSb-first by reversing the data + for(ii = 0; ii < INPUT_DATA_WIDTH; ii = ii + 1) begin + DATA_VALUE_REVERSED[ii] = DATA_VALUE[INPUT_DATA_WIDTH-1-ii]; + end + rst = 1'b1; + #100ns; + rst = 1'b0; + end + + always_ff @(posedge clk) begin + if(rst) begin + shift_en <= 1'b0; + data <= DATA_VALUE_REVERSED; + data_in_cnt <= '0; + end else begin + if(data_in_cnt < INPUT_DATA_WIDTH) begin + data_in <= data[0+:DATA_WIDTH]; + data <= data >> DATA_WIDTH; + shift_en <= 1'b1; + data_in_cnt <= data_in_cnt + DATA_WIDTH; + end else begin + shift_en <= 1'b0; + end + end + end + + jesd204_fec_encode #( + .DATA_WIDTH (DATA_WIDTH) + ) jesd204_fec_encode ( + .fec (fec), + .clk (clk), + .rst (rst), + .shift_en (shift_en), + .data_in (data_in) + ); + +endmodule + +`default_nettype wire diff --git a/library/jesd204/tb/tb_lfsr_input.sv b/library/jesd204/tb/tb_lfsr_input.sv new file mode 100755 index 0000000000..f7390c3e7e --- /dev/null +++ b/library/jesd204/tb/tb_lfsr_input.sv @@ -0,0 +1,95 @@ +`timescale 1ns / 100ps +`default_nettype none + + +module tb_lfsr_input; + + localparam LFSR_WIDTH = 26; + localparam [LFSR_WIDTH:1] RESET_VAL = {LFSR_WIDTH{1'b0}}; + localparam [LFSR_WIDTH:1] LFSR_POLYNOMIAL = 26'h2210110; + localparam MAX_SHIFT_CNT = 64; + + // localparam INPUT_DATA_WIDTH = 64; + // localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = 64'h8001020305050423; + localparam INPUT_DATA_WIDTH = 2048; + localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {1'b1, 2047'b0}; + + logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE_REVERSED; + logic [MAX_SHIFT_CNT-1:0] data; + + logic [MAX_SHIFT_CNT-1:0] data_out; + logic [LFSR_WIDTH:1] shift_reg; + reg clk = 1'b0; + logic rst; + logic shift_en; + logic [$clog2(MAX_SHIFT_CNT)-1:0] shift_cnt; + logic [MAX_SHIFT_CNT-1:0] data_in; + + int data_in_cnt; + int ii; + + always #5 clk = ~clk; + + // 𝑥^26 + 𝑥^21 + 𝑥^17 + 𝑥^9 + 𝑥^4 + 1 + // 100001000100000001000010001 + // Remove the MSb (x^26) term because it represents the loopback from LSb of the LFSR to the MSb + // 0000 1000 1000 0000 1000 0100 01 + // Reverse the order of the taps because the LSb of the LFSR contains the MSb of the FEC data + // 10 0010 0001 0000 0001 0001 0000 + + // S0 S25 FEC register index + // 26 1 LFSR_POLYNOMIAL index + // X0001000010000000100010000 + // X0 0010 0001 0000 0001 0001 0000 + + + + + + initial begin + for(ii = 0; ii < INPUT_DATA_WIDTH; ii = ii + 1) begin + DATA_VALUE_REVERSED[ii] = DATA_VALUE[INPUT_DATA_WIDTH-1-ii]; + end + rst = 1'b1; + #100ns; + rst = 1'b0; + end + + always_ff @(posedge clk) begin + if(rst) begin + shift_en <= 1'b0; + data <= DATA_VALUE_REVERSED; + data_in_cnt <= '0; + end else begin + if(data_in_cnt < INPUT_DATA_WIDTH) begin + // Shift data in MSb-first by reversing the data + data_in <= data[0+:MAX_SHIFT_CNT]; + data <= data >> (shift_cnt+1); + shift_en <= 1'b1; + data_in_cnt <= data_in_cnt + (shift_cnt + 1); + end else begin + shift_en <= 1'b0; + end + end + end + + assign shift_cnt = 63; + + lfsr_input #( + .LFSR_WIDTH (LFSR_WIDTH), + .RESET_VAL (RESET_VAL), + .LFSR_POLYNOMIAL (LFSR_POLYNOMIAL), + .MAX_SHIFT_CNT (MAX_SHIFT_CNT) + ) lfsr_input ( + .data_out (data_out), + .shift_reg (shift_reg), + .clk (clk), + .rst (rst), + .shift_en (shift_en), + .shift_cnt (shift_cnt), + .data_in (data_in) + ); + +endmodule + +`default_nettype wire diff --git a/library/jesd204/tb/tb_link_layer_fec.sv b/library/jesd204/tb/tb_link_layer_fec.sv new file mode 100755 index 0000000000..a0adcb775e --- /dev/null +++ b/library/jesd204/tb/tb_link_layer_fec.sv @@ -0,0 +1,420 @@ +`timescale 1ns / 100ps +`default_nettype none + +module tb_link_layer_fec; + + localparam NUM_LANES=2; + localparam NUM_LINKS=1; + localparam SCR = 0; + localparam DATA_PATH_WIDTH = 8; + localparam DATA_WIDTH = DATA_PATH_WIDTH*8; + + localparam INPUT_DATA_WIDTH = 2048*9*2; + localparam INPUT_DATA_CYCLES = INPUT_DATA_WIDTH/DATA_WIDTH; + localparam logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE = {2{{2048{1'b1}}, 1'b1, 2047'b0, {64{32'h12345678}}, {2048{1'b1}}, 2047'b0, 1'b1, {64{32'hABCDEF01}}, {64{32'h23456789}}, {2048{1'b1}}, 1'b1, 2047'b0}}; + localparam ERROR_CYCLE = (32*8)+4; // Cycle of decoder data input to corrupt + // localparam RECOVERABLE_ERROR_BITS = 64'h1FF000; + localparam RECOVERABLE_ERROR_BITS = 64'h8000000000000000; + localparam UNRECOVERABLE_ERROR_BITS = 64'h1FFFFF; + localparam ERROR_BITS = RECOVERABLE_ERROR_BITS; // Bits of decoder input data to corrupt + localparam NEXT_ERROR_BITS = 64'h1; + // localparam NEXT_ERROR_BITS = 64'h0000000000000000; + localparam REPORT_GOOD_DATA = 1'b1; + + reg clk = 1'b0; + reg sysref = 1'b0; + logic rst; + logic [INPUT_DATA_WIDTH-1:0] DATA_VALUE_REVERSED; + logic [INPUT_DATA_WIDTH-1:0] data; + logic [DATA_WIDTH-1:0] data_in; + logic [DATA_WIDTH-1:0] data_in_swap; + int data_in_cnt; + int ii; + int tx_cycle_cnt; + int rx_cycle_cnt; + genvar jj; + + logic [NUM_LANES-1:0] tx_cfg_lanes_disable; + logic [NUM_LINKS-1:0] tx_cfg_links_disable; + logic [9:0] tx_cfg_octets_per_multiframe; + logic [7:0] tx_cfg_octets_per_frame; + logic [9:0] tx_device_cfg_octets_per_multiframe; + logic [7:0] tx_device_cfg_octets_per_frame; + logic [7:0] tx_device_cfg_beats_per_multiframe; + logic [7:0] tx_device_cfg_lmfc_offset; + logic tx_device_cfg_sysref_oneshot; + logic tx_device_cfg_sysref_disable; + logic tx_cfg_continuous_cgs; + logic tx_cfg_continuous_ilas; + logic tx_cfg_skip_ilas; + logic [7:0] tx_cfg_mframes_per_ilas; + logic tx_cfg_disable_char_replacement; + logic [1:0] tx_cfg_header_mode; + logic tx_cfg_disable_scrambler; + logic tx_lmfc_edge; + logic tx_lmfc_clk; + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] tx_data; + logic tx_ready; + logic [DATA_PATH_WIDTH-1:0] tx_eof; + logic [DATA_PATH_WIDTH-1:0] tx_sof; + logic [DATA_PATH_WIDTH-1:0] tx_somf; + logic [DATA_PATH_WIDTH-1:0] tx_eomf; + logic tx_valid; + + logic [NUM_LANES-1:0] rx_cfg_lanes_disable; + logic [NUM_LINKS-1:0] rx_cfg_links_disable; + logic [9:0] rx_cfg_octets_per_multiframe; + logic [7:0] rx_cfg_octets_per_frame; + logic [9:0] rx_device_cfg_octets_per_multiframe; + logic [7:0] rx_device_cfg_octets_per_frame; + logic [7:0] rx_device_cfg_beats_per_multiframe; + logic [7:0] rx_device_cfg_lmfc_offset; + logic rx_device_cfg_sysref_oneshot; + logic rx_device_cfg_sysref_disable; + logic [7:0] rx_device_cfg_buffer_delay; + logic rx_device_cfg_buffer_early_release; + logic rx_cfg_disable_scrambler; + logic rx_cfg_disable_char_replacement; + logic [1:0] rx_cfg_header_mode; + logic [7:0] rx_cfg_frame_align_err_threshold; + + + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] tx_phy_data; + logic [2*NUM_LANES-1:0] tx_phy_header; + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] rx_phy_data; + logic [2*NUM_LANES-1:0] rx_phy_header; + logic [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_charisk; + logic [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_notintable; + logic [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_disperr; + logic [NUM_LANES-1:0] phy_block_sync; + logic rx_lmfc_edge; + logic rx_lmfc_clk; + logic phy_en_char_align; + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] rx_data; + logic rx_valid; + logic [DATA_PATH_WIDTH-1:0] rx_eof; + logic [DATA_PATH_WIDTH-1:0] rx_sof; + logic [DATA_PATH_WIDTH-1:0] rx_eomf; + logic [DATA_PATH_WIDTH-1:0] rx_somf; + logic rx_ctrl_err_statistics_reset; + logic [8:0] rx_ctrl_err_statistics_mask; + logic [32*NUM_LANES-1:0] rx_status_err_statistics_cnt; + + logic tx_data_dropped; + logic cur_error_cycle; + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] tx_data_q[$]; + logic [DATA_PATH_WIDTH*8*NUM_LANES-1:0] cur_tx_data; + + always #5ns clk = ~clk; + + always #(5ns*32*8) sysref = ~sysref; + + initial begin + rst = 1'b1; + #100ns; + rst = 1'b0; + end + + assign tx_valid = 1'b1; + // assign tx_data = {DATA_PATH_WIDTH*8*NUM_LANES{1'b1}}; + + initial begin + // Shift data in MSb-first by reversing the data + for(ii = 0; ii < INPUT_DATA_WIDTH; ii = ii + 1) begin + DATA_VALUE_REVERSED[ii] = DATA_VALUE[INPUT_DATA_WIDTH-1-ii]; + end + rst = 1'b1; + #100ns; + rst = 1'b0; + end + + initial begin + data = DATA_VALUE_REVERSED; + data_in_cnt = '0; + data_in = '0; + forever begin + data_in = data[0+:DATA_WIDTH]; + @(posedge clk); + #0; + if(tx_ready && (data_in_cnt < INPUT_DATA_CYCLES)) begin + data = data >> DATA_WIDTH; + data_in_cnt = data_in_cnt + 1; + end + end + end + + // // TX data is dropped until the first EoMB is seen + // initial begin + // tx_data_dropped = 1'b1; + // forever begin + // @(negedge clk); + // if(tx_ready & tx_eomf[DATA_PATH_WIDTH-1]) begin + // tx_data_dropped = 1'b0; + // end + // end + // end + + // The first 7 multiblocks of data are dropped, one by TX, 6 by RX + // TODO: is this dependent on TX data pattern when scrambling is disabled? + initial begin + tx_data_dropped = 1'b1; + forever begin + @(negedge clk); + if(tx_ready && (data_in_cnt >= (32 * 7))) begin + tx_data_dropped = 1'b0; + end + end + end + + // always_ff @(posedge clk) begin + // if(rst) begin + // data <= DATA_VALUE_REVERSED; + // data_in_cnt <= '0; + // data_in <= '0; + // end else begin + // if(tx_ready) begin + // if(data_in_cnt < INPUT_DATA_WIDTH) begin + // data_in <= data[0+:DATA_WIDTH]; + // data <= data >> DATA_WIDTH; + // data_in_cnt <= data_in_cnt + DATA_WIDTH; + // end + // end + // end + // end + + always_ff @(posedge clk) begin + if(rst) begin + tx_cycle_cnt <= '0; + end else begin + if(tx_ready) begin + tx_cycle_cnt <= tx_cycle_cnt + 1; + end + end + end + + // Swap order of octets + for(jj = 0; jj < DATA_PATH_WIDTH; jj=jj+1) begin : tx_data_gen + assign data_in_swap[jj*8+:8] = data_in[(DATA_PATH_WIDTH-jj-1)*8+:8]; + end + + assign tx_data = {NUM_LANES{data_in_swap}}; + + assign rx_phy_data = (tx_cycle_cnt == ERROR_CYCLE) ? (tx_phy_data ^ ERROR_BITS) : (tx_cycle_cnt == ERROR_CYCLE+1) ? (tx_phy_data ^ NEXT_ERROR_BITS) : tx_phy_data; + // assign rx_phy_data = tx_phy_data; + assign rx_phy_header = tx_phy_header; + + assign rx_ctrl_err_statistics_mask = 8'h3F; // FEC trapped and non-trapped error + assign rx_ctrl_err_statistics_reset = 1'b0; + + assign cur_error_cycle = tx_cycle_cnt == ERROR_CYCLE; + + initial begin + tx_data_q = {}; + forever begin + @(negedge clk); + if(tx_ready && !tx_data_dropped && (data_in_cnt < INPUT_DATA_CYCLES)) begin + tx_data_q.push_back(tx_data); + // $display("%t TX Cycle %d: %X", $time, tx_cycle_cnt, tx_data); + end + end + end + + initial begin + rx_cycle_cnt = 0; + forever begin + @(negedge clk); + if(rx_valid) begin + if(tx_data_q.size() == 0) begin + $finish; + end + cur_tx_data = tx_data_q.pop_front(); + if(cur_tx_data !== rx_data) begin + $error("RX Cycle: %d Data mismatch. Expected: %X Observed: %X", rx_cycle_cnt, cur_tx_data, rx_data); + end else if(REPORT_GOOD_DATA) begin + $display("RX Cycle: %d Good data:%X", rx_cycle_cnt, cur_tx_data); + end + rx_cycle_cnt = rx_cycle_cnt + 1; + end + end + end + + jesd204_tx_static_config #( + .NUM_LANES (NUM_LANES), + .OCTETS_PER_FRAME(8), + .FRAMES_PER_MULTIFRAME(32), + .SCR (SCR), + .LINK_MODE (2), + .HEADER_MODE (2) + ) jesd204_tx_static_config ( + .clk (clk), + .cfg_lanes_disable (tx_cfg_lanes_disable), + .cfg_links_disable (tx_cfg_links_disable), + .cfg_octets_per_multiframe (tx_cfg_octets_per_multiframe), + .cfg_octets_per_frame (tx_cfg_octets_per_frame), + .device_cfg_octets_per_multiframe (tx_device_cfg_octets_per_multiframe), + .device_cfg_octets_per_frame (tx_device_cfg_octets_per_frame), + .device_cfg_beats_per_multiframe (tx_device_cfg_beats_per_multiframe), + .device_cfg_lmfc_offset (tx_device_cfg_lmfc_offset), + .device_cfg_sysref_oneshot (tx_device_cfg_sysref_oneshot), + .device_cfg_sysref_disable (tx_device_cfg_sysref_disable), + .cfg_continuous_cgs (tx_cfg_continuous_cgs), + .cfg_continuous_ilas (tx_cfg_continuous_ilas), + .cfg_skip_ilas (tx_cfg_skip_ilas), + .cfg_mframes_per_ilas (tx_cfg_mframes_per_ilas), + .cfg_disable_char_replacement (tx_cfg_disable_char_replacement), + .cfg_header_mode (tx_cfg_header_mode), + .cfg_disable_scrambler (tx_cfg_disable_scrambler), + .ilas_config_rd(), + .ilas_config_addr(), + .ilas_config_data() + ); + + jesd204_tx #( + .NUM_LANES (NUM_LANES), + .NUM_LINKS (NUM_LINKS), + .NUM_INPUT_PIPELINE (1), + .NUM_OUTPUT_PIPELINE (0), + .LINK_MODE (2), + .ENABLE_FEC (1), + .DATA_PATH_WIDTH (DATA_PATH_WIDTH) + ) jesd204_tx ( + .clk (clk), + .reset (rst), + .device_clk (clk), + .device_reset (rst), + .phy_data (tx_phy_data), + .phy_charisk (phy_charisk), + .phy_header (tx_phy_header), + .sysref (sysref), + .lmfc_edge (tx_lmfc_edge), + .lmfc_clk (tx_lmfc_clk), + .sync ('0), + .tx_data (tx_data), + .tx_ready (tx_ready), + .tx_eof (tx_eof), + .tx_sof (tx_sof), + .tx_eomf (tx_eomf), + .tx_somf (tx_somf), + .tx_valid (tx_valid), + .cfg_lanes_disable (tx_cfg_lanes_disable), + .cfg_links_disable (tx_cfg_links_disable), + .cfg_octets_per_multiframe (tx_cfg_octets_per_multiframe), + .cfg_octets_per_frame (tx_cfg_octets_per_frame), + .device_cfg_octets_per_multiframe (tx_device_cfg_octets_per_multiframe), + .device_cfg_octets_per_frame (tx_device_cfg_octets_per_frame), + .device_cfg_beats_per_multiframe (tx_device_cfg_beats_per_multiframe), + .device_cfg_lmfc_offset (tx_device_cfg_lmfc_offset), + .device_cfg_sysref_oneshot (tx_device_cfg_sysref_oneshot), + .device_cfg_sysref_disable (tx_device_cfg_sysref_disable), + .cfg_continuous_cgs (tx_cfg_continuous_cgs), + .cfg_continuous_ilas (tx_cfg_continuous_ilas), + .cfg_skip_ilas (tx_cfg_skip_ilas), + .cfg_mframes_per_ilas (tx_cfg_mframes_per_ilas), + .cfg_disable_char_replacement (tx_cfg_disable_char_replacement), + .cfg_header_mode (tx_cfg_header_mode), + .cfg_disable_scrambler (tx_cfg_disable_scrambler), + .ilas_config_rd (), + .ilas_config_addr (), + .ilas_config_data ('0), + .ctrl_manual_sync_request (), + .device_event_sysref_edge (), + .device_event_sysref_alignment_error (), + .status_sync (), + .status_state () + ); + + + + jesd204_rx_static_config #( + .NUM_LANES (NUM_LANES), + .OCTETS_PER_FRAME (8), + .FRAMES_PER_MULTIFRAME (32), + .SCR (SCR), + .LINK_MODE (2), + .HEADER_MODE (2), + .SYSREF_DISABLE (0) + ) jesd204_rx_static_config( + .clk (clk), + .cfg_lanes_disable (rx_cfg_lanes_disable), + .cfg_links_disable (rx_cfg_links_disable), + .cfg_disable_scrambler (rx_cfg_disable_scrambler), + .cfg_disable_char_replacement (rx_cfg_disable_char_replacement), + .cfg_header_mode (rx_cfg_header_mode), + .cfg_frame_align_err_threshold (rx_cfg_frame_align_err_threshold), + .cfg_octets_per_multiframe (rx_cfg_octets_per_multiframe), + .cfg_octets_per_frame (rx_cfg_octets_per_frame), + .device_cfg_octets_per_multiframe (rx_device_cfg_octets_per_multiframe), + .device_cfg_octets_per_frame (rx_device_cfg_octets_per_frame), + .device_cfg_beats_per_multiframe (rx_device_cfg_beats_per_multiframe), + .device_cfg_lmfc_offset (rx_device_cfg_lmfc_offset), + .device_cfg_sysref_oneshot (rx_device_cfg_sysref_oneshot), + .device_cfg_sysref_disable (rx_device_cfg_sysref_disable), + .device_cfg_buffer_delay (rx_device_cfg_buffer_delay), + .device_cfg_buffer_early_release (rx_device_cfg_buffer_early_release) + ); + + + jesd204_rx #( + .NUM_LANES (NUM_LANES), + .LINK_MODE (2), + .ENABLE_FEC (1) + ) jesd204_rx ( + .clk (clk), + .reset (rst), + .device_clk (clk), + .device_reset (rst), + .phy_data (rx_phy_data), + .phy_header (rx_phy_header), + .phy_charisk ('0), + .phy_notintable ('0), + .phy_disperr ('0), + .phy_block_sync ('1), + .sysref (sysref), + .lmfc_edge (rx_lmfc_edge), + .lmfc_clk (rx_lmfc_clk), + .device_event_sysref_alignment_error (), + .device_event_sysref_edge (), + .event_frame_alignment_error (), + .event_unexpected_lane_state_error (), + .sync (), + .phy_en_char_align (), + .rx_data (rx_data), + .rx_valid (rx_valid), + .rx_eof (rx_eof), + .rx_sof (rx_sof), + .rx_eomf (rx_eomf), + .rx_somf (rx_somf), + .cfg_lanes_disable (rx_cfg_lanes_disable), + .cfg_links_disable (rx_cfg_links_disable), + .cfg_octets_per_multiframe (rx_cfg_octets_per_multiframe), + .cfg_octets_per_frame (rx_cfg_octets_per_frame), + .device_cfg_octets_per_multiframe (rx_device_cfg_octets_per_multiframe), + .device_cfg_octets_per_frame (rx_device_cfg_octets_per_frame), + .device_cfg_beats_per_multiframe (rx_device_cfg_beats_per_multiframe), + .cfg_disable_scrambler (rx_cfg_disable_scrambler), + .cfg_disable_char_replacement (rx_cfg_disable_char_replacement), + .cfg_header_mode (rx_cfg_header_mode), + .cfg_frame_align_err_threshold (rx_cfg_frame_align_err_threshold), + .device_cfg_lmfc_offset (rx_device_cfg_lmfc_offset), + .device_cfg_sysref_disable (rx_device_cfg_sysref_disable), + .device_cfg_sysref_oneshot (rx_device_cfg_sysref_oneshot), + .device_cfg_buffer_early_release (rx_device_cfg_buffer_early_release), + .device_cfg_buffer_delay (rx_device_cfg_buffer_delay), + .ctrl_err_statistics_reset (rx_ctrl_err_statistics_reset), + .ctrl_err_statistics_mask (rx_ctrl_err_statistics_mask), + .status_err_statistics_cnt (rx_status_err_statistics_cnt), + .ilas_config_valid (), + .ilas_config_addr (), + .ilas_config_data (), + .status_ctrl_state (), + .status_lane_cgs_state (), + .status_lane_ifs_ready (), + .status_lane_latency (), + .status_lane_emb_state (), + .status_lane_frame_align_err_cnt () + ); + + +endmodule + +`default_nettype wire