766 lines
30 KiB
Systemverilog
766 lines
30 KiB
Systemverilog
|
|
// ============================================================================
|
||
|
|
// Top Module: ulink_rx
|
||
|
|
// Integrates training, descrambling, and frame reception, outputs 512-bit block writes to SRAM
|
||
|
|
// ============================================================================
|
||
|
|
module ulink_rx #(
|
||
|
|
parameter FIFO_DEPTH = 64, // Input FIFO depth
|
||
|
|
parameter [31:0] SCRAMBLER_SEED = 32'hFFFFFFFF // Fixed seed for descrambler (all lanes share)
|
||
|
|
)(
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n // Active-low reset
|
||
|
|
// 4-lane serial input
|
||
|
|
,input logic [3 :0] serial_in
|
||
|
|
// Training parameters
|
||
|
|
,input logic [19 :0] patn_count
|
||
|
|
,input logic [2 :0] tap_step
|
||
|
|
,input logic [2 :0] tap_adj_mask // Delay adjustment mask
|
||
|
|
,input logic [0 :0] tap_force // Delay force to tap_step
|
||
|
|
,input logic force_train
|
||
|
|
,input logic descram_en
|
||
|
|
,input logic always_on
|
||
|
|
,input logic prefilling
|
||
|
|
,output logic prefill_start
|
||
|
|
// Link status outputs
|
||
|
|
,output logic link_down
|
||
|
|
,output logic train_ready
|
||
|
|
,output logic [2 :0] delay_tap
|
||
|
|
,output logic tap_adj_req
|
||
|
|
// SRAM write interface (each block is 512 bits)
|
||
|
|
,output logic [12 :0] wr_addr
|
||
|
|
,output logic [511:0] wr_data
|
||
|
|
,output logic wr_en
|
||
|
|
,output logic [63 :0] byte_mask
|
||
|
|
// CRC error indication (can be used for external monitoring or to restart training)
|
||
|
|
,output logic crc_error
|
||
|
|
,output logic frame_done
|
||
|
|
,output logic [31 :0] train_status
|
||
|
|
,output logic [31 :0] frame_status
|
||
|
|
);
|
||
|
|
|
||
|
|
// Internal connection signals
|
||
|
|
//logic train_ready; // Training ready (not used, but can be exported)
|
||
|
|
logic data_valid; // Data valid pulse from training module
|
||
|
|
logic [127:0] data_int; // 128-bit data from training module
|
||
|
|
logic [127:0] descrambled_data; // Descrambled data
|
||
|
|
logic descrambled_valid; // Descrambled data valid
|
||
|
|
logic [0 :0] train_en; // Training enable
|
||
|
|
logic [3 :0] descram_valid;
|
||
|
|
|
||
|
|
// ========================================================================
|
||
|
|
// prefill module instantiation
|
||
|
|
// ========================================================================
|
||
|
|
prefill #(
|
||
|
|
.DELAY ( 20'd10000 )
|
||
|
|
) U_prefill (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst_n ( rst_n )
|
||
|
|
,.always_on ( always_on )
|
||
|
|
,.prefilling ( prefilling )
|
||
|
|
,.prefill_start ( prefill_start )
|
||
|
|
,.prefill_done ( train_en )
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
// ========================================================================
|
||
|
|
// Training module instantiation
|
||
|
|
// ========================================================================
|
||
|
|
ulink_rx_train u_train (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst_n ( rst_n )
|
||
|
|
,.serial_in ( serial_in )
|
||
|
|
,.patn_count ( patn_count )
|
||
|
|
,.frame_error ( crc_error ) // Frame error feedback to restart training
|
||
|
|
,.frame_done ( frame_done )
|
||
|
|
,.tap_step ( tap_step )
|
||
|
|
,.tap_adj_mask ( tap_adj_mask )
|
||
|
|
,.tap_force ( tap_force )
|
||
|
|
,.force_train ( force_train )
|
||
|
|
,.train_en ( train_en )
|
||
|
|
,.link_down ( link_down )
|
||
|
|
,.delay_tap ( delay_tap )
|
||
|
|
,.tap_adj_req ( tap_adj_req )
|
||
|
|
,.train_ready ( train_ready )
|
||
|
|
,.descram_valid ( descram_valid )
|
||
|
|
,.data_valid ( data_valid )
|
||
|
|
,.data_out ( data_int )
|
||
|
|
,.train_status ( train_status )
|
||
|
|
);
|
||
|
|
|
||
|
|
|
||
|
|
// ========================================================================
|
||
|
|
// Descrambler module instantiation (128-bit, all lanes share the same seed)
|
||
|
|
// ========================================================================
|
||
|
|
ulink_descrambler_128 #(
|
||
|
|
.SEED ( SCRAMBLER_SEED )
|
||
|
|
) u_descrambler (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst_n ( rst_n )
|
||
|
|
,.data_in ( data_int )
|
||
|
|
,.valid_in ( descram_valid )
|
||
|
|
,.enable ( descram_en ) // Always enable descrambling
|
||
|
|
,.data_out ( descrambled_data )
|
||
|
|
,.valid_out ( descrambled_valid )
|
||
|
|
);
|
||
|
|
|
||
|
|
// ========================================================================
|
||
|
|
// Frame receiver module instantiation
|
||
|
|
// ========================================================================
|
||
|
|
ulink_frame_receiver #(
|
||
|
|
.FIFO_DEPTH ( FIFO_DEPTH )
|
||
|
|
) u_frame (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst_n ( rst_n )
|
||
|
|
,.data_in ( descrambled_data )
|
||
|
|
,.valid_in ( descrambled_valid )
|
||
|
|
,.wr_addr ( wr_addr )
|
||
|
|
,.wr_data ( wr_data )
|
||
|
|
,.wr_en ( wr_en )
|
||
|
|
,.byte_mask ( byte_mask )
|
||
|
|
,.crc_error ( crc_error )
|
||
|
|
,.frame_done ( frame_done )
|
||
|
|
,.frame_status ( frame_status )
|
||
|
|
);
|
||
|
|
|
||
|
|
endmodule
|
||
|
|
|
||
|
|
|
||
|
|
// ============================================================================
|
||
|
|
// Sub-module definitions (can be placed in separate files as needed)
|
||
|
|
// ============================================================================
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// 32-bit Descrambler (used inside the 128-bit descrambler)
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
module ulink_descrambler_32 #(
|
||
|
|
parameter [31:0] SEED = 32'hFFFFFFFF
|
||
|
|
) (
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic [31:0] data_in
|
||
|
|
,input logic valid_in
|
||
|
|
,input logic enable
|
||
|
|
,output logic [31:0] data_out
|
||
|
|
,output logic valid_out
|
||
|
|
);
|
||
|
|
logic [31:0] lfsr, next_lfsr;
|
||
|
|
wire feedback = lfsr[31] ^ lfsr[30] ^ lfsr[29] ^ lfsr[28];
|
||
|
|
assign next_lfsr = {lfsr[30:0], feedback};
|
||
|
|
|
||
|
|
always_ff @(posedge clk or negedge rst_n) begin
|
||
|
|
if (!rst_n)
|
||
|
|
lfsr <= SEED;
|
||
|
|
else if (valid_in && enable)
|
||
|
|
lfsr <= next_lfsr;
|
||
|
|
end
|
||
|
|
|
||
|
|
logic [31:0] descrambled;
|
||
|
|
assign descrambled = valid_in && enable ? (data_in ^ lfsr) : data_in;
|
||
|
|
|
||
|
|
always_ff @(posedge clk or negedge rst_n) begin
|
||
|
|
if (!rst_n) begin
|
||
|
|
data_out <= 32'h0;
|
||
|
|
valid_out <= 1'b0;
|
||
|
|
end else begin
|
||
|
|
data_out <= descrambled;
|
||
|
|
valid_out <= valid_in;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
endmodule
|
||
|
|
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// 128-bit Descrambler (composed of four 32-bit descramblers)
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
module ulink_descrambler_128 #(
|
||
|
|
parameter [31:0] SEED = 32'hFFFFFFFF
|
||
|
|
) (
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic [127:0] data_in
|
||
|
|
,input logic [3 :0] valid_in
|
||
|
|
,input logic enable
|
||
|
|
,output logic [127:0] data_out
|
||
|
|
,output logic valid_out
|
||
|
|
);
|
||
|
|
logic [31:0] lane0_out, lane1_out, lane2_out, lane3_out;
|
||
|
|
logic valid_out0, valid_out1, valid_out2, valid_out3;
|
||
|
|
|
||
|
|
ulink_descrambler_32 #(.SEED(SEED)) u0 (
|
||
|
|
.clk (clk),
|
||
|
|
.rst_n (rst_n),
|
||
|
|
.data_in (data_in[31:0]),
|
||
|
|
.valid_in (valid_in[0]),
|
||
|
|
.enable (enable),
|
||
|
|
.data_out (lane0_out),
|
||
|
|
.valid_out(valid_out0)
|
||
|
|
);
|
||
|
|
ulink_descrambler_32 #(.SEED(SEED)) u1 (
|
||
|
|
.clk (clk),
|
||
|
|
.rst_n (rst_n),
|
||
|
|
.data_in (data_in[63:32]),
|
||
|
|
.valid_in (valid_in[1]),
|
||
|
|
.enable (enable),
|
||
|
|
.data_out (lane1_out),
|
||
|
|
.valid_out(valid_out1)
|
||
|
|
);
|
||
|
|
ulink_descrambler_32 #(.SEED(SEED)) u2 (
|
||
|
|
.clk (clk),
|
||
|
|
.rst_n (rst_n),
|
||
|
|
.data_in (data_in[95:64]),
|
||
|
|
.valid_in (valid_in[2]),
|
||
|
|
.enable (enable),
|
||
|
|
.data_out (lane2_out),
|
||
|
|
.valid_out(valid_out2)
|
||
|
|
);
|
||
|
|
ulink_descrambler_32 #(.SEED(SEED)) u3 (
|
||
|
|
.clk (clk),
|
||
|
|
.rst_n (rst_n),
|
||
|
|
.data_in (data_in[127:96]),
|
||
|
|
.valid_in (valid_in[3]),
|
||
|
|
.enable (enable),
|
||
|
|
.data_out (lane3_out),
|
||
|
|
.valid_out(valid_out3)
|
||
|
|
);
|
||
|
|
|
||
|
|
assign data_out = {lane3_out, lane2_out, lane1_out, lane0_out};
|
||
|
|
assign valid_out = valid_out1; // All lanes are synchronized
|
||
|
|
endmodule
|
||
|
|
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// CRC32 Module (used in frame receiver)
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
module crc32 #(
|
||
|
|
parameter POLY = 32'h04C11DB7
|
||
|
|
,parameter INIT = 32'hFFFFFFFF
|
||
|
|
)(
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic clear
|
||
|
|
,input logic [31:0] data
|
||
|
|
,input logic valid
|
||
|
|
,output logic [31:0] crc
|
||
|
|
);
|
||
|
|
logic [31:0] crc_reg, crc_next;
|
||
|
|
integer i;
|
||
|
|
logic data_bit;
|
||
|
|
|
||
|
|
always_ff @(posedge clk or negedge rst_n) begin
|
||
|
|
if (!rst_n)
|
||
|
|
crc_reg <= INIT;
|
||
|
|
else if (clear)
|
||
|
|
crc_reg <= INIT;
|
||
|
|
else if (valid)
|
||
|
|
crc_reg <= crc_next;
|
||
|
|
end
|
||
|
|
|
||
|
|
always_comb begin
|
||
|
|
crc_next = crc_reg;
|
||
|
|
for (i = 0; i < 32; i++) begin
|
||
|
|
data_bit = crc_next[31] ^ data[31-i];
|
||
|
|
crc_next = {crc_next[30:0], 1'b0};
|
||
|
|
if (data_bit) crc_next = crc_next ^ POLY;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
assign crc = crc_reg;
|
||
|
|
endmodule
|
||
|
|
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// Frame Receiver Module (uses syn_fwft_fifo)
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
module ulink_frame_receiver #(
|
||
|
|
parameter FIFO_DEPTH = 64
|
||
|
|
)(
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic [127:0] data_in
|
||
|
|
,input logic valid_in
|
||
|
|
,output logic [12:0] wr_addr
|
||
|
|
,output logic [511:0] wr_data
|
||
|
|
,output logic wr_en
|
||
|
|
,output logic [63:0] byte_mask
|
||
|
|
,output logic [31:0] frame_status
|
||
|
|
,output logic crc_error
|
||
|
|
,output logic frame_done
|
||
|
|
);
|
||
|
|
// Frame header constant
|
||
|
|
localparam FRAME_HEADER = 32'hBCBCBCBC;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// FIFO instantiation
|
||
|
|
logic fifo_rd_en;
|
||
|
|
logic [127:0] fifo_dout;
|
||
|
|
logic fifo_empty;
|
||
|
|
|
||
|
|
//syn_fwft_fifo
|
||
|
|
syn_fwft_fifo #(
|
||
|
|
.width ( 128 )
|
||
|
|
,.depth ( FIFO_DEPTH )
|
||
|
|
) u_fifo (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst ( ~rst_n )
|
||
|
|
,.clr ( 1'b0 )
|
||
|
|
,.wr_en ( valid_in )
|
||
|
|
,.din ( data_in )
|
||
|
|
,.full ( )
|
||
|
|
,.almost_full ( )
|
||
|
|
,.prog_full ( )
|
||
|
|
,.rd_en (fifo_rd_en )
|
||
|
|
,.dout (fifo_dout )
|
||
|
|
,.empty (fifo_empty )
|
||
|
|
,.almost_empty ( )
|
||
|
|
,.prog_empty ( )
|
||
|
|
,.cnt ( )
|
||
|
|
);
|
||
|
|
|
||
|
|
// Split 128-bit data into four 32-bit words
|
||
|
|
typedef enum logic [2:0] { S_IDLE, S_WORD0, S_WORD1, S_WORD2, S_WORD3 } word_state_t;
|
||
|
|
word_state_t word_state_c, word_state_n;
|
||
|
|
|
||
|
|
// ------------------------------------------------------
|
||
|
|
// -- word state machine
|
||
|
|
// ------------------------------------------------------
|
||
|
|
|
||
|
|
//jump conditions
|
||
|
|
wire idle2word0 = (word_state_c == S_IDLE ) && !fifo_empty;
|
||
|
|
wire word02word1 = (word_state_c == S_WORD0 ) ;
|
||
|
|
wire word12word2 = (word_state_c == S_WORD1 ) ;
|
||
|
|
wire word22word3 = (word_state_c == S_WORD2 ) ;
|
||
|
|
wire word32idle = (word_state_c == S_WORD3 ) ;
|
||
|
|
|
||
|
|
|
||
|
|
//state_n
|
||
|
|
assign word_state_n = ((word_state_c == S_IDLE ) && idle2word0 ) ? S_WORD0 :
|
||
|
|
((word_state_c == S_WORD0 ) && word02word1 ) ? S_WORD1 :
|
||
|
|
((word_state_c == S_WORD1 ) && word12word2 ) ? S_WORD2 :
|
||
|
|
((word_state_c == S_WORD2 ) && word22word3 ) ? S_WORD3 :
|
||
|
|
((word_state_c == S_WORD3 ) && word32idle ) ? S_IDLE :
|
||
|
|
word_state_c ;
|
||
|
|
//word_state_c
|
||
|
|
sirv_gnrl_edffr #(.T(word_state_t)) word_state_c_dffr (word_state_n,word_state_c,clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
//fifo_rd_en
|
||
|
|
assign fifo_rd_en = idle2word0;
|
||
|
|
|
||
|
|
wire [127:0] current_fifo_data;
|
||
|
|
|
||
|
|
sirv_gnrl_dfflr #(128) current_fifo_data_dfflr (fifo_rd_en, fifo_dout, current_fifo_data, clk, rst_n);
|
||
|
|
|
||
|
|
wire [31:0] current_word_w = (word_state_c == S_WORD0) ? current_fifo_data[31:0] :
|
||
|
|
(word_state_c == S_WORD1) ? current_fifo_data[63:32] :
|
||
|
|
(word_state_c == S_WORD2) ? current_fifo_data[95:64] :
|
||
|
|
(word_state_c == S_WORD3) ? current_fifo_data[127:96] :
|
||
|
|
32'h0;
|
||
|
|
wire word_valid_w = (word_state_c != S_IDLE);
|
||
|
|
|
||
|
|
wire [31:0] current_word;
|
||
|
|
|
||
|
|
sirv_gnrl_dfflr #(32) current_word_dfflr (word_valid_w, current_word_w, current_word, clk, rst_n);
|
||
|
|
|
||
|
|
wire word_valid;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(1) word_valid_dffr (word_valid_w, word_valid, clk, rst_n);
|
||
|
|
|
||
|
|
// ------------------------------------------------------
|
||
|
|
// -- Frame parsing FSM
|
||
|
|
// ------------------------------------------------------
|
||
|
|
typedef enum logic [2:0] { ST_IDLE, ST_HEAD, ST_DATA, ST_CRC } state_t;
|
||
|
|
state_t state_c, state_n;
|
||
|
|
|
||
|
|
//data_len
|
||
|
|
wire [15:0] data_len;
|
||
|
|
sirv_gnrl_dfflr #(16) data_len_dfflr ((state_c == ST_HEAD ), current_word[15:0], data_len, clk, rst_n);
|
||
|
|
//data_cnt contrl
|
||
|
|
wire [15:0] data_cnt;
|
||
|
|
wire add_data_cnt = (state_c == ST_DATA ) && word_valid;
|
||
|
|
wire end_data_cnt = add_data_cnt && (state_c == ST_DATA ) && (data_cnt == data_len -1);
|
||
|
|
|
||
|
|
wire [15:0] data_cnt_n = end_data_cnt ? 5'h0 :
|
||
|
|
add_data_cnt ? data_cnt + 1'b1 :
|
||
|
|
data_cnt ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(16) data_cnt_dffr (data_cnt_n, data_cnt, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
//jump conditions
|
||
|
|
wire idle2head = (state_c == ST_IDLE ) && (word_valid && current_word == FRAME_HEADER);
|
||
|
|
wire head2data = (state_c == ST_HEAD ) && word_valid;
|
||
|
|
wire data2crc = (state_c == ST_DATA ) && end_data_cnt;
|
||
|
|
wire crc2idle = (state_c == ST_CRC ) && word_valid;
|
||
|
|
|
||
|
|
//state_n
|
||
|
|
assign state_n = ((state_c == ST_IDLE ) && idle2head ) ? ST_HEAD :
|
||
|
|
((state_c == ST_HEAD ) && head2data ) ? ST_DATA :
|
||
|
|
((state_c == ST_DATA ) && data2crc ) ? ST_CRC :
|
||
|
|
((state_c == ST_CRC ) && crc2idle ) ? ST_IDLE :
|
||
|
|
state_c ;
|
||
|
|
//state_c
|
||
|
|
sirv_gnrl_edffr #(.T(state_t)) state_c_dffr (state_n,state_c,clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
//cur_block_offset
|
||
|
|
wire [3:0] cur_block_offset;
|
||
|
|
|
||
|
|
wire add_cur_block_offset = (state_c == ST_DATA ) && word_valid;
|
||
|
|
wire end_cur_block_offset = (state_c == ST_DATA ) && add_cur_block_offset && (cur_block_offset == 16-1);;
|
||
|
|
|
||
|
|
wire [3:0] cur_block_offset_n = end_cur_block_offset ? 5'h0 :
|
||
|
|
(state_c == ST_HEAD ) ? current_word[19:16] :
|
||
|
|
add_cur_block_offset ? cur_block_offset + 1'b1 :
|
||
|
|
cur_block_offset ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(4) cur_block_offset_dffr (cur_block_offset_n, cur_block_offset, clk, rst_n);
|
||
|
|
|
||
|
|
//block_done
|
||
|
|
wire block_done;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(1) block_done_dffr ((state_c == ST_DATA) && ((end_data_cnt && !end_cur_block_offset) || end_cur_block_offset), block_done, clk, rst_n);
|
||
|
|
|
||
|
|
//base_addr
|
||
|
|
wire [15:0] base_addr;
|
||
|
|
sirv_gnrl_dfflr #(16) base_addr_dfflr ((state_c == ST_HEAD ), current_word[31:16], base_addr, clk, rst_n);
|
||
|
|
|
||
|
|
//cur_block_addr
|
||
|
|
wire [12:0] cur_block_addr;
|
||
|
|
wire [12:0] cur_block_addr_w = end_cur_block_offset ? cur_block_addr + 1'b1 :
|
||
|
|
(state_c == ST_HEAD) ? current_word[31:16] >> 4 :
|
||
|
|
crc2idle ? 13'd0 :
|
||
|
|
cur_block_addr;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(13) cur_block_addr_dffr (cur_block_addr_w, cur_block_addr, clk, rst_n);
|
||
|
|
|
||
|
|
//cur_block_data
|
||
|
|
wire [31:0] cur_block_data [15:0];
|
||
|
|
|
||
|
|
|
||
|
|
genvar i;
|
||
|
|
generate
|
||
|
|
for (i = 0; i < 16; i++) begin : gen_block_data
|
||
|
|
wire load_sel = (state_c == ST_DATA) && (cur_block_offset == i);
|
||
|
|
sirv_gnrl_dfflr #(32) cur_block_data_dfflr (load_sel, current_word, cur_block_data[i], clk, rst_n);
|
||
|
|
end
|
||
|
|
endgenerate
|
||
|
|
|
||
|
|
|
||
|
|
//cur_block_mask
|
||
|
|
wire [63:0] cur_block_mask;
|
||
|
|
|
||
|
|
wire clear_mask = (state_c == ST_HEAD) || block_done;
|
||
|
|
|
||
|
|
genvar j;
|
||
|
|
generate
|
||
|
|
for (j = 0; j < 16; j++) begin : gen_mask
|
||
|
|
wire load_sel_mask = (state_c == ST_DATA) && (cur_block_offset == j);
|
||
|
|
wire load_en = load_sel_mask || clear_mask;
|
||
|
|
wire [3:0] dnxt = load_sel_mask ? 4'b1111 :
|
||
|
|
clear_mask ? 4'b0000 :
|
||
|
|
4'b1111;
|
||
|
|
sirv_gnrl_dfflr #(4) cur_block_mask_dfflr (load_en, dnxt, cur_block_mask[j*4 +: 4], clk, rst_n);
|
||
|
|
end
|
||
|
|
endgenerate
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
//SRAM Write Ouput Contrl
|
||
|
|
|
||
|
|
//wr_addr
|
||
|
|
wire [12:0] cur_block_addr_r;
|
||
|
|
sirv_gnrl_dffr #(13) cur_block_addr_r_dffr (cur_block_addr, cur_block_addr_r, clk, rst_n);
|
||
|
|
sirv_gnrl_dfflr #(13) wr_addr_dfflr (block_done, cur_block_addr_r, wr_addr, clk, rst_n);
|
||
|
|
|
||
|
|
//wr_data
|
||
|
|
wire [511:0] cur_block_data_packed;
|
||
|
|
genvar k;
|
||
|
|
generate
|
||
|
|
for (k = 0; k < 16; k++) begin : pack_cur_block_data
|
||
|
|
assign cur_block_data_packed[32*k +: 32] = cur_block_data[k];
|
||
|
|
end
|
||
|
|
endgenerate
|
||
|
|
|
||
|
|
sirv_gnrl_dfflr #(512) wr_data_dfflr (block_done, cur_block_data_packed, wr_data, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
//byte_mask
|
||
|
|
sirv_gnrl_dfflr #(64) byte_mask_dfflr (block_done, cur_block_mask, byte_mask, clk, rst_n);
|
||
|
|
|
||
|
|
//wr_en
|
||
|
|
sirv_gnrl_dffr #(1) wr_en_dffr (block_done, wr_en, clk, rst_n);
|
||
|
|
|
||
|
|
//frame_done
|
||
|
|
sirv_gnrl_dffr #(1) frame_done_dffr (crc2idle, frame_done, clk, rst_n);
|
||
|
|
|
||
|
|
// ------------------------------------------------------
|
||
|
|
// -- CRC32 instance
|
||
|
|
// ------------------------------------------------------
|
||
|
|
wire crc_clear, crc_valid;
|
||
|
|
wire [31:0] crc_out;
|
||
|
|
crc32 u_crc32 (
|
||
|
|
.clk ( clk )
|
||
|
|
,.rst_n ( rst_n )
|
||
|
|
,.clear ( crc_clear )
|
||
|
|
,.data ( current_word )
|
||
|
|
,.valid ( crc_valid )
|
||
|
|
,.crc ( crc_out )
|
||
|
|
);
|
||
|
|
|
||
|
|
//CRC Contrl
|
||
|
|
|
||
|
|
//crc_clear
|
||
|
|
sirv_gnrl_dffr #(1) crc_clear_dffr (crc2idle, crc_clear, clk, rst_n);
|
||
|
|
|
||
|
|
//crc_valid
|
||
|
|
//sirv_gnrl_dffr #(1) crc_valid_dffr ((state_c == ST_HEAD) || (state_c == ST_DATA) && word_valid, crc_valid, clk, rst_n);
|
||
|
|
assign crc_valid = (state_c == ST_HEAD) || (state_c == ST_DATA) && word_valid;
|
||
|
|
//crc_error
|
||
|
|
sirv_gnrl_dffr #(1) crc_error_dffr (crc2idle && (current_word != crc_out), crc_error, clk, rst_n);
|
||
|
|
|
||
|
|
wire [31:0] frame_status_w;
|
||
|
|
|
||
|
|
assign frame_status_w[2 : 0] = state_c;
|
||
|
|
assign frame_status_w[15: 3] = base_addr[15:3];
|
||
|
|
assign frame_status_w[31:16] = data_len;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(32) frame_status_dffr (frame_status_w, frame_status, clk, rst_n);
|
||
|
|
endmodule
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// Training module (provided in user's file, placeholder here)
|
||
|
|
// Note: To avoid duplication, the definition of ulink_rx_train is omitted.
|
||
|
|
// In actual use, include the original file content here or via `include.
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// Assume ulink_rx_train module exists, identical to the user-provided code.
|
||
|
|
|
||
|
|
module ulink_rx_train (
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic [3 :0] serial_in // 4-lane serial input
|
||
|
|
,input logic [19 :0] patn_count // Training count preset value
|
||
|
|
,input logic frame_error // Frame error indication (from frame module)
|
||
|
|
,input logic frame_done // Frame done indication (from frame module)
|
||
|
|
,input logic [2 :0] tap_step // Delay adjustment step value
|
||
|
|
,input logic [2 :0] tap_adj_mask // Delay adjustment mask
|
||
|
|
,input logic [0 :0] tap_force // Delay force to tap_step
|
||
|
|
,input logic force_train // Force Training
|
||
|
|
,input logic [0 :0] train_en // Training enable
|
||
|
|
,output logic link_down // Link down indication
|
||
|
|
,output logic [2 :0] delay_tap // Delay adjustment value
|
||
|
|
,output logic tap_adj_req
|
||
|
|
,output logic train_ready // Training complete, link ready
|
||
|
|
,output logic [127:0] data_out // Latched parallel data
|
||
|
|
,output logic data_valid
|
||
|
|
,output logic [3 :0] descram_valid
|
||
|
|
,output logic [31 :0] train_status
|
||
|
|
);
|
||
|
|
|
||
|
|
// 4 32-bit shift registers, corresponding to 4 input lanes
|
||
|
|
wire [31:0] lane0_reg, lane1_reg, lane2_reg, lane3_reg;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(32) lane0_reg_dffr ({lane0_reg[30:0], serial_in[0]}, lane0_reg, clk, rst_n);
|
||
|
|
sirv_gnrl_dffr #(32) lane1_reg_dffr ({lane1_reg[30:0], serial_in[1]}, lane1_reg, clk, rst_n);
|
||
|
|
sirv_gnrl_dffr #(32) lane2_reg_dffr ({lane2_reg[30:0], serial_in[2]}, lane2_reg, clk, rst_n);
|
||
|
|
sirv_gnrl_dffr #(32) lane3_reg_dffr ({lane3_reg[30:0], serial_in[3]}, lane3_reg, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
// State definition
|
||
|
|
typedef enum logic [1:0] {
|
||
|
|
SM_DOWN, // Link down
|
||
|
|
SM_MATCH, // Match training pattern
|
||
|
|
SM_EXIT, // Wait for exit pattern
|
||
|
|
SM_READY // Link ready
|
||
|
|
} state_t;
|
||
|
|
|
||
|
|
state_t state_c, state_n;
|
||
|
|
|
||
|
|
localparam TRAINING_PATN = 32'h68666E6C; // "hfnl"
|
||
|
|
localparam TRAINING_EXIT = 32'h65786974; // "exit"
|
||
|
|
|
||
|
|
// Bit counter control
|
||
|
|
wire [4:0] bit_counter;
|
||
|
|
|
||
|
|
wire add_bit_conuter = ((state_c == SM_MATCH) || (state_c == SM_EXIT));
|
||
|
|
wire end_bit_conuter = add_bit_conuter && (bit_counter == 32-1);
|
||
|
|
|
||
|
|
wire [4:0] counter_m1 = end_bit_conuter ? 5'h0 :
|
||
|
|
add_bit_conuter ? bit_counter + 1'b1 :
|
||
|
|
bit_counter ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(5) bit_counter_dffr (counter_m1, bit_counter, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
// Combinational signals: all four lanes match simultaneously
|
||
|
|
wire match_en = (lane0_reg == TRAINING_PATN) &&
|
||
|
|
(lane1_reg == TRAINING_PATN) &&
|
||
|
|
(lane2_reg == TRAINING_PATN) &&
|
||
|
|
(lane3_reg == TRAINING_PATN);
|
||
|
|
wire match_exit = (lane0_reg == TRAINING_EXIT) &&
|
||
|
|
(lane1_reg == TRAINING_EXIT) &&
|
||
|
|
(lane2_reg == TRAINING_EXIT) &&
|
||
|
|
(lane3_reg == TRAINING_EXIT);
|
||
|
|
wire match_failed = !(match_en | match_exit) & end_bit_conuter;
|
||
|
|
|
||
|
|
// Match counter
|
||
|
|
wire [19:0] match_counter_c;
|
||
|
|
|
||
|
|
|
||
|
|
wire add_match_counter = (state_c == SM_MATCH) && end_bit_conuter;
|
||
|
|
|
||
|
|
wire end_match_counter = add_match_counter && (match_counter_c == patn_count-2);
|
||
|
|
|
||
|
|
wire [19:0] match_counter_n = end_match_counter ? 20'h0 :
|
||
|
|
add_match_counter ? match_counter_c + 1'b1 :
|
||
|
|
match_counter_c ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(20) match_counter_c_dffr (match_counter_n, match_counter_c, clk, rst_n);
|
||
|
|
// ------------------------------------------------------
|
||
|
|
// -- state machine
|
||
|
|
// ------------------------------------------------------
|
||
|
|
|
||
|
|
//jump conditions
|
||
|
|
wire down2match = (state_c == SM_DOWN ) && match_en && train_en;
|
||
|
|
wire match2down = (state_c == SM_MATCH ) && match_failed;
|
||
|
|
wire match2exit = (state_c == SM_MATCH ) && end_match_counter;
|
||
|
|
wire exit2down = (state_c == SM_EXIT ) && match_failed;
|
||
|
|
wire exit2ready = (state_c == SM_EXIT ) && match_exit;
|
||
|
|
wire ready2down = (state_c == SM_READY ) && frame_error;
|
||
|
|
|
||
|
|
|
||
|
|
//state_n
|
||
|
|
assign state_n = ((state_c == SM_DOWN ) && down2match ) ? SM_MATCH :
|
||
|
|
((state_c == SM_MATCH ) && (match2down || force_train )) ? SM_DOWN :
|
||
|
|
((state_c == SM_MATCH ) && match2exit ) ? SM_EXIT :
|
||
|
|
((state_c == SM_EXIT ) && (exit2down || force_train )) ? SM_DOWN :
|
||
|
|
((state_c == SM_EXIT ) && exit2ready ) ? SM_READY :
|
||
|
|
((state_c == SM_READY ) && (ready2down || force_train )) ? SM_DOWN :
|
||
|
|
state_c ;
|
||
|
|
//state_c
|
||
|
|
sirv_gnrl_edffr #(.T(state_t)) state_c_dffr (state_n,state_c,clk, rst_n);
|
||
|
|
// Delay adjustment (step controlled by tap_step)
|
||
|
|
|
||
|
|
wire tap_adj_req_w = (tap_adj_mask[0] && match2down) ||
|
||
|
|
(tap_adj_mask[1] && exit2down ) ||
|
||
|
|
(tap_adj_mask[2] && ready2down) ;
|
||
|
|
|
||
|
|
wire tap_adj_enable = tap_adj_req_w || tap_force;
|
||
|
|
|
||
|
|
wire [2:0] delay_tap_w = tap_force ? tap_step :
|
||
|
|
delay_tap + tap_step ;
|
||
|
|
|
||
|
|
sirv_gnrl_dfflr #(3) delay_tap_dfflr (tap_adj_enable, delay_tap_w, delay_tap, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(1) tap_adj_req_dffr (tap_adj_req_w, tap_adj_req, clk, rst_n);
|
||
|
|
|
||
|
|
// Link status outputs
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(1) link_down_dffr ((state_c == SM_DOWN), link_down, clk, rst_n);
|
||
|
|
sirv_gnrl_dffr #(1) train_ready_dffr ((state_c == SM_READY), train_ready, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
// ======================
|
||
|
|
// Data output
|
||
|
|
// ======================
|
||
|
|
wire [127:0] data_buf;
|
||
|
|
sirv_gnrl_dffr #(128) data_buf_dffr ({lane3_reg, lane2_reg, lane1_reg, lane0_reg}, data_buf, clk, rst_n);
|
||
|
|
|
||
|
|
// Frame header constant
|
||
|
|
localparam FRAME_HEADER = 32'hBCBCBCBC;
|
||
|
|
|
||
|
|
// ==============================================================================================================
|
||
|
|
// Data input control: In SM_READY state, latch data every 32 cycles and generate a valid pulse
|
||
|
|
// ==============================================================================================================
|
||
|
|
|
||
|
|
//match_head
|
||
|
|
wire match_head_start;
|
||
|
|
wire match_head = (data_buf[31:0] == FRAME_HEADER);
|
||
|
|
wire match_head_start_w = match_head && train_ready ? 1'b1 :
|
||
|
|
link_down ? 1'b0 :
|
||
|
|
frame_done ? 1'b0 :
|
||
|
|
match_head_start;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(1) match_head_start_dffr (match_head_start_w, match_head_start, clk, rst_n);
|
||
|
|
// data counter control
|
||
|
|
wire [4:0] data_counter;
|
||
|
|
|
||
|
|
wire add_data_conuter = match_head_start;
|
||
|
|
wire end_data_conuter = (add_data_conuter && (data_counter == 32-1) || frame_done);
|
||
|
|
|
||
|
|
wire [4:0] data_counter_n = end_data_conuter ? 5'h0 :
|
||
|
|
add_data_conuter ? data_counter + 1'b1 :
|
||
|
|
data_counter ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(5) data_counter_dffr (data_counter_n, data_counter, clk, rst_n);
|
||
|
|
|
||
|
|
//valid_int
|
||
|
|
wire data_valid_w = (state_c == SM_READY) && (match_head || (end_data_conuter && (data_counter == 32-1)));
|
||
|
|
sirv_gnrl_dffr #(1) valid_int_dffr (data_valid_w, data_valid, clk, rst_n);
|
||
|
|
|
||
|
|
//descram_valid
|
||
|
|
wire [3:0] descram_valid_w;
|
||
|
|
assign descram_valid_w[3:1] = {3{data_valid_w}};
|
||
|
|
assign descram_valid_w[0] = (state_c == SM_READY) && (end_data_conuter && (data_counter == 32-1));
|
||
|
|
sirv_gnrl_dffr #(4) descram_valid_dffr (descram_valid_w, descram_valid, clk, rst_n);
|
||
|
|
|
||
|
|
//data_in reg
|
||
|
|
wire data_in_reg;
|
||
|
|
sirv_gnrl_dffr #(128) data_in_reg_dffr (data_buf, data_out, clk, rst_n);
|
||
|
|
|
||
|
|
//train_status
|
||
|
|
wire [31:0] train_status_w;
|
||
|
|
|
||
|
|
assign train_status_w[1 : 0] = state_c;
|
||
|
|
assign train_status_w[2 ] = match_en;
|
||
|
|
assign train_status_w[3 ] = match_exit;
|
||
|
|
assign train_status_w[4 ] = match_failed;
|
||
|
|
assign train_status_w[5 ] = match_head;
|
||
|
|
assign train_status_w[6 ] = match_head_start;
|
||
|
|
assign train_status_w[11: 7] = bit_counter;
|
||
|
|
assign train_status_w[31:12] = match_counter_c;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(32) train_status_dffr (train_status_w, train_status, clk, rst_n);
|
||
|
|
|
||
|
|
endmodule
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
// prefill Module (used in frame receiver)
|
||
|
|
// ----------------------------------------------------------------------------
|
||
|
|
module prefill #(
|
||
|
|
parameter DELAY = 20'd10000
|
||
|
|
)(
|
||
|
|
input logic clk
|
||
|
|
,input logic rst_n
|
||
|
|
,input logic always_on
|
||
|
|
,input logic prefilling
|
||
|
|
,output logic prefill_start
|
||
|
|
,output logic prefill_done
|
||
|
|
);
|
||
|
|
|
||
|
|
// delay counter control
|
||
|
|
wire [19:0] delay_counter;
|
||
|
|
|
||
|
|
wire add_delay_counter = ~(delay_counter == DELAY);
|
||
|
|
wire end_delay_counter = add_delay_counter && (delay_counter == DELAY-1);
|
||
|
|
|
||
|
|
wire [19:0] delay_counter_n = end_delay_counter ? 20'h0 :
|
||
|
|
add_delay_counter ? delay_counter + 1'b1 :
|
||
|
|
delay_counter ;
|
||
|
|
|
||
|
|
sirv_gnrl_dffr #(20) delay_counter_dffr (delay_counter_n, delay_counter, clk, rst_n);
|
||
|
|
|
||
|
|
//prefill_start
|
||
|
|
sirv_gnrl_dffr #(1) prefill_start_dffr (end_delay_counter, prefill_start, clk, rst_n);
|
||
|
|
|
||
|
|
//prefilling_falling
|
||
|
|
wire [1:0] prefilling_r;
|
||
|
|
sirv_gnrl_dffr #(2) prefilling_r_dffr ({prefilling_r[0],prefilling}, prefilling_r, clk, rst_n);
|
||
|
|
|
||
|
|
wire prefilling_falling = !prefilling_r[0] && prefilling_r[1];
|
||
|
|
//prefill_done
|
||
|
|
sirv_gnrl_dfflr #(1) prefill_done_dfflr (prefilling_falling || always_on, 1'b1, prefill_done, clk, rst_n);
|
||
|
|
|
||
|
|
|
||
|
|
endmodule
|
||
|
|
|