Co-authored-by: Andrew Moch <Andrew.Moch@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com> Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com> Co-authored-by: Max Köhler <max.koehler@ni.com> Co-authored-by: Michael Auchter <michael.auchter@ni.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Wade Fife <wade.fife@ettus.com> Co-authored-by: Hector Rubio <hrubio@ni.com> Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
121 lines
3.5 KiB
Systemverilog
121 lines
3.5 KiB
Systemverilog
//
|
|
// Copyright 2021 Ettus Research, A National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: eth_100g_axi2lbus
|
|
//
|
|
// Description:
|
|
// Translate from AXI4S (Xilinx segmented ifc) to lbus.
|
|
//
|
|
// Built using example provided from Xilinx
|
|
//
|
|
// Parameters:
|
|
// - FIFO_DEPTH - FIFO will be 2** deep
|
|
// - NUM_SEG - Number of lbus segments coming in
|
|
|
|
import PkgEth100gLbus::*;
|
|
|
|
module eth_100g_axi2lbus #(
|
|
parameter FIFO_DEPTH = 5,
|
|
parameter NUM_SEG = 4
|
|
)
|
|
(
|
|
|
|
// AXIS IF
|
|
AxiStreamIf.slave axis,
|
|
|
|
// Lbus Segments
|
|
|
|
input logic lbus_rdy,
|
|
output lbus_t lbus_out [NUM_SEG-1:0]
|
|
|
|
);
|
|
|
|
localparam SEG_DATA_WIDTH = DATA_WIDTH/NUM_SEG;
|
|
localparam SEG_BYTES = SEG_DATA_WIDTH/8;
|
|
localparam SEG_MTY_WIDTH = $clog2(SEG_BYTES);
|
|
|
|
// post rotation lbus signals
|
|
lbus_t lbus_d [NUM_SEG-1:0];
|
|
|
|
// Find last so we can find SOP
|
|
logic found_last;
|
|
|
|
// Propagate ready when asserting , propagate delayed ready while deasserting
|
|
logic axis_tready_i;
|
|
assign axis.tready = axis_tready_i | lbus_rdy;
|
|
|
|
always @(posedge axis.clk) begin
|
|
axis_tready_i <= lbus_rdy;
|
|
end
|
|
|
|
//declare a segment width axis bus so I can use it's methods
|
|
AxiStreamIf #(.DATA_WIDTH(SEG_DATA_WIDTH),.USER_WIDTH($clog2(SEG_BYTES)))
|
|
seg_axi (axis.clk, axis.rst);
|
|
assign seg_axi.tlast = 1'b1;
|
|
|
|
logic [NUM_SEG:0] valid;
|
|
assign valid[NUM_SEG] = 1'b0;
|
|
|
|
genvar b;
|
|
genvar s;
|
|
generate begin : lbus_gen
|
|
for (s=0; s < NUM_SEG; s=s+1) begin : segment_loop
|
|
// Reverse data byte ordering on each segment
|
|
for (b = 0; b < DATA_WIDTH/32; b=b+1) begin : byte_loop
|
|
assign lbus_d[s].data[b*8 +: 8] = axis.tdata[((s+1)*(DATA_WIDTH/NUM_SEG)-8-(b*8)) +: 8];
|
|
end : byte_loop
|
|
// valid if tkeep is set for any bytes in the segment
|
|
assign valid[s] = (| axis.tkeep[s*SEG_BYTES +: SEG_BYTES]) & axis.tvalid;
|
|
// enable when valid and transfering
|
|
assign lbus_d[s].ena = valid[s] & axis.tready;
|
|
// eop on last valid byte if last is set
|
|
// we init an extra valid bit to 0 so if all valid bits for all segments are set we trigger an eop on the final segment
|
|
assign lbus_d[s].eop = (valid[s] ^ valid[s+1]) & axis.tlast;
|
|
// set error on all segmetns if tuser is set
|
|
assign lbus_d[s].err = valid[s] & axis.tuser;
|
|
// translate keep to trailing bytes and invert sign
|
|
always_comb begin
|
|
if (lbus_d[s].eop) begin
|
|
lbus_d[s].mty = SEG_BYTES - seg_axi.keep2trailing(axis.tkeep[s*SEG_BYTES+: SEG_BYTES]);
|
|
end else begin
|
|
lbus_d[s].mty = 'b0;
|
|
end
|
|
end
|
|
//SOP can only occur on segment 0, so init all the bits to zero, then assign segment 0
|
|
if (s==0) begin
|
|
assign lbus_d[s].sop = found_last & axis.tvalid & axis.tready;
|
|
end else begin
|
|
assign lbus_d[s].sop = 1'b0;
|
|
end
|
|
// assign the output DFF's
|
|
always_ff @(posedge axis.clk) begin
|
|
lbus_out[s].data <= lbus_d[s].data;
|
|
lbus_out[s].ena <= lbus_d[s].ena;
|
|
lbus_out[s].sop <= lbus_d[s].sop;
|
|
lbus_out[s].eop <= lbus_d[s].eop;
|
|
lbus_out[s].err <= lbus_d[s].err;
|
|
lbus_out[s].mty <= lbus_d[s].mty;
|
|
end
|
|
|
|
end : segment_loop
|
|
end : lbus_gen
|
|
endgenerate
|
|
|
|
|
|
|
|
// SOP Statemachine
|
|
always_ff @(posedge axis.clk) begin : sop_sm
|
|
if(axis.rst) begin
|
|
found_last <= 1'b1;
|
|
end else begin
|
|
if(axis.tvalid & axis.tlast & axis.tready) found_last <= 1'b1;
|
|
else if(axis.tvalid & axis.tready) found_last <= 1'b0;
|
|
end
|
|
end : sop_sm
|
|
|
|
endmodule
|
|
|
|
|