mirror of
https://github.com/fpganinja/taxi.git
synced 2025-12-09 08:58:40 -08:00
245 lines
6.7 KiB
Systemverilog
245 lines
6.7 KiB
Systemverilog
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
|
/*
|
|
|
|
Copyright (c) 2019-2025 FPGA Ninja, LLC
|
|
|
|
Authors:
|
|
- Alex Forencich
|
|
|
|
*/
|
|
|
|
`resetall
|
|
`timescale 1ns / 1ps
|
|
`default_nettype none
|
|
|
|
/*
|
|
* AXI4-Stream asynchronous FIFO with width converter
|
|
*/
|
|
module taxi_axis_async_fifo_adapter #
|
|
(
|
|
// FIFO depth in words
|
|
// KEEP_W words per cycle if KEEP_EN set
|
|
// Rounded up to nearest power of 2 cycles
|
|
parameter DEPTH = 4096,
|
|
// number of RAM pipeline registers in FIFO
|
|
parameter RAM_PIPELINE = 1,
|
|
// use output FIFO
|
|
// When set, the RAM read enable and pipeline clock enables are removed
|
|
parameter logic OUTPUT_FIFO_EN = 1'b0,
|
|
// Frame FIFO mode - operate on frames instead of cycles
|
|
// When set, m_axis_tvalid will not be deasserted within a frame
|
|
// Requires LAST_EN set
|
|
parameter logic FRAME_FIFO = 1'b0,
|
|
// tuser value for bad frame marker
|
|
parameter USER_BAD_FRAME_VALUE = 1'b1,
|
|
// tuser mask for bad frame marker
|
|
parameter USER_BAD_FRAME_MASK = 1'b1,
|
|
// Drop frames larger than FIFO
|
|
// Requires FRAME_FIFO set
|
|
parameter logic DROP_OVERSIZE_FRAME = FRAME_FIFO,
|
|
// Drop frames marked bad
|
|
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
|
parameter logic DROP_BAD_FRAME = 1'b0,
|
|
// Drop incoming frames when full
|
|
// When set, s_axis_tready is always asserted
|
|
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
|
parameter logic DROP_WHEN_FULL = 1'b0,
|
|
// Mark incoming frames as bad frames when full
|
|
// When set, s_axis_tready is always asserted
|
|
// Requires FRAME_FIFO to be clear
|
|
parameter logic MARK_WHEN_FULL = 1'b0,
|
|
// Enable pause request input
|
|
parameter logic PAUSE_EN = 1'b0,
|
|
// Pause between frames
|
|
parameter logic FRAME_PAUSE = FRAME_FIFO
|
|
)
|
|
(
|
|
/*
|
|
* AXI4-Stream input (sink)
|
|
*/
|
|
input wire logic s_clk,
|
|
input wire logic s_rst,
|
|
taxi_axis_if.snk s_axis,
|
|
|
|
/*
|
|
* AXI4-Stream output (source)
|
|
*/
|
|
input wire logic m_clk,
|
|
input wire logic m_rst,
|
|
taxi_axis_if.src m_axis,
|
|
|
|
/*
|
|
* Pause
|
|
*/
|
|
input wire logic s_pause_req = 1'b0,
|
|
output wire logic s_pause_ack,
|
|
input wire logic m_pause_req = 1'b0,
|
|
output wire logic m_pause_ack,
|
|
|
|
/*
|
|
* Status
|
|
*/
|
|
output wire logic [$clog2(DEPTH):0] s_status_depth,
|
|
output wire logic [$clog2(DEPTH):0] s_status_depth_commit,
|
|
output wire logic s_status_overflow,
|
|
output wire logic s_status_bad_frame,
|
|
output wire logic s_status_good_frame,
|
|
output wire logic [$clog2(DEPTH):0] m_status_depth,
|
|
output wire logic [$clog2(DEPTH):0] m_status_depth_commit,
|
|
output wire logic m_status_overflow,
|
|
output wire logic m_status_bad_frame,
|
|
output wire logic m_status_good_frame
|
|
);
|
|
|
|
// extract parameters
|
|
localparam S_DATA_W = s_axis.DATA_W;
|
|
localparam logic S_KEEP_EN = s_axis.KEEP_EN;
|
|
localparam S_KEEP_W = s_axis.KEEP_W;
|
|
localparam logic S_STRB_EN = s_axis.STRB_EN;
|
|
|
|
localparam M_DATA_W = m_axis.DATA_W;
|
|
localparam logic M_KEEP_EN = m_axis.KEEP_EN;
|
|
localparam M_KEEP_W = m_axis.KEEP_W;
|
|
localparam logic M_STRB_EN = m_axis.STRB_EN;
|
|
|
|
// force keep width to 1 when disabled
|
|
localparam S_BYTE_LANES = S_KEEP_EN ? S_KEEP_W : 1;
|
|
localparam M_BYTE_LANES = M_KEEP_EN ? M_KEEP_W : 1;
|
|
|
|
// bus byte sizes (must be identical)
|
|
localparam S_BYTE_SIZE = S_DATA_W / S_BYTE_LANES;
|
|
localparam M_BYTE_SIZE = M_DATA_W / M_BYTE_LANES;
|
|
// output bus is wider
|
|
localparam EXPAND_BUS = M_BYTE_LANES > S_BYTE_LANES;
|
|
// total data and keep widths
|
|
localparam DATA_W = EXPAND_BUS ? M_DATA_W : S_DATA_W;
|
|
localparam KEEP_W = EXPAND_BUS ? M_BYTE_LANES : S_BYTE_LANES;
|
|
localparam KEEP_EN = EXPAND_BUS ? M_KEEP_EN : S_KEEP_EN;
|
|
localparam STRB_EN = M_STRB_EN && S_STRB_EN;
|
|
|
|
// check configuration
|
|
if (S_BYTE_SIZE * S_BYTE_LANES != S_DATA_W)
|
|
$fatal(0, "Error: input data width not evenly divisible (instance %m)");
|
|
|
|
if (M_BYTE_SIZE * M_BYTE_LANES != M_DATA_W)
|
|
$fatal(0, "Error: output data width not evenly divisible (instance %m)");
|
|
|
|
if (S_BYTE_SIZE != M_BYTE_SIZE)
|
|
$fatal(0, "Error: byte size mismatch (instance %m)");
|
|
|
|
taxi_axis_if #(
|
|
.DATA_W(DATA_W),
|
|
.KEEP_EN(KEEP_EN),
|
|
.KEEP_W(KEEP_W),
|
|
.STRB_EN(s_axis.STRB_EN),
|
|
.LAST_EN(s_axis.LAST_EN),
|
|
.ID_EN(s_axis.ID_EN),
|
|
.ID_W(s_axis.ID_W),
|
|
.DEST_EN(s_axis.DEST_EN),
|
|
.DEST_W(s_axis.DEST_W),
|
|
.USER_EN(s_axis.USER_EN),
|
|
.USER_W(s_axis.USER_W)
|
|
) axis_pre_fifo();
|
|
|
|
taxi_axis_if #(
|
|
.DATA_W(DATA_W),
|
|
.KEEP_EN(KEEP_EN),
|
|
.KEEP_W(KEEP_W),
|
|
.STRB_EN(m_axis.STRB_EN),
|
|
.LAST_EN(m_axis.LAST_EN),
|
|
.ID_EN(m_axis.ID_EN),
|
|
.ID_W(m_axis.ID_W),
|
|
.DEST_EN(m_axis.DEST_EN),
|
|
.DEST_W(m_axis.DEST_W),
|
|
.USER_EN(m_axis.USER_EN),
|
|
.USER_W(m_axis.USER_W)
|
|
) axis_post_fifo();
|
|
|
|
taxi_axis_adapter
|
|
pre_fifo_adapter_inst (
|
|
.clk(s_clk),
|
|
.rst(s_rst),
|
|
|
|
/*
|
|
* AXI4-Stream input (sink)
|
|
*/
|
|
.s_axis(s_axis),
|
|
|
|
/*
|
|
* AXI4-Stream output (source)
|
|
*/
|
|
.m_axis(axis_pre_fifo)
|
|
);
|
|
|
|
taxi_axis_async_fifo #(
|
|
.DEPTH(DEPTH),
|
|
.RAM_PIPELINE(RAM_PIPELINE),
|
|
.OUTPUT_FIFO_EN(OUTPUT_FIFO_EN),
|
|
.FRAME_FIFO(FRAME_FIFO),
|
|
.USER_BAD_FRAME_VALUE(USER_BAD_FRAME_VALUE),
|
|
.USER_BAD_FRAME_MASK(USER_BAD_FRAME_MASK),
|
|
.DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME),
|
|
.DROP_BAD_FRAME(DROP_BAD_FRAME),
|
|
.DROP_WHEN_FULL(DROP_WHEN_FULL),
|
|
.MARK_WHEN_FULL(MARK_WHEN_FULL),
|
|
.PAUSE_EN(PAUSE_EN),
|
|
.FRAME_PAUSE(FRAME_PAUSE)
|
|
)
|
|
fifo_inst (
|
|
/*
|
|
* AXI4-Stream input (sink)
|
|
*/
|
|
.s_clk(s_clk),
|
|
.s_rst(s_rst),
|
|
.s_axis(axis_pre_fifo),
|
|
|
|
/*
|
|
* AXI4-Stream output (source)
|
|
*/
|
|
.m_clk(m_clk),
|
|
.m_rst(m_rst),
|
|
.m_axis(axis_post_fifo),
|
|
|
|
/*
|
|
* Pause
|
|
*/
|
|
.s_pause_req(s_pause_req),
|
|
.s_pause_ack(s_pause_ack),
|
|
.m_pause_req(m_pause_req),
|
|
.m_pause_ack(m_pause_ack),
|
|
|
|
/*
|
|
* Status
|
|
*/
|
|
.s_status_depth(s_status_depth),
|
|
.s_status_depth_commit(s_status_depth_commit),
|
|
.s_status_overflow(s_status_overflow),
|
|
.s_status_bad_frame(s_status_bad_frame),
|
|
.s_status_good_frame(s_status_good_frame),
|
|
.m_status_depth(m_status_depth),
|
|
.m_status_depth_commit(m_status_depth_commit),
|
|
.m_status_overflow(m_status_overflow),
|
|
.m_status_bad_frame(m_status_bad_frame),
|
|
.m_status_good_frame(m_status_good_frame)
|
|
);
|
|
|
|
taxi_axis_adapter
|
|
post_fifo_adapter_inst (
|
|
.clk(m_clk),
|
|
.rst(m_rst),
|
|
|
|
/*
|
|
* AXI4-Stream input (sink)
|
|
*/
|
|
.s_axis(axis_post_fifo),
|
|
|
|
/*
|
|
* AXI4-Stream output (source)
|
|
*/
|
|
.m_axis(m_axis)
|
|
);
|
|
|
|
endmodule
|
|
|
|
`resetall
|