jesd204_rx: 64b mode support for receive peripheral

Instantiate 64B/66B decoder based on synthesis parameter.
main
Laszlo Nagy 2019-10-10 08:21:17 +01:00 committed by Laszlo Nagy
parent 075f703443
commit d1072847df
7 changed files with 868 additions and 42 deletions

View File

@ -14,8 +14,12 @@ GENERIC_DEPS += jesd204_rx_cgs.v
GENERIC_DEPS += jesd204_rx_ctrl.v
GENERIC_DEPS += jesd204_rx_lane.v
XILINX_DEPS += error_monitor.v
XILINX_DEPS += jesd204_rx_constr.ttcl
XILINX_DEPS += jesd204_rx_ctrl_64b.v
XILINX_DEPS += jesd204_rx_header.v
XILINX_DEPS += jesd204_rx_ip.tcl
XILINX_DEPS += jesd204_rx_lane_64b.v
XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_cfg.xml
XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_cfg_rtl.xml

View File

@ -0,0 +1,90 @@
//
// 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
// <http://www.gnu.org/licenses/>.
//
// 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
module error_monitor #(
parameter EVENT_WIDTH = 16,
parameter CNT_WIDTH = 32
) (
input clk,
input reset,
input active,
input [EVENT_WIDTH-1:0] error_event,
input [EVENT_WIDTH-1:0] error_event_mask,
output reg [CNT_WIDTH-1:0] status_err_cnt = 'h0
);
localparam EVENT_WIDTH_LOG = $clog2(EVENT_WIDTH);
reg [EVENT_WIDTH-1:0] err;
function [EVENT_WIDTH_LOG-1:0] num_set_bits;
input [EVENT_WIDTH-1:0] x;
integer j;
begin
num_set_bits = 0;
for (j = 0; j < EVENT_WIDTH; j = j + 1) begin
num_set_bits = num_set_bits + x[j];
end
end
endfunction
always @(posedge clk) begin
if (active == 1'b1) begin
err <= (~error_event_mask) & error_event;
end else begin
err <= {EVENT_WIDTH{1'b0}};
end
end
always @(posedge clk) begin
if (reset == 1'b1) begin
status_err_cnt <= 'h0;
end else if (~&status_err_cnt[CNT_WIDTH-1:EVENT_WIDTH_LOG]) begin
status_err_cnt <= status_err_cnt + num_set_bits(err);
end
end
endmodule

View File

@ -47,15 +47,20 @@
module jesd204_rx #(
parameter NUM_LANES = 1,
parameter NUM_LINKS = 1,
parameter NUM_INPUT_PIPELINE = 1
parameter NUM_INPUT_PIPELINE = 1,
parameter LINK_MODE = 1, // 2 - 64B/66B; 1 - 8B/10B
/* Only 4 is supported at the moment for 8b/10b and 8 for 64b */
parameter DATA_PATH_WIDTH = LINK_MODE == 2 ? 8 : 4
) (
input clk,
input reset,
input [32*NUM_LANES-1:0] phy_data,
input [4*NUM_LANES-1:0] phy_charisk,
input [4*NUM_LANES-1:0] phy_notintable,
input [4*NUM_LANES-1:0] phy_disperr,
input [DATA_PATH_WIDTH*8*NUM_LANES-1:0] phy_data,
input [2*NUM_LANES-1:0] phy_header,
input [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_charisk,
input [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_notintable,
input [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_disperr,
input [NUM_LANES-1:0] phy_block_sync,
input sysref,
output lmfc_edge,
@ -68,10 +73,10 @@ module jesd204_rx #(
output phy_en_char_align,
output [32*NUM_LANES-1:0] rx_data,
output [DATA_PATH_WIDTH*8*NUM_LANES-1:0] rx_data,
output rx_valid,
output [3:0] rx_eof,
output [3:0] rx_sof,
output [DATA_PATH_WIDTH-1:0] rx_eof,
output [DATA_PATH_WIDTH-1:0] rx_sof,
input [NUM_LANES-1:0] cfg_lanes_disable,
input [NUM_LINKS-1:0] cfg_links_disable,
@ -86,7 +91,7 @@ module jesd204_rx #(
input cfg_disable_scrambler,
input ctrl_err_statistics_reset,
input [2:0] ctrl_err_statistics_mask,
input [6:0] ctrl_err_statistics_mask,
output [32*NUM_LANES-1:0] status_err_statistics_cnt,
@ -97,7 +102,8 @@ module jesd204_rx #(
output [1:0] status_ctrl_state,
output [2*NUM_LANES-1:0] status_lane_cgs_state,
output [NUM_LANES-1:0] status_lane_ifs_ready,
output [14*NUM_LANES-1:0] status_lane_latency
output [14*NUM_LANES-1:0] status_lane_latency,
output [3*NUM_LANES-1:0] status_lane_emb_state
);
/*
@ -108,9 +114,6 @@ localparam CHAR_INFO_REGISTERED = 0;
localparam ALIGN_MUX_REGISTERED = 0;
localparam SCRAMBLER_REGISTERED = 0;
/* Only 4 is supported at the moment */
localparam DATA_PATH_WIDTH = 4;
/*
* Maximum number of octets per multiframe for ADI JESD204 DACs is 256 (Adjust
* as necessary). Divide by data path width.
@ -133,6 +136,7 @@ localparam LMFC_COUNTER_WIDTH = MAX_BEATS_PER_MULTIFRAME > 256 ? 9 :
/* Helper for common expressions */
localparam DW = 8*DATA_PATH_WIDTH*NUM_LANES;
localparam CW = DATA_PATH_WIDTH*NUM_LANES;
localparam HW = 2*NUM_LANES;
wire [NUM_LANES-1:0] cgs_reset;
wire [NUM_LANES-1:0] cgs_ready;
@ -141,13 +145,16 @@ wire [NUM_LANES-1:0] ifs_reset;
reg buffer_release_n = 1'b1;
reg buffer_release_d1 = 1'b0;
wire [NUM_LANES-1:0] buffer_ready_n;
wire all_buffer_ready_n;
reg eof_reset = 1'b1;
wire [DW-1:0] phy_data_r;
wire [HW-1:0] phy_header_r;
wire [CW-1:0] phy_charisk_r;
wire [CW-1:0] phy_notintable_r;
wire [CW-1:0] phy_disperr_r;
wire [NUM_LANES-1:0] phy_block_sync_r;
wire [DW-1:0] rx_data_s;
@ -170,12 +177,14 @@ always @(posedge clk) begin
end
end
assign all_buffer_ready_n = |(buffer_ready_n & ~cfg_lanes_disable);
always @(posedge clk) begin
if (reset == 1'b1) begin
buffer_release_n <= 1'b1;
end else begin
if (buffer_release_opportunity == 1'b1) begin
buffer_release_n <= |(buffer_ready_n & ~cfg_lanes_disable);
buffer_release_n <= all_buffer_ready_n;
end
end
buffer_release_d1 <= ~buffer_release_n;
@ -183,21 +192,25 @@ always @(posedge clk) begin
end
pipeline_stage #(
.WIDTH(3 * CW + DW),
.WIDTH(NUM_LANES + (3 * CW) + HW + DW),
.REGISTERED(NUM_INPUT_PIPELINE)
) i_input_pipeline_stage (
.clk(clk),
.in({
phy_data,
phy_header,
phy_charisk,
phy_notintable,
phy_disperr
phy_disperr,
phy_block_sync
}),
.out({
phy_data_r,
phy_header_r,
phy_charisk_r,
phy_notintable_r,
phy_disperr_r
phy_disperr_r,
phy_block_sync_r
})
);
@ -229,11 +242,36 @@ jesd204_lmfc i_lmfc (
.lmfc_edge(lmfc_edge),
.lmfc_clk(lmfc_clk),
.lmfc_counter(lmfc_counter),
.lmc_edge(),
.lmc_quarter_edge(),
.eoemb(),
.sysref_edge(event_sysref_edge),
.sysref_alignment_error(event_sysref_alignment_error)
);
jesd204_eof_generator #(
.DATA_PATH_WIDTH(DATA_PATH_WIDTH),
.MAX_OCTETS_PER_FRAME(MAX_OCTETS_PER_FRAME)
) i_eof_gen (
.clk(clk),
.reset(eof_reset),
.lmfc_edge(lmfc_edge),
.cfg_octets_per_frame(cfg_octets_per_frame),
.cfg_generate_eomf(1'b0),
.sof(rx_sof),
.eof(rx_eof),
.eomf()
);
generate
genvar i;
if (LINK_MODE[0] == 1) begin : mode_8b10b
jesd204_rx_ctrl #(
.NUM_LANES(NUM_LANES),
.NUM_LINKS(NUM_LINKS)
@ -260,25 +298,6 @@ jesd204_rx_ctrl #(
.status_state(status_ctrl_state)
);
jesd204_eof_generator #(
.DATA_PATH_WIDTH(DATA_PATH_WIDTH),
.MAX_OCTETS_PER_FRAME(MAX_OCTETS_PER_FRAME)
) i_eof_gen (
.clk(clk),
.reset(eof_reset),
.lmfc_edge(lmfc_edge),
.cfg_octets_per_frame(cfg_octets_per_frame),
.cfg_generate_eomf(1'b0),
.sof(rx_sof),
.eof(rx_eof),
.eomf()
);
genvar i;
generate
for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane
localparam D_START = i * DATA_PATH_WIDTH*8;
@ -314,7 +333,7 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane
.buffer_ready_n(buffer_ready_n[i]),
.ctrl_err_statistics_reset(ctrl_err_statistics_reset),
.ctrl_err_statistics_mask(ctrl_err_statistics_mask),
.ctrl_err_statistics_mask(ctrl_err_statistics_mask[2:0]),
.status_err_statistics_cnt(status_err_statistics_cnt[32*i+31:32*i]),
.ilas_config_valid(ilas_config_valid[i]),
@ -326,7 +345,6 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane
.status_frame_align(frame_align[2*i+1:2*i])
);
end
endgenerate
/* Delay matching based on the number of pipeline stages */
reg [NUM_LANES-1:0] ifs_ready_d1 = 1'b0;
@ -358,4 +376,88 @@ jesd204_lane_latency_monitor #(
.lane_latency(status_lane_latency)
);
end
if (LINK_MODE[1] == 1) begin : mode_64b66b
wire [NUM_LANES-1:0] emb_lock;
jesd204_rx_ctrl_64b #(
.NUM_LANES(NUM_LANES)
) i_jesd204_rx_ctrl_64b (
.clk(clk),
.reset(reset),
.cfg_lanes_disable(cfg_lanes_disable),
.phy_block_sync(phy_block_sync_r),
.emb_lock(emb_lock),
.all_emb_lock(all_emb_lock),
.buffer_release_n(buffer_release_n),
.status_state(status_ctrl_state)
);
for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane
localparam D_START = i * DATA_PATH_WIDTH*8;
localparam D_STOP = D_START + DATA_PATH_WIDTH*8-1;
localparam H_START = i * 2;
localparam H_STOP = H_START + 2-1;
wire [7:0] status_lane_skew;
jesd204_rx_lane_64b #(
.ELASTIC_BUFFER_SIZE(ELASTIC_BUFFER_SIZE)
) i_lane (
.clk(clk),
.reset(reset),
.phy_data(phy_data_r[D_STOP:D_START]),
.phy_header(phy_header_r[H_STOP:H_START]),
.phy_block_sync(phy_block_sync_r[i]),
.cfg_disable_scrambler(cfg_disable_scrambler),
.cfg_header_mode(2'b0),
.cfg_rx_thresh_emb_err(5'd8),
.cfg_beats_per_multiframe(cfg_beats_per_multiframe),
.rx_data(rx_data_s[D_STOP:D_START]),
.buffer_release_n(buffer_release_n),
.buffer_ready_n(buffer_ready_n[i]),
.all_buffer_ready_n(all_buffer_ready_n),
.lmfc_edge(lmfc_edge),
.emb_lock(emb_lock[i]),
.ctrl_err_statistics_reset(ctrl_err_statistics_reset),
.ctrl_err_statistics_mask(ctrl_err_statistics_mask[6: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]),
.status_lane_skew(status_lane_skew)
);
assign status_lane_latency[14*(i+1)-1:14*i] = {3'b0,status_lane_skew,3'b0};
end
// Assign unused outputs
assign sync = 'b0;
assign phy_en_char_align = 1'b0;
assign ilas_config_valid ='b0;
assign ilas_config_addr = 'b0;
assign ilas_config_data = 'b0;
assign status_lane_cgs_state = 'b0;
assign status_lane_ifs_ready = {NUM_LANES{1'b1}};
end
endgenerate
endmodule

View File

@ -0,0 +1,136 @@
//
// 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
// <http://www.gnu.org/licenses/>.
//
// 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
module jesd204_rx_ctrl_64b #(
parameter NUM_LANES = 1
) (
input clk,
input reset,
input [NUM_LANES-1:0] cfg_lanes_disable,
input [NUM_LANES-1:0] phy_block_sync,
input [NUM_LANES-1:0] emb_lock,
output all_emb_lock,
input buffer_release_n,
output [1:0] status_state
);
localparam STATE_RESET = 2'b00;
localparam STATE_WAIT_BS = 2'b01;
localparam STATE_BLOCK_SYNC = 2'b10;
localparam STATE_DATA = 2'b11;
reg [1:0] state = STATE_RESET;
reg [1:0] next_state;
reg [5:0] good_cnt;
reg rst_good_cnt;
wire [NUM_LANES-1:0] phy_block_sync_masked;
wire [NUM_LANES-1:0] emb_lock_masked;
wire all_block_sync;
assign phy_block_sync_masked = phy_block_sync | cfg_lanes_disable;
assign emb_lock_masked = emb_lock | 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;
case (state)
STATE_RESET:
next_state = STATE_WAIT_BS;
STATE_WAIT_BS:
if (all_block_sync) begin
rst_good_cnt = 1'b0;
if (&good_cnt) begin
next_state = STATE_BLOCK_SYNC;
end
end
STATE_BLOCK_SYNC:
if (~all_block_sync) begin
next_state = STATE_WAIT_BS;
end else if (all_emb_lock & ~buffer_release_n) begin
rst_good_cnt = 1'b0;
if (&good_cnt) begin
next_state = STATE_DATA;
end
end
STATE_DATA:
if (~all_block_sync) begin
next_state = STATE_WAIT_BS;
end else if (~all_emb_lock | buffer_release_n) begin
next_state = STATE_BLOCK_SYNC;
end
endcase
end
// Wait n consecutive valid cycles before jumping into next state
always @(posedge clk) begin
if (reset || rst_good_cnt) begin
good_cnt <= 'h0;
end else begin
good_cnt <= good_cnt + 1;
end
end
always @(posedge clk) begin
if (reset == 1'b1) begin
state <= STATE_RESET;
end else begin
state <= next_state;
end
end
assign status_state = state;
endmodule

View File

@ -0,0 +1,207 @@
//
// 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
// <http://www.gnu.org/licenses/>.
//
// 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
module jesd204_rx_header (
input clk,
input reset,
input sh_lock,
input [1:0] header,
input [1:0] cfg_header_mode, // 0 - CRC12 ; 1 - CRC3; 2 - FEC; 3 - CMD
input [4:0] cfg_rx_thresh_emb_err,
input [7:0] cfg_beats_per_multiframe,
output emb_lock,
output valid_eomb,
output valid_eoemb,
// Received header data qualified by valid_eomb
output [11:0] crc12,
output [2:0] crc3,
output [25:0] fec,
output [18:0] cmd,
output reg [7:0] sh_count = 'h0,
output [2:0] status_lane_emb_state,
output reg event_invalid_header,
output reg event_unexpected_eomb,
output reg event_unexpected_eoemb
);
localparam STATE_EMB_INIT = 3'b001;
localparam STATE_EMB_HUNT = 3'b010;
localparam STATE_EMB_LOCK = 3'b100;
localparam BIT_EMB_INIT = 0;
localparam BIT_EMB_HUNT = 1;
localparam BIT_EMB_LOCK = 2;
reg [2:0] state = STATE_EMB_INIT;
reg [2:0] next_state;
reg [31:0] sync_word = 'h0;
wire header_bit;
wire invalid_sequence;
wire invalid_eoemb;
wire invalid_eomb;
wire [6:0] cmd0;
wire [6:0] cmd1;
wire [18:0] cmd3;
wire eoemb;
wire eomb;
assign header_bit = header == 2'b01;
always @(posedge clk) begin
sync_word <= {sync_word[30:0],header_bit};
end
assign crc12 = {sync_word[31:29],sync_word[27:25],
sync_word[23:21],sync_word[19:17]};
assign crc3 = {sync_word[31:29]};
assign cmd0 = {sync_word[15:13],sync_word[11],
sync_word[7:5]};
assign cmd1 = {sync_word[27:25],
sync_word[19:17],
sync_word[11]};
assign cmd3 = {sync_word[31:29],sync_word[27:25],
sync_word[23:21],sync_word[19:17],
sync_word[15:13],sync_word[11],
sync_word[7:5]};
assign cmd = cfg_header_mode == 0 ? {12'b0,cmd0} :
cfg_header_mode == 1 ? {12'b0,cmd1} :
cfg_header_mode == 3 ? cmd3 : 'b0;
assign fec = {sync_word[31:10],sync_word[8:5]};
assign eomb = sync_word[4:0] == 5'b00001;
assign eoemb = sync_word[9] & eomb;
always @(posedge clk) begin
if (next_state[BIT_EMB_INIT] || sh_count == cfg_beats_per_multiframe) begin
sh_count <= 'h0;
end else begin
sh_count <= sh_count + 8'b1;
end
end
reg [1:0] emb_vcount = 'b0;
always @(posedge clk) begin
if (state[BIT_EMB_INIT]) begin
emb_vcount <= 'b0;
end else if (state[BIT_EMB_HUNT] && (sh_count == 0 && eoemb)) begin
emb_vcount <= emb_vcount + 'b1;
end
end
reg [4:0] emb_icount = 'b0;
always @(posedge clk) begin
if (state[BIT_EMB_INIT]) begin
emb_icount <= 'b0;
end else if (state[BIT_EMB_LOCK]) begin
if (sh_count == 0 && eoemb) begin
emb_icount <= 'b0;
end else if (invalid_eoemb || invalid_eomb) begin
emb_icount <= emb_icount + 5'b1;
end
end
end
always @(*) begin
next_state = state;
case (state)
STATE_EMB_INIT:
if (eoemb) begin
next_state = STATE_EMB_HUNT;
end
STATE_EMB_HUNT:
if (invalid_sequence) begin
next_state = STATE_EMB_INIT;
end else if (eoemb && emb_vcount == 2'd3) begin
next_state = STATE_EMB_LOCK;
end
STATE_EMB_LOCK:
if (emb_icount == cfg_rx_thresh_emb_err) begin
next_state = STATE_EMB_INIT;
end
endcase
if (sh_lock == 1'b0) next_state = STATE_EMB_INIT;
end
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 invalid_sequence = (invalid_eoemb || invalid_eomb);
always @(posedge clk) begin
if (reset == 1'b1) begin
state <= STATE_EMB_INIT;
end else begin
state <= next_state;
end
end
assign emb_lock = next_state[BIT_EMB_LOCK];
// Status & error events
assign status_lane_emb_state = state;
always @(posedge clk) begin
event_invalid_header <= (~state[BIT_EMB_INIT]) && (header[0] == header[1]);
event_unexpected_eomb <= (~state[BIT_EMB_INIT]) && (sh_count[4:0] != 0 && eomb);
event_unexpected_eoemb <= (~state[BIT_EMB_INIT]) && invalid_eoemb;
end
endmodule

View File

@ -48,9 +48,13 @@ source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
adi_ip_create jesd204_rx
adi_ip_files jesd204_rx [list \
"jesd204_rx_lane.v" \
"jesd204_rx_lane_64b.v" \
"jesd204_rx_header.v" \
"jesd204_rx_cgs.v" \
"jesd204_rx_ctrl.v" \
"jesd204_rx_ctrl_64b.v" \
"elastic_buffer.v" \
"error_monitor.v" \
"jesd204_ilas_monitor.v" \
"align_mux.v" \
"jesd204_lane_latency_monitor.v" \
@ -80,10 +84,12 @@ adi_add_multi_bus 16 "rx_phy" "slave" \
"xilinx.com:display_jesd204:jesd204_rx_bus_rtl:1.0" \
"xilinx.com:display_jesd204:jesd204_rx_bus:1.0" \
[list \
{"phy_data" "rxdata" 32} \
{ "phy_charisk" "rxcharisk" 4} \
{ "phy_disperr" "rxdisperr" 4} \
{ "phy_notintable" "rxnotintable" 4} \
{ "phy_data" "rxdata" 32 "(spirit:decode(id('MODELPARAM_VALUE.DATA_PATH_WIDTH')) * 8)"} \
{ "phy_charisk" "rxcharisk" 4 "(spirit:decode(id('MODELPARAM_VALUE.DATA_PATH_WIDTH')))"} \
{ "phy_disperr" "rxdisperr" 4 "(spirit:decode(id('MODELPARAM_VALUE.DATA_PATH_WIDTH')))"} \
{ "phy_notintable" "rxnotintable" 4 "(spirit:decode(id('MODELPARAM_VALUE.DATA_PATH_WIDTH')))"} \
{ "phy_header" "rxheader" 2} \
{ "phy_block_sync" "rxblock_sync" 1} \
] \
"(spirit:decode(id('MODELPARAM_VALUE.NUM_LANES')) > {i})"
@ -112,6 +118,7 @@ adi_add_bus "rx_status" "master" \
{ \
{ "status_ctrl_state" "ctrl_state" } \
{ "status_lane_cgs_state" "lane_cgs_state" } \
{ "status_lane_emb_state" "lane_emb_state" } \
{ "status_err_statistics_cnt" "err_statistics_cnt" } \
{ "status_lane_ifs_ready" "lane_ifs_ready" } \
{ "status_lane_latency" "lane_latency" } \
@ -136,9 +143,39 @@ adi_add_bus "rx_event" "master" \
adi_add_bus_clock "clk" "rx_cfg:rx_ilas_config:rx_event:rx_status:rx_data" "reset"
adi_set_bus_dependency "rx_ilas_config" "rx_ilas_config" \
"(spirit:decode(id('MODELPARAM_VALUE.LINK_MODE')) = 1)"
adi_set_ports_dependency "sync" \
"(spirit:decode(id('MODELPARAM_VALUE.LINK_MODE')) = 1)"
adi_set_ports_dependency "phy_en_char_align" \
"(spirit:decode(id('MODELPARAM_VALUE.LINK_MODE')) = 1)"
set cc [ipx::current_core]
set page0 [ipgui::get_pagespec -name "Page 0" -component $cc]
# Link layer mode
set p [ipgui::get_guiparamspec -name "LINK_MODE" -component $cc]
ipgui::move_param -component $cc -order 0 $p -parent $page0
set_property -dict [list \
"display_name" "Link Layer mode" \
"tooltip" "Link Layer mode" \
"widget" "comboBox" \
] $p
set_property -dict [list \
value_validation_type pairs \
value_validation_pairs {64B66B 2 8B10B 1} \
] [ipx::get_user_parameters $p -of_objects $cc]
# Data width selection
set param [ipx::get_user_parameters DATA_PATH_WIDTH -of_objects $cc]
set_property -dict [list \
enablement_value false \
value_tcl_expr {expr $LINK_MODE*4} \
] $param
set param [ipx::add_user_parameter SYSREF_IOB $cc]
set_property -dict {value_resolve_type user value_format bool value true} $param

View File

@ -0,0 +1,250 @@
//
// 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
// <http://www.gnu.org/licenses/>.
//
// 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
module jesd204_rx_lane_64b #(
parameter ELASTIC_BUFFER_SIZE = 256
) (
input clk,
input reset,
input [63:0] phy_data,
input [1:0] phy_header,
input phy_block_sync,
output [63:0] rx_data,
output reg buffer_ready_n = 'b1,
input all_buffer_ready_n,
input buffer_release_n,
input lmfc_edge,
output emb_lock,
input cfg_disable_scrambler,
input [1:0] cfg_header_mode, // 0 - CRC12 ; 1 - CRC3; 2 - FEC; 3 - CMD
input [4:0] cfg_rx_thresh_emb_err,
input [7:0] cfg_beats_per_multiframe,
input ctrl_err_statistics_reset,
input [3:0] ctrl_err_statistics_mask,
output [31:0] status_err_statistics_cnt,
output [2:0] status_lane_emb_state,
output reg [7:0] status_lane_skew
);
reg [11:0] crc12_calculated_prev;
wire [63:0] data_descrambled_s;
wire [63:0] data_descrambled;
wire [11:0] crc12_received;
wire [11:0] crc12_calculated;
wire event_invalid_header;
wire event_unexpected_eomb;
wire event_unexpected_eoemb;
wire event_crc12_mismatch;
wire err_cnt_rst;
wire [63:0] rx_data_msb_s;
wire eomb;
wire eoemb;
wire [7:0] sh_count;
jesd204_rx_header i_rx_header (
.clk(clk),
.reset(reset),
.sh_lock(phy_block_sync),
.header(phy_header),
.cfg_header_mode(cfg_header_mode),
.cfg_rx_thresh_emb_err(cfg_rx_thresh_emb_err),
.cfg_beats_per_multiframe(cfg_beats_per_multiframe),
.emb_lock(emb_lock),
.valid_eomb(eomb),
.valid_eoemb(eoemb),
.crc12(crc12_received),
.crc3(),
.fec(),
.cmd(),
.sh_count(sh_count),
.status_lane_emb_state(status_lane_emb_state),
.event_invalid_header(event_invalid_header),
.event_unexpected_eomb(event_unexpected_eomb),
.event_unexpected_eoemb(event_unexpected_eoemb)
);
jesd204_crc12 i_crc12 (
.clk(clk),
.reset(reset),
.init(eomb),
.data_in(phy_data),
.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
crc12_on <= 1'b1;
end
end
reg crc12_rdy = 'b0;
always @(posedge clk) begin
if (reset == 1'b1) begin
crc12_rdy <= 1'b0;
end else if (crc12_on && eomb) begin
crc12_rdy <= 1'b1;
end
end
always @(posedge clk) begin
if (eomb) begin
crc12_calculated_prev <= crc12_calculated;
end
end
assign event_crc12_mismatch = crc12_rdy && eomb && (crc12_calculated_prev != crc12_received);
assign err_cnt_rst = reset || ctrl_err_statistics_reset;
error_monitor #(
.EVENT_WIDTH(4),
.CNT_WIDTH(32)
) i_error_monitor (
.clk(clk),
.reset(err_cnt_rst),
.active(1'b1),
.error_event({
event_invalid_header,
event_unexpected_eomb,
event_unexpected_eoemb,
event_crc12_mismatch
}),
.error_event_mask(ctrl_err_statistics_mask),
.status_err_cnt(status_err_statistics_cnt)
);
jesd204_scrambler_64b #(
.WIDTH(64),
.DESCRAMBLE(1)
) i_descrambler (
.clk(clk),
.reset(reset),
.enable(~cfg_disable_scrambler),
.data_in(phy_data),
.data_out(data_descrambled_s)
);
pipeline_stage #(
.WIDTH(64),
.REGISTERED(1)
) i_pipeline_stage2 (
.clk(clk),
.in({
data_descrambled_s
}),
.out({
data_descrambled
})
);
// Control when data is written to the elastic buffer
// Start writing to the buffer when current lane is multiblock locked, but if
// other lanes are not writing in the next half multiblock period stop
// writing.
// This limits the supported lane skew to half of the multiframe
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_ready_n <= 1'b1;
end else if (eoemb) begin
buffer_ready_n <= 1'b0;
end
end
elastic_buffer #(
.WIDTH(64),
.SIZE(ELASTIC_BUFFER_SIZE)
) i_elastic_buffer (
.clk(clk),
.reset(reset),
.wr_data(data_descrambled),
.rd_data(rx_data_msb_s),
.ready_n(buffer_ready_n),
.do_release_n(buffer_release_n)
);
// Measure the delay from the eoemb to the next LMFC edge.
always @(posedge clk) begin
if (lmfc_edge) begin
status_lane_skew <= sh_count;
end
end
/* Reorder octets LSB first */
genvar i;
generate
for (i = 0; i < 64; i = i + 8) begin: g_link_data
assign rx_data[i+:8] = rx_data_msb_s[64-1-i-:8];
end
endgenerate
endmodule