Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce the size of the repository. However, over the last half-decade, the split between the repositories has proven more burdensome than it has been helpful. By merging the FPGA code back, it will be possible to create atomic commits that touch both FPGA and UHD codebases. Continuous integration testing is also simplified by merging the repositories, because it was previously difficult to automatically derive the correct UHD branch when testing a feature branch on the FPGA repository. This commit also updates the license files and paths therein. We are therefore merging the repositories again. Future development for FPGA code will happen in the same repository as the UHD host code and MPM code. == Original Codebase and Rebasing == The original FPGA repository will be hosted for the foreseeable future at its original local location: https://github.com/EttusResearch/fpga/ It can be used for bisecting, reference, and a more detailed history. The final commit from said repository to be merged here is 05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as v4.0.0.0-pre-uhd-merge. If you have changes in the FPGA repository that you want to rebase onto the UHD repository, simply run the following commands: - Create a directory to store patches (this should be an empty directory): mkdir ~/patches - Now make sure that your FPGA codebase is based on the same state as the code that was merged: cd src/fpga # Or wherever your FPGA code is stored git rebase v4.0.0.0-pre-uhd-merge Note: The rebase command may look slightly different depending on what exactly you're trying to rebase. - Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge: git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches Note: Make sure that only patches are stored in your output directory. It should otherwise be empty. Make sure that you picked the correct range of commits, and only commits you wanted to rebase were exported as patch files. - Go to the UHD repository and apply the patches: cd src/uhd # Or wherever your UHD repository is stored git am --directory fpga ~/patches/* rm -rf ~/patches # This is for cleanup == Contributors == The following people have contributed mainly to these files (this list is not complete): Co-authored-by: Alex Williams <alex.williams@ni.com> Co-authored-by: Andrej Rode <andrej.rode@ettus.com> Co-authored-by: Ashish Chaudhari <ashish@ettus.com> Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com> Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Derek Kozel <derek.kozel@ettus.com> Co-authored-by: EJ Kreinar <ej@he360.com> Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com> Co-authored-by: Ian Buckley <ian.buckley@gmail.com> Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Jon Kiser <jon.kiser@ni.com> Co-authored-by: Josh Blum <josh@joshknows.com> Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com> Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Matt Ettus <matt@ettus.com> Co-authored-by: Michael West <michael.west@ettus.com> Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com> Co-authored-by: Nick Foster <nick@ettus.com> Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Paul David <paul.david@ettus.com> Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com> Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com> Co-authored-by: Sylvain Munaut <tnt@246tNt.com> Co-authored-by: Trung Tran <trung.tran@ettus.com> Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com> Co-authored-by: Wade Fife <wade.fife@ettus.com> Original-commit: bafa9d95453387814ef25e6b6256ba8db2df612f
This commit is contained in:
co-authored by
Alex Williams
Andrej Rode
Ashish Chaudhari
Ben Hilburn
Ciro Nishiguchi
Daniel Jepson
Derek Kozel
EJ Kreinar
Humberto Jimenez
Ian Buckley
Jörg Hofrichter
Jon Kiser
Josh Blum
Jonathon Pendlum
Matt Ettus
Michael West
Moritz Fischer
Nick Foster
Nicolas Cuervo
Paul Butler
Paul David
Ryan Marlow
Sugandha Gupta
Sylvain Munaut
Trung Tran
Vidush Vishwanath
Wade Fife
parent
74893643ca
commit
6b67702ad7
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Copyright 2019 Ettus Research, A National Instruments Company
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
#-------------------------------------------------
|
||||
# Top-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Define BASE_DIR to point to the "top" dir
|
||||
BASE_DIR = $(abspath ../../../../top)
|
||||
# Include viv_sim_preamble after defining BASE_DIR
|
||||
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
|
||||
|
||||
#-------------------------------------------------
|
||||
# Design Specific
|
||||
#-------------------------------------------------
|
||||
# Include makefiles and sources for the DUT and its dependencies
|
||||
include $(BASE_DIR)/../lib/rfnoc/core/Makefile.srcs
|
||||
include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs
|
||||
include Makefile.srcs
|
||||
|
||||
DESIGN_SRCS += $(abspath \
|
||||
$(RFNOC_CORE_SRCS) \
|
||||
$(RFNOC_UTIL_SRCS) \
|
||||
$(RFNOC_BLOCK_AXI_RAM_FIFO_SRCS) \
|
||||
)
|
||||
|
||||
#-------------------------------------------------
|
||||
# Testbench Specific
|
||||
#-------------------------------------------------
|
||||
SIM_TOP = rfnoc_block_axi_ram_fifo_all_tb
|
||||
|
||||
SIM_SRCS = \
|
||||
$(abspath sim_axi_ram.sv) \
|
||||
$(abspath rfnoc_block_axi_ram_fifo_tb.sv) \
|
||||
$(abspath rfnoc_block_axi_ram_fifo_all_tb.sv)
|
||||
|
||||
#-------------------------------------------------
|
||||
# Bottom-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Include all simulator specific makefiles here
|
||||
# Each should define a unique target to simulate
|
||||
# e.g. xsim, vsim, etc and a common "clean" target
|
||||
include $(BASE_DIR)/../tools/make/viv_simulator.mak
|
||||
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright 2019 Ettus Research, A National Instruments Company
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
##################################################
|
||||
# RFNoC Utility Sources
|
||||
##################################################
|
||||
RFNOC_BLOCK_AXI_RAM_FIFO_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/rfnoc/blocks/rfnoc_block_axi_ram_fifo/, \
|
||||
noc_shell_axi_ram_fifo.v \
|
||||
axi_ram_fifo_regs.vh \
|
||||
axi_ram_fifo_regs.v \
|
||||
axi_ram_fifo_bist.v \
|
||||
axi_ram_fifo_bist_regs.v \
|
||||
axi_ram_fifo.v \
|
||||
rfnoc_block_axi_ram_fifo.v \
|
||||
))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,294 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: axi_ram_fifo_bist
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Implements a built-in self test for the RAM FIFO. It can generate random
|
||||
// or sequential data that it outputs as quickly as possible. The output of
|
||||
// the RAM is verified to make sure that it matches what was input to the RAM.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// DATA_W : The width of the data port to use for the AXI4-Stream interface
|
||||
//
|
||||
// COUNT_W : Width of internal counters. This must be wide enough so that
|
||||
// word, cycle, and and error counters don't overflow during a
|
||||
// test.
|
||||
//
|
||||
// CLK_RATE : The frequency of clk in Hz
|
||||
//
|
||||
// RAND : Set to 1 for random data, 0 for sequential data.
|
||||
//
|
||||
|
||||
module axi_ram_fifo_bist #(
|
||||
parameter DATA_W = 64,
|
||||
parameter COUNT_W = 48,
|
||||
parameter CLK_RATE = 200e6,
|
||||
parameter RAND = 1
|
||||
) (
|
||||
input clk,
|
||||
input rst,
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// CTRL Port
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
input wire s_ctrlport_req_wr,
|
||||
input wire s_ctrlport_req_rd,
|
||||
input wire [19:0] s_ctrlport_req_addr,
|
||||
input wire [31:0] s_ctrlport_req_data,
|
||||
output wire s_ctrlport_resp_ack,
|
||||
output wire [31:0] s_ctrlport_resp_data,
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// AXI-Stream Interface
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Output to RAM FIFO
|
||||
output wire [DATA_W-1:0] m_tdata,
|
||||
output reg m_tvalid,
|
||||
input wire m_tready,
|
||||
|
||||
// Input from RAM FIFO
|
||||
input wire [DATA_W-1:0] s_tdata,
|
||||
input wire s_tvalid,
|
||||
output wire s_tready,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Status
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
output reg running
|
||||
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Local Parameters
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Internal word size to use for data generation. The output word will be a
|
||||
// multiple of this size.
|
||||
localparam WORD_W = 32;
|
||||
|
||||
// Random number seed (must not be 0)
|
||||
localparam [WORD_W-1:0] SEED = 'h012345678;
|
||||
|
||||
// Test data reset value
|
||||
localparam [WORD_W-1:0] INIT = RAND ? SEED : 0;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Assertions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
if (DATA_W % WORD_W != 0) begin
|
||||
DATA_W_must_be_a_multiple_of_WORD_W();
|
||||
end
|
||||
|
||||
// LFSR only supports 8, 16, and 32 bits
|
||||
if (WORD_W != 32 && WORD_W != 16 && WORD_W != 8) begin
|
||||
WORD_W_not_supported();
|
||||
end
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Functions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Linear-feedback Shift Register for random number generation.
|
||||
function [WORD_W-1:0] lfsr(input [WORD_W-1:0] din);
|
||||
reg new_bit;
|
||||
begin
|
||||
case (WORD_W)
|
||||
8 : new_bit = din[7] ^ din[5] ^ din[4] ^ din[3];
|
||||
16 : new_bit = din[15] ^ din[14] ^ din[12] ^ din[3];
|
||||
32 : new_bit = din[31] ^ din[21] ^ din[1] ^ din[0];
|
||||
endcase
|
||||
lfsr = { din[WORD_W-2:0], new_bit };
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [WORD_W-1:0] next(input [WORD_W-1:0] din);
|
||||
next = RAND ? lfsr(din) : din + 1;
|
||||
endfunction
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Signal Declarations
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
reg [COUNT_W-1:0] tx_count; // Number of words transmitted to FIFO
|
||||
reg [COUNT_W-1:0] rx_count; // Number of words received back from FIFO
|
||||
reg [COUNT_W-1:0] error_count; // Number of words that show errors
|
||||
|
||||
reg [WORD_W-1:0] tx_data = next(INIT); // Transmitted data word
|
||||
reg [DATA_W-1:0] rx_data = INIT; // Received data words
|
||||
reg [WORD_W-1:0] exp_data; // Expected data word
|
||||
reg rx_valid; // Received word is value (strobe)
|
||||
|
||||
wire [COUNT_W-1:0] num_words; // Number of words to test
|
||||
reg [COUNT_W-1:0] cycle_count; // Number of clock cycles test has been running for
|
||||
wire start; // Start test
|
||||
wire stop; // Stop test
|
||||
wire clear; // Clear the counters
|
||||
wire continuous; // Continuous test mode
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Registers
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
axi_ram_fifo_bist_regs #(
|
||||
.DATA_W (DATA_W),
|
||||
.COUNT_W (COUNT_W),
|
||||
.CLK_RATE (CLK_RATE)
|
||||
) axi_ram_fifo_bist_regs_i (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
.s_ctrlport_req_wr (s_ctrlport_req_wr),
|
||||
.s_ctrlport_req_rd (s_ctrlport_req_rd),
|
||||
.s_ctrlport_req_addr (s_ctrlport_req_addr),
|
||||
.s_ctrlport_req_data (s_ctrlport_req_data),
|
||||
.s_ctrlport_resp_ack (s_ctrlport_resp_ack),
|
||||
.s_ctrlport_resp_data (s_ctrlport_resp_data),
|
||||
.tx_count (tx_count),
|
||||
.rx_count (rx_count),
|
||||
.error_count (error_count),
|
||||
.cycle_count (cycle_count),
|
||||
.num_words (num_words),
|
||||
.start (start),
|
||||
.stop (stop),
|
||||
.clear (clear),
|
||||
.continuous (continuous),
|
||||
.running (running)
|
||||
);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// State Machine
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
localparam ST_IDLE = 0;
|
||||
localparam ST_ACTIVE = 1;
|
||||
localparam ST_WAIT_DONE = 2;
|
||||
|
||||
reg [ 1:0] state;
|
||||
reg [COUNT_W-1:0] num_words_m1;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
state <= ST_IDLE;
|
||||
m_tvalid <= 0;
|
||||
running <= 0;
|
||||
end else begin
|
||||
m_tvalid <= 0;
|
||||
|
||||
case (state)
|
||||
ST_IDLE : begin
|
||||
num_words_m1 <= num_words-1;
|
||||
if (start) begin
|
||||
running <= 1;
|
||||
state <= ST_ACTIVE;
|
||||
end
|
||||
end
|
||||
|
||||
ST_ACTIVE : begin
|
||||
if (stop || (tx_count == num_words_m1 && m_tvalid && m_tready && !continuous)) begin
|
||||
m_tvalid <= 0;
|
||||
state <= ST_WAIT_DONE;
|
||||
end else begin
|
||||
m_tvalid <= 1;
|
||||
running <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
ST_WAIT_DONE : begin
|
||||
if (rx_count >= tx_count) begin
|
||||
running <= 0;
|
||||
state <= ST_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Data Generator
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
reg count_en;
|
||||
|
||||
// Output data is the concatenation of our generated test word.
|
||||
assign m_tdata = {(DATA_W/WORD_W){ tx_data }};
|
||||
|
||||
// We were born ready
|
||||
assign s_tready = 1;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
tx_data <= next(INIT);
|
||||
exp_data <= INIT;
|
||||
rx_valid <= 0;
|
||||
tx_count <= 0;
|
||||
rx_count <= 0;
|
||||
error_count <= 0;
|
||||
cycle_count <= 0;
|
||||
count_en <= 0;
|
||||
end else begin
|
||||
//
|
||||
// Output Data generation
|
||||
//
|
||||
if (m_tvalid && m_tready) begin
|
||||
tx_data <= next(tx_data);
|
||||
tx_count <= tx_count + 1;
|
||||
end
|
||||
|
||||
//
|
||||
// Expected Data Generation
|
||||
//
|
||||
if (s_tvalid & s_tready) begin
|
||||
rx_valid <= 1;
|
||||
exp_data <= next(exp_data);
|
||||
rx_count <= rx_count + 1;
|
||||
rx_data <= s_tdata;
|
||||
end else begin
|
||||
rx_valid <= 0;
|
||||
end
|
||||
|
||||
//
|
||||
// Data checker
|
||||
//
|
||||
if (rx_valid) begin
|
||||
if (rx_data !== {(DATA_W/WORD_W){exp_data}}) begin
|
||||
error_count <= error_count + 1;
|
||||
end
|
||||
end
|
||||
|
||||
//
|
||||
// Cycle Counter
|
||||
//
|
||||
// Start counting after get the first word back so that we measure
|
||||
// throughput and not latency.
|
||||
if (state == ST_IDLE) count_en <= 0;
|
||||
else if (s_tvalid) count_en <= 1;
|
||||
|
||||
if (count_en) cycle_count <= cycle_count + 1;
|
||||
|
||||
//
|
||||
// Clear counters upon request
|
||||
//
|
||||
if (clear) begin
|
||||
tx_count <= 0;
|
||||
rx_count <= 0;
|
||||
error_count <= 0;
|
||||
cycle_count <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: axi_ram_fifo_bist_regs
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Implements the registers for the RAM FIFO BIST logic.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// DATA_W : The width of the data port to use for the AXI4-Stream
|
||||
// interface.
|
||||
//
|
||||
// COUNT_W : Width of internal counters. This must be wide enough so that
|
||||
// word, cycle, and and error counters don't overflow during a
|
||||
// test.
|
||||
//
|
||||
// CLK_RATE : The frequency of clk in Hz
|
||||
//
|
||||
|
||||
module axi_ram_fifo_bist_regs #(
|
||||
parameter DATA_W = 64,
|
||||
parameter COUNT_W = 48,
|
||||
parameter CLK_RATE = 200e6
|
||||
) (
|
||||
input clk,
|
||||
input rst,
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// CTRL Port
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
input wire s_ctrlport_req_wr,
|
||||
input wire s_ctrlport_req_rd,
|
||||
input wire [19:0] s_ctrlport_req_addr,
|
||||
input wire [31:0] s_ctrlport_req_data,
|
||||
output reg s_ctrlport_resp_ack,
|
||||
output reg [31:0] s_ctrlport_resp_data,
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Control and Status
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
input wire [COUNT_W-1:0] tx_count,
|
||||
input wire [COUNT_W-1:0] rx_count,
|
||||
input wire [COUNT_W-1:0] error_count,
|
||||
input wire [COUNT_W-1:0] cycle_count,
|
||||
|
||||
output wire [COUNT_W-1:0] num_words,
|
||||
|
||||
output reg start,
|
||||
output reg stop,
|
||||
output reg clear,
|
||||
output reg continuous,
|
||||
input wire running
|
||||
);
|
||||
|
||||
`include "axi_ram_fifo_regs.vh"
|
||||
|
||||
localparam BYTES_PER_WORD = DATA_W/8;
|
||||
localparam WORD_SHIFT = $clog2(BYTES_PER_WORD);
|
||||
|
||||
// Make sure DATA_W is a power of 2, or else the word/byte count conversion
|
||||
// logic won't be correct.
|
||||
if (2**$clog2(DATA_W) != DATA_W) begin
|
||||
DATA_W_must_be_a_power_of_2();
|
||||
end
|
||||
|
||||
// The register logic currently assumes that COUNT_W is at least 33 bits.
|
||||
if (COUNT_W <= 32) begin
|
||||
COUNT_W_must_be_larger_than_32();
|
||||
end
|
||||
|
||||
wire [19:0] word_addr;
|
||||
wire [63:0] tx_byte_count;
|
||||
wire [63:0] rx_byte_count;
|
||||
reg [63:0] num_bytes = 0;
|
||||
|
||||
reg [31:0] tx_byte_count_hi = 0;
|
||||
reg [31:0] rx_byte_count_hi = 0;
|
||||
reg [31:0] error_count_hi = 0;
|
||||
reg [31:0] cycle_count_hi = 0;
|
||||
|
||||
// Only use the word address to simplify address decoding logic
|
||||
assign word_addr = {s_ctrlport_req_addr[19:2], 2'b00 };
|
||||
|
||||
// Convert between words and bytes
|
||||
assign tx_byte_count = tx_count << WORD_SHIFT;
|
||||
assign rx_byte_count = rx_count << WORD_SHIFT;
|
||||
assign num_words = num_bytes >> WORD_SHIFT;
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
s_ctrlport_resp_ack <= 0;
|
||||
start <= 0;
|
||||
stop <= 0;
|
||||
continuous <= 0;
|
||||
clear <= 0;
|
||||
num_bytes <= 0;
|
||||
end else begin
|
||||
// Default values
|
||||
s_ctrlport_resp_ack <= 0;
|
||||
start <= 0;
|
||||
stop <= 0;
|
||||
clear <= 0;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Read Logic
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
if (s_ctrlport_req_rd) begin
|
||||
case (word_addr)
|
||||
REG_BIST_CTRL : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[REG_BIST_RUNNING_POS] <= running;
|
||||
s_ctrlport_resp_data[REG_BIST_CONT_POS] <= continuous;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_CLK_RATE : begin
|
||||
s_ctrlport_resp_data <= CLK_RATE;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_NUM_BYTES_LO : begin
|
||||
s_ctrlport_resp_data <= num_bytes[31:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_NUM_BYTES_HI : begin
|
||||
s_ctrlport_resp_data <= num_bytes[63:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_TX_BYTE_COUNT_LO : begin
|
||||
s_ctrlport_resp_data <= tx_byte_count[31:0];
|
||||
tx_byte_count_hi <= tx_byte_count[63:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_TX_BYTE_COUNT_HI : begin
|
||||
s_ctrlport_resp_data <= tx_byte_count_hi;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_RX_BYTE_COUNT_LO : begin
|
||||
s_ctrlport_resp_data <= rx_byte_count[31:0];
|
||||
rx_byte_count_hi[COUNT_W-33:0] <= rx_byte_count[COUNT_W-1:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_RX_BYTE_COUNT_HI : begin
|
||||
s_ctrlport_resp_data <= rx_byte_count_hi;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_ERROR_COUNT_LO : begin
|
||||
s_ctrlport_resp_data <= error_count[31:0];
|
||||
error_count_hi[COUNT_W-33:0] <= error_count[COUNT_W-1:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_ERROR_COUNT_HI : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data <= error_count_hi;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_CYCLE_COUNT_LO : begin
|
||||
s_ctrlport_resp_data <= cycle_count[31:0];
|
||||
cycle_count_hi[COUNT_W-33:0] <= cycle_count[COUNT_W-1:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_CYCLE_COUNT_HI : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data <= cycle_count_hi;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Write Logic
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
if (s_ctrlport_req_wr) begin
|
||||
case (word_addr)
|
||||
REG_BIST_CTRL : begin
|
||||
start <= s_ctrlport_req_data[REG_BIST_START_POS];
|
||||
stop <= s_ctrlport_req_data[REG_BIST_STOP_POS];
|
||||
clear <= s_ctrlport_req_data[REG_BIST_CLEAR_POS];
|
||||
continuous <= s_ctrlport_req_data[REG_BIST_CONT_POS];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_NUM_BYTES_LO : begin
|
||||
// Update only the word-count portion
|
||||
num_bytes[31:WORD_SHIFT] <= s_ctrlport_req_data[31:WORD_SHIFT];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_BIST_NUM_BYTES_HI : begin
|
||||
num_bytes[COUNT_W-1:32] <= s_ctrlport_req_data[COUNT_W-33:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: axi_ram_fifo_regs
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Implements the software-accessible registers for the axi_ram_fifo block.
|
||||
//
|
||||
|
||||
|
||||
module axi_ram_fifo_regs #(
|
||||
parameter MEM_ADDR_W = 32,
|
||||
parameter MEM_DATA_W = 64,
|
||||
parameter [MEM_ADDR_W-1:0] FIFO_ADDR_BASE = 'h0,
|
||||
parameter [MEM_ADDR_W-1:0] FIFO_ADDR_MASK = 'h0000FFFF,
|
||||
parameter [MEM_ADDR_W-1:0] FIFO_ADDR_MASK_MIN = 'h00000FFF,
|
||||
parameter BIST = 1,
|
||||
parameter IN_FIFO_SIZE = 10,
|
||||
parameter WORD_ADDR_W = 29,
|
||||
parameter BURST_TIMEOUT = 128,
|
||||
parameter TIMEOUT_W = 12
|
||||
) (
|
||||
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// CTRL Port
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
input wire s_ctrlport_req_wr,
|
||||
input wire s_ctrlport_req_rd,
|
||||
input wire [19:0] s_ctrlport_req_addr,
|
||||
input wire [31:0] s_ctrlport_req_data,
|
||||
output reg s_ctrlport_resp_ack,
|
||||
output reg [31:0] s_ctrlport_resp_data,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Register Inputs and Outputs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Read-back Registers
|
||||
input wire [ 31:0] rb_out_pkt_count,
|
||||
input wire [WORD_ADDR_W:0] rb_occupied,
|
||||
|
||||
// Settings Registers
|
||||
output reg [ 15:0] set_suppress_threshold,
|
||||
output reg [ TIMEOUT_W-1:0] set_timeout,
|
||||
output reg [MEM_ADDR_W-1:0] set_fifo_addr_base = FIFO_ADDR_BASE,
|
||||
output reg [MEM_ADDR_W-1:0] set_fifo_addr_mask = FIFO_ADDR_MASK
|
||||
);
|
||||
|
||||
`include "axi_ram_fifo_regs.vh"
|
||||
|
||||
function automatic integer min(input integer a, b);
|
||||
min = a < b ? a : b;
|
||||
endfunction
|
||||
|
||||
function automatic integer max(input integer a, b);
|
||||
max = a > b ? a : b;
|
||||
endfunction
|
||||
|
||||
wire [19:0] word_addr;
|
||||
wire [63:0] reg_fifo_fullness;
|
||||
reg [31:0] reg_fifo_fullness_hi;
|
||||
|
||||
// Only use the word address to simplify address decoding logic
|
||||
assign word_addr = {s_ctrlport_req_addr[19:2], 2'b00 };
|
||||
|
||||
// Convert the "occupied" word count to a 64-bit byte value
|
||||
assign reg_fifo_fullness = {
|
||||
{64-MEM_ADDR_W{1'b0}}, // Set unused upper bits to 0
|
||||
rb_occupied,
|
||||
{(MEM_ADDR_W-WORD_ADDR_W){1'b0}} // Set byte offset bits to 0
|
||||
};
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
s_ctrlport_resp_ack <= 0;
|
||||
set_suppress_threshold <= 0;
|
||||
set_timeout <= BURST_TIMEOUT;
|
||||
set_fifo_addr_base <= FIFO_ADDR_BASE;
|
||||
set_fifo_addr_mask <= FIFO_ADDR_MASK;
|
||||
end else begin
|
||||
s_ctrlport_resp_ack <= 0;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Write Logic
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
if (s_ctrlport_req_wr) begin
|
||||
case (word_addr)
|
||||
REG_FIFO_READ_SUPPRESS : begin
|
||||
set_suppress_threshold <= s_ctrlport_req_data[REG_FIFO_SUPPRESS_THRESH_POS +: REG_FIFO_SUPPRESS_THRESH_W];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_TIMEOUT : begin
|
||||
set_timeout[REG_TIMEOUT_W-1:0] <= s_ctrlport_req_data[REG_TIMEOUT_W-1:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_BASE_LO : begin
|
||||
set_fifo_addr_base[min(32, MEM_ADDR_W)-1:0] <= s_ctrlport_req_data[min(32, MEM_ADDR_W)-1:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_BASE_HI : begin
|
||||
if (MEM_ADDR_W > 32) begin
|
||||
set_fifo_addr_base[max(32, MEM_ADDR_W-1):32] <= s_ctrlport_req_data[max(0, MEM_ADDR_W-33):0];
|
||||
end
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_MASK_LO : begin
|
||||
// Coerce the lower bits so we are guaranteed to meet the minimum mask size requirement.
|
||||
set_fifo_addr_mask[min(32, MEM_ADDR_W)-1:0] <=
|
||||
s_ctrlport_req_data[min(32, MEM_ADDR_W)-1:0] | FIFO_ADDR_MASK_MIN;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_MASK_HI : begin
|
||||
if (MEM_ADDR_W > 32) begin
|
||||
set_fifo_addr_mask[max(32, MEM_ADDR_W-1):32] <= s_ctrlport_req_data[max(0, MEM_ADDR_W-33):0];
|
||||
end
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Read Logic
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
if (s_ctrlport_req_rd) begin
|
||||
case (word_addr)
|
||||
REG_FIFO_INFO : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[REG_FIFO_MAGIC_POS +: REG_FIFO_MAGIC_W] <= 16'hF1F0;
|
||||
s_ctrlport_resp_data[REG_FIFO_BIST_PRSNT_POS] <= (BIST != 0);
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_READ_SUPPRESS : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[REG_FIFO_IN_FIFO_SIZE_POS +: REG_FIFO_IN_FIFO_SIZE_W]
|
||||
<= IN_FIFO_SIZE;
|
||||
s_ctrlport_resp_data[REG_FIFO_SUPPRESS_THRESH_POS +: REG_FIFO_SUPPRESS_THRESH_W]
|
||||
<= set_suppress_threshold;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_MEM_SIZE : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[REG_FIFO_DATA_SIZE_POS +: REG_FIFO_DATA_SIZE_W]
|
||||
<= MEM_DATA_W;
|
||||
s_ctrlport_resp_data[REG_FIFO_ADDR_SIZE_POS +: REG_FIFO_ADDR_SIZE_W]
|
||||
<= MEM_ADDR_W;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_TIMEOUT : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[REG_TIMEOUT_W-1:0] <= set_timeout[REG_TIMEOUT_W-1:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_FULLNESS_LO : begin
|
||||
s_ctrlport_resp_data <= reg_fifo_fullness[31:0];
|
||||
reg_fifo_fullness_hi <= reg_fifo_fullness[63:32];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_FULLNESS_HI : begin
|
||||
s_ctrlport_resp_data <= reg_fifo_fullness_hi;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_BASE_LO : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[min(32, MEM_ADDR_W)-1:0] <= set_fifo_addr_base[min(32, MEM_ADDR_W)-1:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_BASE_HI : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
if (MEM_ADDR_W > 32) begin
|
||||
s_ctrlport_resp_data[max(0,MEM_ADDR_W-33):0] <= set_fifo_addr_base[max(32, MEM_ADDR_W-1):32];
|
||||
end
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_MASK_LO : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data[min(32, MEM_ADDR_W)-1:0] <= set_fifo_addr_mask[min(32, MEM_ADDR_W)-1:0];
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_ADDR_MASK_HI : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
if (MEM_ADDR_W > 32) begin
|
||||
s_ctrlport_resp_data[max(0, MEM_ADDR_W-33):0] <= set_fifo_addr_mask[max(32, MEM_ADDR_W-1):32];
|
||||
end
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
REG_FIFO_PACKET_CNT : begin
|
||||
s_ctrlport_resp_data <= 0;
|
||||
s_ctrlport_resp_data <= rb_out_pkt_count;
|
||||
s_ctrlport_resp_ack <= 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: axi_ram_fifo_regs (Header)
|
||||
//
|
||||
// Description: Header file for axi_ram_fifo_regs. All registers are 32-bit
|
||||
// words from software's perspective.
|
||||
//
|
||||
|
||||
// Address space size, per FIFO. That is, each FIFO is separated in the CTRL
|
||||
// Port address space by 2^FIFO_ADDR_W bytes.
|
||||
localparam RAM_FIFO_ADDR_W = 7;
|
||||
|
||||
|
||||
// REG_FIFO_INFO (R|W)
|
||||
//
|
||||
// Contains info/control bits for the FIFO.
|
||||
//
|
||||
// [31:16] : Returns the magic number 0xF1F0 (read-only)
|
||||
// [0] : Indicates if BIST logic is present (read-only)
|
||||
//
|
||||
localparam REG_FIFO_INFO = 'h0;
|
||||
//
|
||||
localparam REG_FIFO_MAGIC_POS = 16;
|
||||
localparam REG_FIFO_BIST_PRSNT_POS = 0;
|
||||
//
|
||||
localparam REG_FIFO_MAGIC_W = 16;
|
||||
|
||||
|
||||
// REG_FIFO_READ_SUPPRESS (R|W)
|
||||
//
|
||||
// Controls the read suppression threshold. RAM reads will be disabled whenever
|
||||
// the amount of free space in the input buffer (in units of RAM words) falls
|
||||
// below this threshold. This is intended to prevent input buffer overflows
|
||||
// caused by the RAM being too busy with reads. To disable the read suppression
|
||||
// feature, set the threshold to 0. In general, the threshold should be set to
|
||||
// a small value relative to the input FIFO buffer size (the IN_FIFO_SIZE
|
||||
// field) so that it is only enabled when the input FIFO buffer is close to
|
||||
// overflowing.
|
||||
//
|
||||
|
||||
// [31:16] : Address width of input buffer. In other words, the input buffer is
|
||||
// 2**REG_FIFO_IN_FIFO_SIZE RAM words deep. (read-only)
|
||||
// [15: 0] : Read suppression threshold, in RAM words (read/write)
|
||||
//
|
||||
localparam REG_FIFO_READ_SUPPRESS = 'h4;
|
||||
//
|
||||
localparam REG_FIFO_IN_FIFO_SIZE_POS = 16;
|
||||
localparam REG_FIFO_SUPPRESS_THRESH_POS = 0;
|
||||
//
|
||||
localparam REG_FIFO_IN_FIFO_SIZE_W = 16;
|
||||
localparam REG_FIFO_SUPPRESS_THRESH_W = 16;
|
||||
|
||||
|
||||
// REG_FIFO_MEM_SIZE (R)
|
||||
//
|
||||
// Returns information about the size of the attached memory. The address size
|
||||
// allows software to determine what mask and base address values are valid.
|
||||
//
|
||||
// [31:16] : Returns the bit width of the RAM word size.
|
||||
// [15: 0] : Returns the bit width of the RAM byte address size. That is, the
|
||||
// addressable portion of the attached memory is
|
||||
// 2**REG_FIFO_ADDR_SIZE bytes.
|
||||
//
|
||||
localparam REG_FIFO_MEM_SIZE = 'h8;
|
||||
//
|
||||
localparam REG_FIFO_DATA_SIZE_POS = 16;
|
||||
localparam REG_FIFO_ADDR_SIZE_POS = 0;
|
||||
//
|
||||
localparam REG_FIFO_DATA_SIZE_W = 16;
|
||||
localparam REG_FIFO_ADDR_SIZE_W = 16;
|
||||
|
||||
|
||||
// REG_FIFO_TIMEOUT (R/W)
|
||||
//
|
||||
// Programs the FIFO timeout, in memory interface clock cycles. For efficiency,
|
||||
// we want the memory to read and write full bursts. But we also don't want
|
||||
// smaller amounts of data to be stuck in the FIFO. This timeout determines how
|
||||
// long we wait for new data before we go ahead and perform a smaller
|
||||
// read/write. A longer timeout will make more efficient use of the memory, but
|
||||
// will increase latency. The default value is set by a module parameter.
|
||||
//
|
||||
// [31:12] : <Reserved>
|
||||
// [11: 0] : Timeout
|
||||
//
|
||||
localparam REG_FIFO_TIMEOUT = 'hC;
|
||||
//
|
||||
localparam REG_TIMEOUT_POS = 0;
|
||||
localparam REG_TIMEOUT_W = 12;
|
||||
|
||||
|
||||
// REG_FIFO_FULLNESS (R)
|
||||
//
|
||||
// Returns the fullness of the FIFO in bytes. This is is a 64-bit register in
|
||||
// which the least-significant 32-bit word must be read first.
|
||||
//
|
||||
localparam REG_FIFO_FULLNESS_LO = 'h10;
|
||||
localparam REG_FIFO_FULLNESS_HI = 'h14;
|
||||
|
||||
|
||||
// REG_FIFO_ADDR_BASE (R|W)
|
||||
//
|
||||
// Sets the base byte address to use for this FIFO. This should only be updated
|
||||
// when the FIFO is idle. This should be set to a multiple of
|
||||
// REG_FIFO_ADDR_MASK+1. Depending on the size of the memory connected, upper
|
||||
// bits might be ignored.
|
||||
//
|
||||
localparam REG_FIFO_ADDR_BASE_LO = 'h18;
|
||||
localparam REG_FIFO_ADDR_BASE_HI = 'h1C;
|
||||
|
||||
|
||||
// REG_FIFO_ADDR_MASK (R|W)
|
||||
//
|
||||
// The byte address mask that controls the portion of the memory address that
|
||||
// is allocated to this FIFO. For example, set to 0xFFFF for a 64 KiB memory.
|
||||
//
|
||||
// This should only be updated when the FIFO is idle. It must be equal to a
|
||||
// power-of-2 minus 1. It should be no smaller than FIFO_ADDR_MASK_MIN, defined
|
||||
// in axi_ram_fifo.v, otherwise it will be coerced up to that size.
|
||||
//
|
||||
// This is is a 64-bit register in which the least-significant 32-bit word must
|
||||
// be read/written first. Depending on the size of the memory connected, the
|
||||
// upper bits might be ignored.
|
||||
//
|
||||
localparam REG_FIFO_ADDR_MASK_LO = 'h20;
|
||||
localparam REG_FIFO_ADDR_MASK_HI = 'h24;
|
||||
|
||||
|
||||
// REG_FIFO_PACKET_CNT (R)
|
||||
//
|
||||
// Returns the number of packets transferred out of the FIFO block.
|
||||
//
|
||||
localparam REG_FIFO_PACKET_CNT = 'h28;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BIST Registers
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Only read these registers if the BIST component is included.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// REG_BIST_CTRL (R|W)
|
||||
//
|
||||
// Control register for the BIST component.
|
||||
//
|
||||
// [4] : BIST is running. Changes to 1 after a test is started, then returns to
|
||||
// 0 when BIST is complete.
|
||||
//
|
||||
// [3] : Continuous mode (run until stopped). When set to 1, test will continue
|
||||
// to run until Stop bit is set.
|
||||
//
|
||||
// [2] : Clear the BIST counters (i.e., the TX, RX, cycle, and error counters)
|
||||
//
|
||||
// [1] : Stop BIST (strobe). Write a 1 to this bit to stop the test that is
|
||||
// currently running
|
||||
//
|
||||
// [0] : Start BIST (strobe). Write a 1 to this bit to start a test using the
|
||||
// configured NUM_BYTES and continuous mode setting.
|
||||
//
|
||||
localparam REG_BIST_CTRL = 'h30;
|
||||
//
|
||||
localparam REG_BIST_RUNNING_POS = 4;
|
||||
localparam REG_BIST_CONT_POS = 3;
|
||||
localparam REG_BIST_CLEAR_POS = 2; // Strobe
|
||||
localparam REG_BIST_STOP_POS = 1; // Strobe
|
||||
localparam REG_BIST_START_POS = 0; // Strobe
|
||||
|
||||
|
||||
// REG_BIST_CLOCK_RATE (R)
|
||||
//
|
||||
// Reports the clock rate of the BIST component in Hz. This can be used with
|
||||
// REG_BIST_CYCLE_COUNT to calculate throughput.
|
||||
//
|
||||
localparam REG_BIST_CLK_RATE = 'h34;
|
||||
|
||||
|
||||
// REG_BIST_NUM_BYTES (R|W)
|
||||
//
|
||||
// Number of bytes to generate for the next BIST run. THis is not used if the
|
||||
// REG_BIST_CONT_POS bit is set. This register should not be updated while the
|
||||
// BIST is running.
|
||||
//
|
||||
localparam REG_BIST_NUM_BYTES_LO = 'h38;
|
||||
localparam REG_BIST_NUM_BYTES_HI = 'h3C;
|
||||
|
||||
|
||||
// REG_BIST_TX_BYTE_COUNT (R)
|
||||
//
|
||||
// Reports the number of bytes transmitted by the BIST component. This should
|
||||
// always be read least-significant word first to ensure coherency. Once BIST
|
||||
// is complete, the TX count will equal the RX count.
|
||||
//
|
||||
localparam REG_BIST_TX_BYTE_COUNT_LO = 'h40;
|
||||
localparam REG_BIST_TX_BYTE_COUNT_HI = 'h44;
|
||||
|
||||
|
||||
// REG_BIST_RX_BYTE_COUNT (R)
|
||||
//
|
||||
// Reports the number of bytes received by the BIST component. This should
|
||||
// always be read least-significant word first to ensure coherency. Once BIST
|
||||
// is complete, the TX count will equal the RX count.
|
||||
//
|
||||
localparam REG_BIST_RX_BYTE_COUNT_LO = 'h48;
|
||||
localparam REG_BIST_RX_BYTE_COUNT_HI = 'h4C;
|
||||
|
||||
|
||||
// REG_BIST_ERROR_COUNT (R)
|
||||
//
|
||||
// Reports the number of words in which the BIST component detected errors.
|
||||
// This should always be read least-significant word first to ensure coherency.
|
||||
//
|
||||
localparam REG_BIST_ERROR_COUNT_LO = 'h50;
|
||||
localparam REG_BIST_ERROR_COUNT_HI = 'h54;
|
||||
|
||||
|
||||
// REG_BIST_CYCLE_COUNT (R)
|
||||
//
|
||||
// Reports the number of clock cycles that have elapsed while the BIST was
|
||||
// running. This can be used to calculate throughput. This should always be
|
||||
// read least-significant word first to ensure coherency.
|
||||
//
|
||||
localparam REG_BIST_CYCLE_COUNT_LO = 'h58;
|
||||
localparam REG_BIST_CYCLE_COUNT_HI = 'h5C;
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: noc_shell_axi_ram_fifo
|
||||
//
|
||||
// Description: A NoC Shell for the RFNoC AXI RAM FIFO. This NoC Shell
|
||||
// implements the control port interface but does nothing to the
|
||||
// data path other than moving it to the requested clock domain.
|
||||
//
|
||||
|
||||
`define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
|
||||
|
||||
|
||||
module noc_shell_axi_ram_fifo #(
|
||||
parameter [31:0] NOC_ID = 32'h0,
|
||||
parameter [ 9:0] THIS_PORTID = 10'd0,
|
||||
parameter CHDR_W = 64,
|
||||
parameter DATA_W = 64,
|
||||
parameter [ 5:0] CTRL_FIFO_SIZE = 0,
|
||||
parameter [ 0:0] CTRLPORT_MST_EN = 1,
|
||||
parameter [ 0:0] CTRLPORT_SLV_EN = 1,
|
||||
parameter [ 5:0] NUM_DATA_I = 1,
|
||||
parameter [ 5:0] NUM_DATA_O = 1,
|
||||
parameter [ 5:0] MTU = 10,
|
||||
parameter SYNC_DATA_CLOCKS = 0
|
||||
) (
|
||||
//---------------------------------------------------------------------------
|
||||
// Framework Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// RFNoC Framework Clocks and Resets
|
||||
input wire rfnoc_chdr_clk,
|
||||
output wire rfnoc_chdr_rst,
|
||||
input wire rfnoc_ctrl_clk,
|
||||
output wire rfnoc_ctrl_rst,
|
||||
// RFNoC Backend Interface
|
||||
input wire [ 511:0] rfnoc_core_config,
|
||||
output wire [ 511:0] rfnoc_core_status,
|
||||
// CHDR Input Ports (from framework)
|
||||
input wire [(CHDR_W*NUM_DATA_I)-1:0] s_rfnoc_chdr_tdata,
|
||||
input wire [ NUM_DATA_I-1:0] s_rfnoc_chdr_tlast,
|
||||
input wire [ NUM_DATA_I-1:0] s_rfnoc_chdr_tvalid,
|
||||
output wire [ NUM_DATA_I-1:0] s_rfnoc_chdr_tready,
|
||||
// CHDR Output Ports (to framework)
|
||||
output wire [(CHDR_W*NUM_DATA_O)-1:0] m_rfnoc_chdr_tdata,
|
||||
output wire [ NUM_DATA_O-1:0] m_rfnoc_chdr_tlast,
|
||||
output wire [ NUM_DATA_O-1:0] m_rfnoc_chdr_tvalid,
|
||||
input wire [ NUM_DATA_O-1:0] m_rfnoc_chdr_tready,
|
||||
// AXIS-Ctrl Input Port (from framework)
|
||||
input wire [ 31:0] s_rfnoc_ctrl_tdata,
|
||||
input wire s_rfnoc_ctrl_tlast,
|
||||
input wire s_rfnoc_ctrl_tvalid,
|
||||
output wire s_rfnoc_ctrl_tready,
|
||||
// AXIS-Ctrl Output Port (to framework)
|
||||
output wire [ 31:0] m_rfnoc_ctrl_tdata,
|
||||
output wire m_rfnoc_ctrl_tlast,
|
||||
output wire m_rfnoc_ctrl_tvalid,
|
||||
input wire m_rfnoc_ctrl_tready,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Client Control Port Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Clock
|
||||
input wire ctrlport_clk,
|
||||
input wire ctrlport_rst,
|
||||
// Master
|
||||
output wire m_ctrlport_req_wr,
|
||||
output wire m_ctrlport_req_rd,
|
||||
output wire [19:0] m_ctrlport_req_addr,
|
||||
output wire [31:0] m_ctrlport_req_data,
|
||||
output wire [ 3:0] m_ctrlport_req_byte_en,
|
||||
output wire m_ctrlport_req_has_time,
|
||||
output wire [63:0] m_ctrlport_req_time,
|
||||
input wire m_ctrlport_resp_ack,
|
||||
input wire [ 1:0] m_ctrlport_resp_status,
|
||||
input wire [31:0] m_ctrlport_resp_data,
|
||||
// Slave
|
||||
input wire s_ctrlport_req_wr,
|
||||
input wire s_ctrlport_req_rd,
|
||||
input wire [19:0] s_ctrlport_req_addr,
|
||||
input wire [ 9:0] s_ctrlport_req_portid,
|
||||
input wire [15:0] s_ctrlport_req_rem_epid,
|
||||
input wire [ 9:0] s_ctrlport_req_rem_portid,
|
||||
input wire [31:0] s_ctrlport_req_data,
|
||||
input wire [ 3:0] s_ctrlport_req_byte_en,
|
||||
input wire s_ctrlport_req_has_time,
|
||||
input wire [63:0] s_ctrlport_req_time,
|
||||
output wire s_ctrlport_resp_ack,
|
||||
output wire [ 1:0] s_ctrlport_resp_status,
|
||||
output wire [31:0] s_ctrlport_resp_data,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Client Data Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Clock
|
||||
input wire axis_data_clk,
|
||||
input wire axis_data_rst,
|
||||
|
||||
// Output data stream (to user logic)
|
||||
output wire [ (NUM_DATA_I*DATA_W)-1:0] m_axis_tdata,
|
||||
output wire [(NUM_DATA_I*`MAX(DATA_W/CHDR_W, 1))-1:0] m_axis_tkeep,
|
||||
output wire [ NUM_DATA_I-1:0] m_axis_tlast,
|
||||
output wire [ NUM_DATA_I-1:0] m_axis_tvalid,
|
||||
input wire [ NUM_DATA_I-1:0] m_axis_tready,
|
||||
|
||||
// Input data stream (from user logic)
|
||||
input wire [ (NUM_DATA_O*DATA_W)-1:0] s_axis_tdata,
|
||||
input wire [(NUM_DATA_O*`MAX(DATA_W/CHDR_W, 1))-1:0] s_axis_tkeep,
|
||||
input wire [ NUM_DATA_O-1:0] s_axis_tlast,
|
||||
input wire [ NUM_DATA_O-1:0] s_axis_tvalid,
|
||||
output wire [ NUM_DATA_O-1:0] s_axis_tready
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Backend Interface
|
||||
//---------------------------------------------------------------------------
|
||||
wire data_i_flush_en;
|
||||
wire [31:0] data_i_flush_timeout;
|
||||
wire [63:0] data_i_flush_active;
|
||||
wire [63:0] data_i_flush_done;
|
||||
wire data_o_flush_en;
|
||||
wire [31:0] data_o_flush_timeout;
|
||||
wire [63:0] data_o_flush_active;
|
||||
wire [63:0] data_o_flush_done;
|
||||
|
||||
backend_iface #(
|
||||
.NOC_ID (NOC_ID),
|
||||
.NUM_DATA_I (NUM_DATA_I),
|
||||
.NUM_DATA_O (NUM_DATA_O),
|
||||
.CTRL_FIFOSIZE (CTRL_FIFO_SIZE),
|
||||
.MTU (MTU)
|
||||
) backend_iface_i (
|
||||
.rfnoc_chdr_clk (rfnoc_chdr_clk),
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk),
|
||||
.rfnoc_core_config (rfnoc_core_config),
|
||||
.rfnoc_core_status (rfnoc_core_status),
|
||||
.rfnoc_chdr_rst (rfnoc_chdr_rst),
|
||||
.rfnoc_ctrl_rst (rfnoc_ctrl_rst),
|
||||
.data_i_flush_en (data_i_flush_en),
|
||||
.data_i_flush_timeout (data_i_flush_timeout),
|
||||
.data_i_flush_active (data_i_flush_active),
|
||||
.data_i_flush_done (data_i_flush_done),
|
||||
.data_o_flush_en (data_o_flush_en),
|
||||
.data_o_flush_timeout (data_o_flush_timeout),
|
||||
.data_o_flush_active (data_o_flush_active),
|
||||
.data_o_flush_done (data_o_flush_done)
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Control Path
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
ctrlport_endpoint #(
|
||||
.THIS_PORTID (THIS_PORTID ),
|
||||
.SYNC_CLKS (0 ),
|
||||
.AXIS_CTRL_MST_EN (CTRLPORT_SLV_EN),
|
||||
.AXIS_CTRL_SLV_EN (CTRLPORT_MST_EN),
|
||||
.SLAVE_FIFO_SIZE (CTRL_FIFO_SIZE )
|
||||
) ctrlport_ep_i (
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk ),
|
||||
.rfnoc_ctrl_rst (rfnoc_ctrl_rst ),
|
||||
.ctrlport_clk (ctrlport_clk ),
|
||||
.ctrlport_rst (ctrlport_rst ),
|
||||
.s_rfnoc_ctrl_tdata (s_rfnoc_ctrl_tdata ),
|
||||
.s_rfnoc_ctrl_tlast (s_rfnoc_ctrl_tlast ),
|
||||
.s_rfnoc_ctrl_tvalid (s_rfnoc_ctrl_tvalid ),
|
||||
.s_rfnoc_ctrl_tready (s_rfnoc_ctrl_tready ),
|
||||
.m_rfnoc_ctrl_tdata (m_rfnoc_ctrl_tdata ),
|
||||
.m_rfnoc_ctrl_tlast (m_rfnoc_ctrl_tlast ),
|
||||
.m_rfnoc_ctrl_tvalid (m_rfnoc_ctrl_tvalid ),
|
||||
.m_rfnoc_ctrl_tready (m_rfnoc_ctrl_tready ),
|
||||
.m_ctrlport_req_wr (m_ctrlport_req_wr ),
|
||||
.m_ctrlport_req_rd (m_ctrlport_req_rd ),
|
||||
.m_ctrlport_req_addr (m_ctrlport_req_addr ),
|
||||
.m_ctrlport_req_data (m_ctrlport_req_data ),
|
||||
.m_ctrlport_req_byte_en (m_ctrlport_req_byte_en ),
|
||||
.m_ctrlport_req_has_time (m_ctrlport_req_has_time ),
|
||||
.m_ctrlport_req_time (m_ctrlport_req_time ),
|
||||
.m_ctrlport_resp_ack (m_ctrlport_resp_ack ),
|
||||
.m_ctrlport_resp_status (m_ctrlport_resp_status ),
|
||||
.m_ctrlport_resp_data (m_ctrlport_resp_data ),
|
||||
.s_ctrlport_req_wr (s_ctrlport_req_wr ),
|
||||
.s_ctrlport_req_rd (s_ctrlport_req_rd ),
|
||||
.s_ctrlport_req_addr (s_ctrlport_req_addr ),
|
||||
.s_ctrlport_req_portid (s_ctrlport_req_portid ),
|
||||
.s_ctrlport_req_rem_epid (s_ctrlport_req_rem_epid ),
|
||||
.s_ctrlport_req_rem_portid(s_ctrlport_req_rem_portid),
|
||||
.s_ctrlport_req_data (s_ctrlport_req_data ),
|
||||
.s_ctrlport_req_byte_en (s_ctrlport_req_byte_en ),
|
||||
.s_ctrlport_req_has_time (s_ctrlport_req_has_time ),
|
||||
.s_ctrlport_req_time (s_ctrlport_req_time ),
|
||||
.s_ctrlport_resp_ack (s_ctrlport_resp_ack ),
|
||||
.s_ctrlport_resp_status (s_ctrlport_resp_status ),
|
||||
.s_ctrlport_resp_data (s_ctrlport_resp_data )
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Data Path
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Set WORD_W to the smaller of DATA_W and CHDR_W. This will be our common
|
||||
// word size between the CHDR and user data ports.
|
||||
localparam WORD_W = DATA_W < CHDR_W ? DATA_W : CHDR_W;
|
||||
localparam KEEP_W = `MAX(DATA_W/CHDR_W, 1);
|
||||
|
||||
genvar i;
|
||||
|
||||
for (i = 0; i < NUM_DATA_I; i = i + 1) begin : gen_in
|
||||
wire [CHDR_W-1:0] temp_in_tdata;
|
||||
wire temp_in_tlast;
|
||||
wire temp_in_tvalid;
|
||||
wire temp_in_tready;
|
||||
|
||||
axis_packet_flush #(
|
||||
.WIDTH (CHDR_W),
|
||||
.FLUSH_PARTIAL_PKTS (0),
|
||||
.TIMEOUT_W (32),
|
||||
.PIPELINE ("IN")
|
||||
) in_packet_flush_i (
|
||||
.clk (rfnoc_chdr_clk),
|
||||
.reset (rfnoc_chdr_rst),
|
||||
.enable (data_i_flush_en),
|
||||
.timeout (data_i_flush_timeout),
|
||||
.flushing (data_i_flush_active[i]),
|
||||
.done (data_i_flush_done[i]),
|
||||
.s_axis_tdata (s_rfnoc_chdr_tdata[i*CHDR_W +: CHDR_W]),
|
||||
.s_axis_tlast (s_rfnoc_chdr_tlast[i]),
|
||||
.s_axis_tvalid (s_rfnoc_chdr_tvalid[i]),
|
||||
.s_axis_tready (s_rfnoc_chdr_tready[i]),
|
||||
.m_axis_tdata (temp_in_tdata),
|
||||
.m_axis_tlast (temp_in_tlast),
|
||||
.m_axis_tvalid (temp_in_tvalid),
|
||||
.m_axis_tready (temp_in_tready)
|
||||
);
|
||||
|
||||
axis_width_conv #(
|
||||
.WORD_W (WORD_W),
|
||||
.IN_WORDS (CHDR_W/WORD_W),
|
||||
.OUT_WORDS (DATA_W/WORD_W),
|
||||
.SYNC_CLKS (SYNC_DATA_CLOCKS),
|
||||
.PIPELINE ("NONE")
|
||||
) in_width_conv_i (
|
||||
.s_axis_aclk (rfnoc_chdr_clk),
|
||||
.s_axis_rst (rfnoc_chdr_rst),
|
||||
.s_axis_tdata (temp_in_tdata),
|
||||
.s_axis_tkeep ({CHDR_W/WORD_W{1'b1}}),
|
||||
.s_axis_tlast (temp_in_tlast),
|
||||
.s_axis_tvalid (temp_in_tvalid),
|
||||
.s_axis_tready (temp_in_tready),
|
||||
.m_axis_aclk (axis_data_clk),
|
||||
.m_axis_rst (axis_data_rst),
|
||||
.m_axis_tdata (m_axis_tdata[i*DATA_W +: DATA_W]),
|
||||
.m_axis_tkeep (m_axis_tkeep[i*KEEP_W +: KEEP_W]),
|
||||
.m_axis_tlast (m_axis_tlast[i]),
|
||||
.m_axis_tvalid (m_axis_tvalid[i]),
|
||||
.m_axis_tready (m_axis_tready[i])
|
||||
);
|
||||
end
|
||||
|
||||
|
||||
for (i = 0; i < NUM_DATA_O; i = i + 1) begin : gen_out
|
||||
wire [ CHDR_W-1:0] temp_out_tdata;
|
||||
wire [CHDR_W/WORD_W-1:0] temp_out_tkeep;
|
||||
wire temp_out_tlast;
|
||||
wire temp_out_tvalid;
|
||||
wire temp_out_tready;
|
||||
|
||||
axis_width_conv #(
|
||||
.WORD_W (WORD_W),
|
||||
.IN_WORDS (DATA_W/WORD_W),
|
||||
.OUT_WORDS (CHDR_W/WORD_W),
|
||||
.SYNC_CLKS (SYNC_DATA_CLOCKS),
|
||||
.PIPELINE ("NONE")
|
||||
) out_width_conv_i (
|
||||
.s_axis_aclk (axis_data_clk),
|
||||
.s_axis_rst (axis_data_rst),
|
||||
.s_axis_tdata (s_axis_tdata[i*DATA_W +: DATA_W]),
|
||||
.s_axis_tkeep (s_axis_tkeep[i*KEEP_W +: KEEP_W]),
|
||||
.s_axis_tlast (s_axis_tlast[i]),
|
||||
.s_axis_tvalid (s_axis_tvalid[i]),
|
||||
.s_axis_tready (s_axis_tready[i]),
|
||||
.m_axis_aclk (rfnoc_chdr_clk),
|
||||
.m_axis_rst (rfnoc_chdr_rst),
|
||||
.m_axis_tdata (temp_out_tdata),
|
||||
.m_axis_tkeep (),
|
||||
.m_axis_tlast (temp_out_tlast),
|
||||
.m_axis_tvalid (temp_out_tvalid),
|
||||
.m_axis_tready (temp_out_tready)
|
||||
);
|
||||
|
||||
axis_packet_flush #(
|
||||
.WIDTH (CHDR_W),
|
||||
.FLUSH_PARTIAL_PKTS (0),
|
||||
.TIMEOUT_W (32),
|
||||
.PIPELINE ("OUT")
|
||||
) out_packet_flush_i (
|
||||
.clk (rfnoc_chdr_clk),
|
||||
.reset (rfnoc_chdr_rst),
|
||||
.enable (data_o_flush_en),
|
||||
.timeout (data_o_flush_timeout),
|
||||
.flushing (data_o_flush_active[i]),
|
||||
.done (data_o_flush_done[i]),
|
||||
.s_axis_tdata (temp_out_tdata),
|
||||
.s_axis_tlast (temp_out_tlast),
|
||||
.s_axis_tvalid (temp_out_tvalid),
|
||||
.s_axis_tready (temp_out_tready),
|
||||
.m_axis_tdata (m_rfnoc_chdr_tdata[i*CHDR_W +: CHDR_W]),
|
||||
.m_axis_tlast (m_rfnoc_chdr_tlast[i]),
|
||||
.m_axis_tvalid (m_rfnoc_chdr_tvalid[i]),
|
||||
.m_axis_tready (m_rfnoc_chdr_tready[i])
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,485 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rfnoc_block_axi_ram_fifo
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Implements a FIFO using an AXI memory-mapped interface to an external
|
||||
// memory.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// THIS_PORTID : Control crossbar port to which this block is connected
|
||||
//
|
||||
// CHDR_W : CHDR AXI-Stream data bus width
|
||||
//
|
||||
// NUM_PORTS : Number of independent FIFOs to support, all sharing the
|
||||
// same memory.
|
||||
//
|
||||
// MTU : Maximum transfer unit (maximum packet size) to support,
|
||||
// in CHDR_W-sized words.
|
||||
//
|
||||
// MEM_DATA_W : Width of the data bus to use for the AXI memory-mapped
|
||||
// interface. This must be no bigger than CHDR_W and it must
|
||||
// evenly divide CHDR_W.
|
||||
//
|
||||
// MEM_ADDR_W : Width of the byte address to use for RAM addressing. This
|
||||
// effectively sets the maximum combined size of all FIFOs.
|
||||
// This must be less than or equal to AWIDTH.
|
||||
//
|
||||
// AWIDTH : Width of the address bus for the AXI memory-mapped
|
||||
// interface. This must be at least as big as MEM_DATA_W.
|
||||
//
|
||||
// FIFO_ADDR_BASE : Default base byte address of each FIFO. When NUM_PORTS >
|
||||
// 1, this should be the concatenation of all the FIFO base
|
||||
// addresses. These values can be reconfigured by software.
|
||||
//
|
||||
// FIFO_ADDR_MASK : Default byte address mask used by each FIFO. It must be
|
||||
// all ones. The size of the FIFO in bytes will be this
|
||||
// minus one. These values can be reconfigured by software.
|
||||
//
|
||||
// BURST_TIMEOUT : Default number of memory clock cycles to wait for new
|
||||
// data before performing a short, sub-optimal burst. One
|
||||
// value per FIFO.
|
||||
//
|
||||
// IN_FIFO_SIZE : Size of the input buffer. This is used to mitigate the
|
||||
// effects of memory write latency, which can be significant
|
||||
// when the external memory is DRAM.
|
||||
//
|
||||
// OUT_FIFO_SIZE : Size of the output buffer. This is used to mitigate the
|
||||
// effects of memory read latency, which can be significant
|
||||
// when the external memory is DRAM.
|
||||
//
|
||||
// BIST : Includes BIST logic when true.
|
||||
//
|
||||
// MEM_CLK_RATE : Frequency of mem_clk in Hz. This is used by BIST for
|
||||
// throughput calculation.
|
||||
//
|
||||
|
||||
module rfnoc_block_axi_ram_fifo #(
|
||||
parameter THIS_PORTID = 0,
|
||||
parameter CHDR_W = 64,
|
||||
parameter NUM_PORTS = 1,
|
||||
parameter MTU = 10,
|
||||
parameter MEM_DATA_W = CHDR_W,
|
||||
parameter MEM_ADDR_W = 32,
|
||||
parameter AWIDTH = 32,
|
||||
parameter [NUM_PORTS*MEM_ADDR_W-1:0] FIFO_ADDR_BASE = {NUM_PORTS{ {MEM_ADDR_W{1'b0}} }},
|
||||
parameter [NUM_PORTS*MEM_ADDR_W-1:0] FIFO_ADDR_MASK = {NUM_PORTS{ {(MEM_ADDR_W-$clog2(NUM_PORTS)){1'b1}} }},
|
||||
parameter [ NUM_PORTS*32-1:0] BURST_TIMEOUT = {NUM_PORTS{ 32'd256 }},
|
||||
parameter IN_FIFO_SIZE = 11,
|
||||
parameter OUT_FIFO_SIZE = 11,
|
||||
parameter BIST = 1,
|
||||
parameter MEM_CLK_RATE = 200e6
|
||||
) (
|
||||
//---------------------------------------------------------------------------
|
||||
// AXIS CHDR Port
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
input wire rfnoc_chdr_clk,
|
||||
|
||||
// CHDR inputs from framework
|
||||
input wire [NUM_PORTS*CHDR_W-1:0] s_rfnoc_chdr_tdata,
|
||||
input wire [ NUM_PORTS-1:0] s_rfnoc_chdr_tlast,
|
||||
input wire [ NUM_PORTS-1:0] s_rfnoc_chdr_tvalid,
|
||||
output wire [ NUM_PORTS-1:0] s_rfnoc_chdr_tready,
|
||||
|
||||
// CHDR outputs to framework
|
||||
output wire [NUM_PORTS*CHDR_W-1:0] m_rfnoc_chdr_tdata,
|
||||
output wire [ NUM_PORTS-1:0] m_rfnoc_chdr_tlast,
|
||||
output wire [ NUM_PORTS-1:0] m_rfnoc_chdr_tvalid,
|
||||
input wire [ NUM_PORTS-1:0] m_rfnoc_chdr_tready,
|
||||
|
||||
// Backend interface
|
||||
input wire [511:0] rfnoc_core_config,
|
||||
output wire [511:0] rfnoc_core_status,
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// AXIS CTRL Port
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
input wire rfnoc_ctrl_clk,
|
||||
|
||||
// CTRL port requests from framework
|
||||
input wire [31:0] s_rfnoc_ctrl_tdata,
|
||||
input wire s_rfnoc_ctrl_tlast,
|
||||
input wire s_rfnoc_ctrl_tvalid,
|
||||
output wire s_rfnoc_ctrl_tready,
|
||||
|
||||
// CTRL port requests to framework
|
||||
output wire [31:0] m_rfnoc_ctrl_tdata,
|
||||
output wire m_rfnoc_ctrl_tlast,
|
||||
output wire m_rfnoc_ctrl_tvalid,
|
||||
input wire m_rfnoc_ctrl_tready,
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// AXI Memory Mapped Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// AXI Interface Clock and Reset
|
||||
input wire mem_clk,
|
||||
input wire axi_rst,
|
||||
|
||||
// AXI Write Address Channel
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_awid, // Write address ID. This signal is the identification tag for the write address signals
|
||||
output wire [ NUM_PORTS*AWIDTH-1:0] m_axi_awaddr, // Write address. The write address gives the address of the first transfer in a write burst
|
||||
output wire [ NUM_PORTS*8-1:0] m_axi_awlen, // Burst length. The burst length gives the exact number of transfers in a burst.
|
||||
output wire [ NUM_PORTS*3-1:0] m_axi_awsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||
output wire [ NUM_PORTS*2-1:0] m_axi_awburst, // Burst type. The burst type and the size information, determine how the address is calculated
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_awlock, // Lock type. Provides additional information about the atomic characteristics of the transfer.
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_awcache, // Memory type. This signal indicates how transactions are required to progress
|
||||
output wire [ NUM_PORTS*3-1:0] m_axi_awprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_awqos, // Quality of Service, QoS. The QoS identifier sent for each write transaction
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_awregion, // Region identifier. Permits a single physical interface on a slave to be re-used.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_awuser, // User signal. Optional User-defined signal in the write address channel.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_awvalid, // Write address valid. This signal indicates that the channel is signaling valid write addr
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_awready, // Write address ready. This signal indicates that the slave is ready to accept an address
|
||||
|
||||
// AXI Write Data Channel
|
||||
output wire [ NUM_PORTS*MEM_DATA_W-1:0] m_axi_wdata, // Write data
|
||||
output wire [NUM_PORTS*MEM_DATA_W/8-1:0] m_axi_wstrb, // Write strobes. This signal indicates which byte lanes hold valid data.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_wlast, // Write last. This signal indicates the last transfer in a write burst
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_wuser, // User signal. Optional User-defined signal in the write data channel.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_wvalid, // Write valid. This signal indicates that valid write data and strobes are available.
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_wready, // Write ready. This signal indicates that the slave can accept the write data.
|
||||
|
||||
// AXI Write Response Channel
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_bid, // Response ID tag. This signal is the ID tag of the write response.
|
||||
input wire [ NUM_PORTS*2-1:0] m_axi_bresp, // Write response. This signal indicates the status of the write transaction.
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_buser, // User signal. Optional User-defined signal in the write response channel.
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_bvalid, // Write response valid. This signal indicates that the channel is signaling a valid response
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_bready, // Response ready. This signal indicates that the master can accept a write response
|
||||
|
||||
// AXI Read Address Channel
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_arid, // Read address ID. This signal is the identification tag for the read address group of signals
|
||||
output wire [ NUM_PORTS*AWIDTH-1:0] m_axi_araddr, // Read address. The read address gives the address of the first transfer in a read burst
|
||||
output wire [ NUM_PORTS*8-1:0] m_axi_arlen, // Burst length. This signal indicates the exact number of transfers in a burst.
|
||||
output wire [ NUM_PORTS*3-1:0] m_axi_arsize, // Burst size. This signal indicates the size of each transfer in the burst.
|
||||
output wire [ NUM_PORTS*2-1:0] m_axi_arburst, // Burst type. The burst type and the size information determine how the address for each transfer
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_arlock, // Lock type. This signal provides additional information about the atomic characteristics
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_arcache, // Memory type. This signal indicates how transactions are required to progress
|
||||
output wire [ NUM_PORTS*3-1:0] m_axi_arprot, // Protection type. This signal indicates the privilege and security level of the transaction
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_arqos, // Quality of Service, QoS. QoS identifier sent for each read transaction.
|
||||
output wire [ NUM_PORTS*4-1:0] m_axi_arregion, // Region identifier. Permits a single physical interface on a slave to be re-used
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_aruser, // User signal. Optional User-defined signal in the read address channel.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_arvalid, // Read address valid. This signal indicates that the channel is signaling valid read addr
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_arready, // Read address ready. This signal indicates that the slave is ready to accept an address
|
||||
|
||||
// AXI Read Data Channel
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_rid, // Read ID tag. This signal is the identification tag for the read data group of signals
|
||||
input wire [NUM_PORTS*MEM_DATA_W-1:0] m_axi_rdata, // Read data.
|
||||
input wire [ NUM_PORTS*2-1:0] m_axi_rresp, // Read response. This signal indicates the status of the read transfer
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_rlast, // Read last. This signal indicates the last transfer in a read burst.
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_ruser, // User signal. Optional User-defined signal in the read data channel.
|
||||
input wire [ NUM_PORTS*1-1:0] m_axi_rvalid, // Read valid. This signal indicates that the channel is signaling the required read data.
|
||||
output wire [ NUM_PORTS*1-1:0] m_axi_rready // Read ready. This signal indicates that the master can accept the read data and response
|
||||
);
|
||||
|
||||
`include "axi_ram_fifo_regs.vh"
|
||||
|
||||
localparam NOC_ID = 'hF1F0_0000;
|
||||
|
||||
// If the memory width is larger than the CHDR width, then we need to use
|
||||
// tkeep to track which CHDR words are valid as they go through the FIFO.
|
||||
// Calculate the TKEEP width here. Set to 1 if it's not needed.
|
||||
localparam KEEP_W = (MEM_DATA_W/CHDR_W) > 1 ? (MEM_DATA_W/CHDR_W) : 1;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Parameter Checks
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
if (CHDR_W % MEM_DATA_W != 0 && MEM_DATA_W % CHDR_W != 0)
|
||||
CHDR_W_must_be_a_multiple_of_MEM_DATA_W_or_vice_versa();
|
||||
|
||||
if (MEM_ADDR_W > AWIDTH)
|
||||
MEM_ADDR_W_must_be_greater_than_AWIDTH();
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// NoC Shell
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire rfnoc_chdr_rst;
|
||||
|
||||
wire ctrlport_req_wr;
|
||||
wire ctrlport_req_rd;
|
||||
wire [19:0] ctrlport_req_addr;
|
||||
wire [31:0] ctrlport_req_data;
|
||||
wire ctrlport_resp_ack;
|
||||
wire [31:0] ctrlport_resp_data;
|
||||
|
||||
wire [NUM_PORTS*MEM_DATA_W-1:0] m_axis_data_tdata;
|
||||
wire [ NUM_PORTS*KEEP_W-1:0] m_axis_data_tkeep;
|
||||
wire [ NUM_PORTS-1:0] m_axis_data_tlast;
|
||||
wire [ NUM_PORTS-1:0] m_axis_data_tvalid;
|
||||
wire [ NUM_PORTS-1:0] m_axis_data_tready;
|
||||
|
||||
wire [NUM_PORTS*MEM_DATA_W-1:0] s_axis_data_tdata;
|
||||
wire [ NUM_PORTS*KEEP_W-1:0] s_axis_data_tkeep;
|
||||
wire [ NUM_PORTS-1:0] s_axis_data_tlast;
|
||||
wire [ NUM_PORTS-1:0] s_axis_data_tvalid;
|
||||
wire [ NUM_PORTS-1:0] s_axis_data_tready;
|
||||
|
||||
noc_shell_axi_ram_fifo #(
|
||||
.NOC_ID (NOC_ID),
|
||||
.THIS_PORTID (THIS_PORTID),
|
||||
.CHDR_W (CHDR_W),
|
||||
.DATA_W (MEM_DATA_W),
|
||||
.CTRL_FIFO_SIZE (5),
|
||||
.CTRLPORT_MST_EN (1),
|
||||
.CTRLPORT_SLV_EN (0),
|
||||
.NUM_DATA_I (NUM_PORTS),
|
||||
.NUM_DATA_O (NUM_PORTS),
|
||||
.MTU (MTU),
|
||||
.SYNC_DATA_CLOCKS (0)
|
||||
) noc_shell_axi_ram_fifo_i (
|
||||
.rfnoc_chdr_clk (rfnoc_chdr_clk),
|
||||
.rfnoc_chdr_rst (rfnoc_chdr_rst),
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk),
|
||||
.rfnoc_ctrl_rst (),
|
||||
.rfnoc_core_config (rfnoc_core_config),
|
||||
.rfnoc_core_status (rfnoc_core_status),
|
||||
.s_rfnoc_chdr_tdata (s_rfnoc_chdr_tdata),
|
||||
.s_rfnoc_chdr_tlast (s_rfnoc_chdr_tlast),
|
||||
.s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid),
|
||||
.s_rfnoc_chdr_tready (s_rfnoc_chdr_tready),
|
||||
.m_rfnoc_chdr_tdata (m_rfnoc_chdr_tdata),
|
||||
.m_rfnoc_chdr_tlast (m_rfnoc_chdr_tlast),
|
||||
.m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid),
|
||||
.m_rfnoc_chdr_tready (m_rfnoc_chdr_tready),
|
||||
.s_rfnoc_ctrl_tdata (s_rfnoc_ctrl_tdata),
|
||||
.s_rfnoc_ctrl_tlast (s_rfnoc_ctrl_tlast),
|
||||
.s_rfnoc_ctrl_tvalid (s_rfnoc_ctrl_tvalid),
|
||||
.s_rfnoc_ctrl_tready (s_rfnoc_ctrl_tready),
|
||||
.m_rfnoc_ctrl_tdata (m_rfnoc_ctrl_tdata),
|
||||
.m_rfnoc_ctrl_tlast (m_rfnoc_ctrl_tlast),
|
||||
.m_rfnoc_ctrl_tvalid (m_rfnoc_ctrl_tvalid),
|
||||
.m_rfnoc_ctrl_tready (m_rfnoc_ctrl_tready),
|
||||
.ctrlport_clk (mem_clk),
|
||||
.ctrlport_rst (axi_rst),
|
||||
.m_ctrlport_req_wr (ctrlport_req_wr),
|
||||
.m_ctrlport_req_rd (ctrlport_req_rd),
|
||||
.m_ctrlport_req_addr (ctrlport_req_addr),
|
||||
.m_ctrlport_req_data (ctrlport_req_data),
|
||||
.m_ctrlport_req_byte_en (),
|
||||
.m_ctrlport_req_has_time (),
|
||||
.m_ctrlport_req_time (),
|
||||
.m_ctrlport_resp_ack (ctrlport_resp_ack),
|
||||
.m_ctrlport_resp_status (2'b0),
|
||||
.m_ctrlport_resp_data (ctrlport_resp_data),
|
||||
.s_ctrlport_req_wr (1'b0),
|
||||
.s_ctrlport_req_rd (1'b0),
|
||||
.s_ctrlport_req_addr (20'b0),
|
||||
.s_ctrlport_req_portid (10'b0),
|
||||
.s_ctrlport_req_rem_epid (16'b0),
|
||||
.s_ctrlport_req_rem_portid (10'b0),
|
||||
.s_ctrlport_req_data (32'b0),
|
||||
.s_ctrlport_req_byte_en (4'b0),
|
||||
.s_ctrlport_req_has_time (1'b0),
|
||||
.s_ctrlport_req_time (64'b0),
|
||||
.s_ctrlport_resp_ack (),
|
||||
.s_ctrlport_resp_status (),
|
||||
.s_ctrlport_resp_data (),
|
||||
.axis_data_clk (mem_clk),
|
||||
.axis_data_rst (axi_rst),
|
||||
.m_axis_tdata (m_axis_data_tdata),
|
||||
.m_axis_tkeep (m_axis_data_tkeep),
|
||||
.m_axis_tlast (m_axis_data_tlast),
|
||||
.m_axis_tvalid (m_axis_data_tvalid),
|
||||
.m_axis_tready (m_axis_data_tready),
|
||||
.s_axis_tdata (s_axis_data_tdata),
|
||||
.s_axis_tkeep (s_axis_data_tkeep),
|
||||
.s_axis_tlast (s_axis_data_tlast),
|
||||
.s_axis_tvalid (s_axis_data_tvalid),
|
||||
.s_axis_tready (s_axis_data_tready)
|
||||
);
|
||||
|
||||
wire rfnoc_chdr_rst_mem_clk;
|
||||
reg mem_rst_block;
|
||||
|
||||
// Cross the CHDR reset to the mem_clk domain
|
||||
pulse_synchronizer #(
|
||||
.MODE ("POSEDGE")
|
||||
) ctrl_rst_sync_i (
|
||||
.clk_a (rfnoc_chdr_clk),
|
||||
.rst_a (1'b0),
|
||||
.pulse_a (rfnoc_chdr_rst),
|
||||
.busy_a (),
|
||||
.clk_b (mem_clk),
|
||||
.pulse_b (rfnoc_chdr_rst_mem_clk)
|
||||
);
|
||||
|
||||
// Combine the resets in a glitch-free manner
|
||||
always @(posedge mem_clk) begin
|
||||
mem_rst_block <= axi_rst | rfnoc_chdr_rst_mem_clk;
|
||||
end
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// CTRL Port Splitter
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire [ NUM_PORTS-1:0] m_ctrlport_req_wr;
|
||||
wire [ NUM_PORTS-1:0] m_ctrlport_req_rd;
|
||||
wire [20*NUM_PORTS-1:0] m_ctrlport_req_addr;
|
||||
wire [32*NUM_PORTS-1:0] m_ctrlport_req_data;
|
||||
wire [ NUM_PORTS-1:0] m_ctrlport_resp_ack;
|
||||
wire [32*NUM_PORTS-1:0] m_ctrlport_resp_data;
|
||||
|
||||
ctrlport_decoder #(
|
||||
.NUM_SLAVES (NUM_PORTS),
|
||||
.BASE_ADDR (0),
|
||||
.SLAVE_ADDR_W (RAM_FIFO_ADDR_W)
|
||||
) ctrlport_splitter_i (
|
||||
.ctrlport_clk (mem_clk),
|
||||
.ctrlport_rst (mem_rst_block),
|
||||
.s_ctrlport_req_wr (ctrlport_req_wr),
|
||||
.s_ctrlport_req_rd (ctrlport_req_rd),
|
||||
.s_ctrlport_req_addr (ctrlport_req_addr),
|
||||
.s_ctrlport_req_data (ctrlport_req_data),
|
||||
.s_ctrlport_req_byte_en (4'b1111),
|
||||
.s_ctrlport_req_has_time (1'b0),
|
||||
.s_ctrlport_req_time (64'b0),
|
||||
.s_ctrlport_resp_ack (ctrlport_resp_ack),
|
||||
.s_ctrlport_resp_status (),
|
||||
.s_ctrlport_resp_data (ctrlport_resp_data),
|
||||
.m_ctrlport_req_wr (m_ctrlport_req_wr),
|
||||
.m_ctrlport_req_rd (m_ctrlport_req_rd),
|
||||
.m_ctrlport_req_addr (m_ctrlport_req_addr),
|
||||
.m_ctrlport_req_data (m_ctrlport_req_data),
|
||||
.m_ctrlport_req_byte_en (),
|
||||
.m_ctrlport_req_has_time (),
|
||||
.m_ctrlport_req_time (),
|
||||
.m_ctrlport_resp_ack (m_ctrlport_resp_ack),
|
||||
.m_ctrlport_resp_status ({NUM_PORTS*2{1'b0}}),
|
||||
.m_ctrlport_resp_data (m_ctrlport_resp_data)
|
||||
);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// FIFO Instances
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
genvar i;
|
||||
for (i = 0; i < NUM_PORTS; i = i + 1) begin : gen_ram_fifos
|
||||
|
||||
wire [MEM_ADDR_W-1:0] m_axi_awaddr_int;
|
||||
wire [MEM_ADDR_W-1:0] m_axi_araddr_int;
|
||||
|
||||
// Resize the addresses from MEM_ADDR_W to AWIDTH
|
||||
assign m_axi_awaddr[(AWIDTH*(i+1))-1:AWIDTH*i] = m_axi_awaddr_int;
|
||||
assign m_axi_araddr[(AWIDTH*(i+1))-1:AWIDTH*i] = m_axi_araddr_int;
|
||||
|
||||
axi_ram_fifo #(
|
||||
.MEM_ADDR_W (MEM_ADDR_W),
|
||||
.MEM_DATA_W (MEM_DATA_W),
|
||||
.KEEP_W (KEEP_W),
|
||||
.FIFO_ADDR_BASE (FIFO_ADDR_BASE[MEM_ADDR_W*i +: MEM_ADDR_W]),
|
||||
.FIFO_ADDR_MASK (FIFO_ADDR_MASK[MEM_ADDR_W*i +: MEM_ADDR_W]),
|
||||
.BURST_TIMEOUT (BURST_TIMEOUT[32*i +: 32]),
|
||||
.BIST (BIST),
|
||||
.CLK_RATE (MEM_CLK_RATE),
|
||||
.IN_FIFO_SIZE (IN_FIFO_SIZE),
|
||||
.OUT_FIFO_SIZE (OUT_FIFO_SIZE)
|
||||
) axi_ram_fifo_i (
|
||||
|
||||
.clk(mem_clk),
|
||||
.rst(mem_rst_block),
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Control Port
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
.s_ctrlport_req_wr (m_ctrlport_req_wr[i]),
|
||||
.s_ctrlport_req_rd (m_ctrlport_req_rd[i]),
|
||||
.s_ctrlport_req_addr (m_ctrlport_req_addr[20*i +: 20]),
|
||||
.s_ctrlport_req_data (m_ctrlport_req_data[32*i +: 32]),
|
||||
.s_ctrlport_resp_ack (m_ctrlport_resp_ack[i]),
|
||||
.s_ctrlport_resp_data (m_ctrlport_resp_data[32*i +: 32]),
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// AXI-Stream FIFO Interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// AXI-Stream Input
|
||||
.s_tdata (m_axis_data_tdata[MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.s_tkeep (m_axis_data_tkeep[KEEP_W*i +: KEEP_W]),
|
||||
.s_tlast (m_axis_data_tlast[i]),
|
||||
.s_tvalid (m_axis_data_tvalid[i]),
|
||||
.s_tready (m_axis_data_tready[i]),
|
||||
//
|
||||
// AXI-Stream Output
|
||||
.m_tdata (s_axis_data_tdata[MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.m_tkeep (s_axis_data_tkeep[KEEP_W*i +: KEEP_W]),
|
||||
.m_tlast (s_axis_data_tlast[i]),
|
||||
.m_tvalid (s_axis_data_tvalid[i]),
|
||||
.m_tready (s_axis_data_tready[i]),
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// AXI4 Memory Interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// AXI Write address channel
|
||||
.m_axi_awid (m_axi_awid[i]),
|
||||
.m_axi_awaddr (m_axi_awaddr_int),
|
||||
.m_axi_awlen (m_axi_awlen[(8*(i+1))-1:8*i]),
|
||||
.m_axi_awsize (m_axi_awsize[(3*(i+1))-1:3*i]),
|
||||
.m_axi_awburst (m_axi_awburst[(2*(i+1))-1:2*i]),
|
||||
.m_axi_awlock (m_axi_awlock[i]),
|
||||
.m_axi_awcache (m_axi_awcache[(4*(i+1))-1:4*i]),
|
||||
.m_axi_awprot (m_axi_awprot[(3*(i+1))-1:3*i]),
|
||||
.m_axi_awqos (m_axi_awqos[(4*(i+1))-1:4*i]),
|
||||
.m_axi_awregion (m_axi_awregion[(4*(i+1))-1:4*i]),
|
||||
.m_axi_awuser (m_axi_awuser[i]),
|
||||
.m_axi_awvalid (m_axi_awvalid[i]),
|
||||
.m_axi_awready (m_axi_awready[i]),
|
||||
//
|
||||
// AXI Write data channel.
|
||||
.m_axi_wdata (m_axi_wdata[(MEM_DATA_W*(i+1))-1:MEM_DATA_W*i]),
|
||||
.m_axi_wstrb (m_axi_wstrb[((MEM_DATA_W/8)*(i+1))-1:(MEM_DATA_W/8)*i]),
|
||||
.m_axi_wlast (m_axi_wlast[i]),
|
||||
.m_axi_wuser (m_axi_wuser[i]),
|
||||
.m_axi_wvalid (m_axi_wvalid[i]),
|
||||
.m_axi_wready (m_axi_wready[i]),
|
||||
//
|
||||
// AXI Write response channel signals
|
||||
.m_axi_bid (m_axi_bid[i]),
|
||||
.m_axi_bresp (m_axi_bresp[(2*(i+1))-1:2*i]),
|
||||
.m_axi_buser (m_axi_buser[i]),
|
||||
.m_axi_bvalid (m_axi_bvalid[i]),
|
||||
.m_axi_bready (m_axi_bready[i]),
|
||||
//
|
||||
// AXI Read address channel
|
||||
.m_axi_arid (m_axi_arid[i]),
|
||||
.m_axi_araddr (m_axi_araddr_int),
|
||||
.m_axi_arlen (m_axi_arlen[(8*(i+1))-1:8*i]),
|
||||
.m_axi_arsize (m_axi_arsize[(3*(i+1))-1:3*i]),
|
||||
.m_axi_arburst (m_axi_arburst[(2*(i+1))-1:2*i]),
|
||||
.m_axi_arlock (m_axi_arlock[i]),
|
||||
.m_axi_arcache (m_axi_arcache[(4*(i+1))-1:4*i]),
|
||||
.m_axi_arprot (m_axi_arprot[(3*(i+1))-1:3*i]),
|
||||
.m_axi_arqos (m_axi_arqos[(4*(i+1))-1:4*i]),
|
||||
.m_axi_arregion (m_axi_arregion[(4*(i+1))-1:4*i]),
|
||||
.m_axi_aruser (m_axi_aruser[i]),
|
||||
.m_axi_arvalid (m_axi_arvalid[i]),
|
||||
.m_axi_arready (m_axi_arready[i]),
|
||||
//
|
||||
// AXI Read data channel
|
||||
.m_axi_rid (m_axi_rid[i]),
|
||||
.m_axi_rdata (m_axi_rdata[(MEM_DATA_W*(i+1))-1:MEM_DATA_W*i]),
|
||||
.m_axi_rresp (m_axi_rresp[(2*(i+1))-1:2*i]),
|
||||
.m_axi_rlast (m_axi_rlast[i]),
|
||||
.m_axi_ruser (m_axi_ruser[i]),
|
||||
.m_axi_rvalid (m_axi_rvalid[i]),
|
||||
.m_axi_rready (m_axi_rready[i])
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rfnoc_block_axi_ram_fifo_all_tb
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This is the testbench for rfnoc_block_axi_ram_fifo that instantiates
|
||||
// several variations of rfnoc_block_axi_ram_fifo_tb to test different
|
||||
// configurations.
|
||||
//
|
||||
|
||||
|
||||
module rfnoc_block_axi_ram_fifo_all_tb;
|
||||
|
||||
timeunit 1ns;
|
||||
timeprecision 1ps;
|
||||
|
||||
import PkgTestExec::*;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Test Definitions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
int CHDR_W;
|
||||
int NUM_PORTS;
|
||||
int MEM_DATA_W;
|
||||
int MEM_ADDR_W;
|
||||
int FIFO_ADDR_W;
|
||||
int IN_FIFO_SIZE;
|
||||
int OUT_FIFO_SIZE;
|
||||
bit OVERFLOW;
|
||||
bit BIST;
|
||||
} test_config_t;
|
||||
|
||||
localparam NUM_TESTS = 4;
|
||||
|
||||
localparam test_config_t test[NUM_TESTS] = '{
|
||||
'{CHDR_W: 64, NUM_PORTS: 2, MEM_DATA_W: 64, MEM_ADDR_W: 13, FIFO_ADDR_W: 12, IN_FIFO_SIZE: 9, OUT_FIFO_SIZE: 9, OVERFLOW: 1, BIST: 1 },
|
||||
'{CHDR_W: 64, NUM_PORTS: 1, MEM_DATA_W: 128, MEM_ADDR_W: 14, FIFO_ADDR_W: 13, IN_FIFO_SIZE: 9, OUT_FIFO_SIZE: 9, OVERFLOW: 1, BIST: 1 },
|
||||
'{CHDR_W: 128, NUM_PORTS: 1, MEM_DATA_W: 64, MEM_ADDR_W: 13, FIFO_ADDR_W: 12, IN_FIFO_SIZE: 9, OUT_FIFO_SIZE: 10, OVERFLOW: 0, BIST: 1 },
|
||||
'{CHDR_W: 128, NUM_PORTS: 1, MEM_DATA_W: 128, MEM_ADDR_W: 16, FIFO_ADDR_W: 14, IN_FIFO_SIZE: 12, OUT_FIFO_SIZE: 12, OVERFLOW: 0, BIST: 0 }
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DUT Instances
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
genvar i;
|
||||
for (i = 0; i < NUM_TESTS; i++) begin : gen_test_config
|
||||
rfnoc_block_axi_ram_fifo_tb #(
|
||||
.CHDR_W (test[i].CHDR_W),
|
||||
.NUM_PORTS (test[i].NUM_PORTS),
|
||||
.MEM_DATA_W (test[i].MEM_DATA_W),
|
||||
.MEM_ADDR_W (test[i].MEM_ADDR_W),
|
||||
.FIFO_ADDR_W (test[i].FIFO_ADDR_W),
|
||||
.IN_FIFO_SIZE (test[i].IN_FIFO_SIZE),
|
||||
.OUT_FIFO_SIZE (test[i].OUT_FIFO_SIZE),
|
||||
.OVERFLOW (test[i].OVERFLOW),
|
||||
.BIST (test[i].BIST)
|
||||
) rfnoc_block_radio_tb_i ();
|
||||
end : gen_test_config
|
||||
|
||||
|
||||
endmodule : rfnoc_block_axi_ram_fifo_all_tb
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,637 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, A National Instruments Company
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: sim_axi_ram
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Simulation model for a basic AXI4 memory mapped memory. A few notes on its
|
||||
// behavior:
|
||||
//
|
||||
// - This model does not reorder requests (regardless of WID/RID). All
|
||||
// requests are evaluated strictly in order.
|
||||
// - The only supported response is OKAY
|
||||
// - This model supports misaligned memory accesses, which cause a
|
||||
// simulation warning.
|
||||
// - A reset does not clear the memory contents
|
||||
// - The memory itself is implemented using an associative array (sparse
|
||||
// matrix) so that large memories can be supported.
|
||||
// - This model is half duplex, meaning read and write data transfers won't
|
||||
// happen at the same time. A new data transfer won't begin until the
|
||||
// previous one has completed.
|
||||
//
|
||||
|
||||
module sim_axi_ram #(
|
||||
parameter AWIDTH = 32,
|
||||
parameter DWIDTH = 64,
|
||||
parameter IDWIDTH = 2,
|
||||
parameter BIG_ENDIAN = 0,
|
||||
parameter STALL_PROB = 25
|
||||
) (
|
||||
input logic s_aclk,
|
||||
input logic s_aresetn,
|
||||
|
||||
// Write Address Channel
|
||||
input logic [IDWIDTH-1:0] s_axi_awid,
|
||||
input logic [ AWIDTH-1:0] s_axi_awaddr,
|
||||
input logic [ 7:0] s_axi_awlen,
|
||||
input logic [ 2:0] s_axi_awsize,
|
||||
input logic [ 1:0] s_axi_awburst,
|
||||
input logic s_axi_awvalid,
|
||||
output logic s_axi_awready,
|
||||
|
||||
// Write Data Channel
|
||||
input logic [ DWIDTH-1:0] s_axi_wdata,
|
||||
input logic [DWIDTH/8-1:0] s_axi_wstrb,
|
||||
input logic s_axi_wlast,
|
||||
input logic s_axi_wvalid,
|
||||
output logic s_axi_wready,
|
||||
|
||||
// Write Response Channel
|
||||
output logic [IDWIDTH-1:0] s_axi_bid,
|
||||
output logic [ 1:0] s_axi_bresp,
|
||||
output logic s_axi_bvalid,
|
||||
input logic s_axi_bready,
|
||||
|
||||
// Read Address Channel
|
||||
input logic [IDWIDTH-1:0] s_axi_arid,
|
||||
input logic [ AWIDTH-1:0] s_axi_araddr,
|
||||
input logic [ 7:0] s_axi_arlen,
|
||||
input logic [ 2:0] s_axi_arsize,
|
||||
input logic [ 1:0] s_axi_arburst,
|
||||
input logic s_axi_arvalid,
|
||||
output logic s_axi_arready,
|
||||
|
||||
// Read Data Channel
|
||||
output logic [ 0:0] s_axi_rid,
|
||||
output logic [DWIDTH-1:0] s_axi_rdata,
|
||||
output logic [ 1:0] s_axi_rresp,
|
||||
output logic s_axi_rlast,
|
||||
output logic s_axi_rvalid,
|
||||
input logic s_axi_rready
|
||||
);
|
||||
|
||||
localparam DEBUG = 0;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Data Types
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
typedef enum logic [1:0] { FIXED, INCR, WRAP } burst_t;
|
||||
typedef enum logic [1:0] { OKAY, EXOKAY, SLVERR, DECERR } resp_t;
|
||||
|
||||
typedef struct packed {
|
||||
longint count; // Number of requests to wait for before executing
|
||||
logic [IDWIDTH-1:0] id;
|
||||
logic [AWIDTH-1:0] addr;
|
||||
logic [8:0] len; // Add an extra bit, since actual true length is +1
|
||||
logic [7:0] size; // Add extra bits to store size in bytes, instead of clog2(size)
|
||||
burst_t burst;
|
||||
} req_t;
|
||||
|
||||
// Make the address type an extra bit wide so that we can detect
|
||||
// out-of-bounds accesses easily.
|
||||
typedef bit [AWIDTH:0] addr_t;
|
||||
|
||||
// Data word type
|
||||
typedef logic [DWIDTH-1:0] data_t;
|
||||
|
||||
// Mask to indicate which bits should be written.
|
||||
typedef bit [DWIDTH/8-1:0] mask_t;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Data Structures
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
byte memory [addr_t]; // Byte addressable memory
|
||||
mailbox #(req_t) read_req = new(); // Read request queue
|
||||
mailbox #(req_t) write_req = new(); // Write request queue
|
||||
mailbox #(req_t) write_resp = new(); // Write response queue
|
||||
|
||||
longint req_count; // Number of requests received
|
||||
longint compl_count; // Number of requests completed
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// External Configuration Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int waddr_stall_prob = STALL_PROB;
|
||||
int wdata_stall_prob = STALL_PROB;
|
||||
int wresp_stall_prob = STALL_PROB;
|
||||
int raddr_stall_prob = STALL_PROB;
|
||||
int rdata_stall_prob = STALL_PROB;
|
||||
|
||||
// Set ALL stall probabilities to the same value
|
||||
function void set_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
waddr_stall_prob = probability;
|
||||
wdata_stall_prob = probability;
|
||||
wresp_stall_prob = probability;
|
||||
raddr_stall_prob = probability;
|
||||
rdata_stall_prob = probability;
|
||||
endfunction : set_stall_prob
|
||||
|
||||
// Set WRITE stall probabilities to the same value
|
||||
function void set_write_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
waddr_stall_prob = probability;
|
||||
wdata_stall_prob = probability;
|
||||
wresp_stall_prob = probability;
|
||||
endfunction : set_write_stall_prob
|
||||
|
||||
// Set READ stall probabilities to the same value
|
||||
function void set_read_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
raddr_stall_prob = probability;
|
||||
rdata_stall_prob = probability;
|
||||
endfunction : set_read_stall_prob
|
||||
|
||||
// Set Write Address Channel stall probability
|
||||
function void set_waddr_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
waddr_stall_prob = probability;
|
||||
endfunction : set_waddr_stall_prob
|
||||
|
||||
// Set Write Data Channel stall probability
|
||||
function void set_wdata_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
wdata_stall_prob = probability;
|
||||
endfunction : set_wdata_stall_prob
|
||||
|
||||
// Set Write Response Channel stall probability
|
||||
function void set_wresp_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
wresp_stall_prob = probability;
|
||||
endfunction : set_wresp_stall_prob
|
||||
|
||||
// Set Read Address Channel stall probability
|
||||
function void set_raddr_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
raddr_stall_prob = probability;
|
||||
endfunction : set_raddr_stall_prob
|
||||
|
||||
// Set Read Data Channel stall probability
|
||||
function void set_rdata_stall_prob(int probability);
|
||||
assert(probability >= 0 && probability <= 100) else begin
|
||||
$error("Probability must be from 0 to 100");
|
||||
end
|
||||
rdata_stall_prob = probability;
|
||||
endfunction : set_rdata_stall_prob
|
||||
|
||||
// Get Write Address Channel stall probability
|
||||
function int get_waddr_stall_prob();
|
||||
return waddr_stall_prob;
|
||||
endfunction : get_waddr_stall_prob
|
||||
|
||||
// Get Write Data Channel stall probability
|
||||
function int get_wdata_stall_prob();
|
||||
return wdata_stall_prob;
|
||||
endfunction : get_wdata_stall_prob
|
||||
|
||||
// Get Write Response Channel stall probability
|
||||
function int get_wresp_stall_prob();
|
||||
return wresp_stall_prob;
|
||||
endfunction : get_wresp_stall_prob
|
||||
|
||||
// Get Read Address Channel stall probability
|
||||
function int get_raddr_stall_prob();
|
||||
return raddr_stall_prob;
|
||||
endfunction : get_raddr_stall_prob
|
||||
|
||||
// Get Read Data Channel stall probability
|
||||
function int get_rdata_stall_prob();
|
||||
return rdata_stall_prob;
|
||||
endfunction : get_rdata_stall_prob
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
function data_t read_mem(addr_t byte_addr, int num_bytes);
|
||||
data_t data;
|
||||
addr_t incr;
|
||||
|
||||
if (BIG_ENDIAN) begin
|
||||
byte_addr = byte_addr + num_bytes-1;
|
||||
incr = -1;
|
||||
end else begin
|
||||
incr = 1;
|
||||
end
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) begin
|
||||
if (byte_addr >= 2**AWIDTH) begin
|
||||
$fatal(1, "Read extends beyond memory range");
|
||||
end
|
||||
if (memory.exists(byte_addr)) data[i*8 +: 8] = memory[byte_addr];
|
||||
else data[i*8 +: 8] = 'X;
|
||||
byte_addr += incr;
|
||||
end
|
||||
|
||||
return data;
|
||||
endfunction : read_mem
|
||||
|
||||
|
||||
function void write_mem(addr_t byte_addr, int num_bytes, data_t data, mask_t mask);
|
||||
addr_t incr;
|
||||
|
||||
if (BIG_ENDIAN) begin
|
||||
byte_addr = byte_addr + num_bytes-1;
|
||||
incr = -1;
|
||||
end else begin
|
||||
incr = 1;
|
||||
end
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) begin
|
||||
if (mask[i]) begin
|
||||
if (byte_addr >= 2**AWIDTH) begin
|
||||
$fatal(1, "Write extends beyond memory range");
|
||||
end
|
||||
memory[byte_addr] = data[i*8 +: 8];
|
||||
end
|
||||
byte_addr += incr;
|
||||
end
|
||||
endfunction : write_mem
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Write Requests
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
initial begin : write_req_proc
|
||||
req_t req;
|
||||
burst_t burst;
|
||||
|
||||
s_axi_awready <= 0;
|
||||
|
||||
forever begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) continue;
|
||||
|
||||
if (s_axi_awvalid) begin
|
||||
if (s_axi_awready) begin
|
||||
req.count = req_count;
|
||||
req.id = s_axi_awid;
|
||||
req.addr = s_axi_awaddr;
|
||||
req.len = s_axi_awlen + 1; // Per AXI4 spec, Burst_length = AxLEN[7:0] + 1
|
||||
req.size = 2**s_axi_awsize; // Store as true size in bytes, not clog2(size)
|
||||
req.burst = burst_t'(s_axi_awburst);
|
||||
|
||||
// Check that the request is valid
|
||||
assert (!$isunknown(req)) else begin
|
||||
$fatal(1, "Write request signals are unknown");
|
||||
end
|
||||
assert (s_axi_araddr % (DWIDTH/8) == 0) else begin
|
||||
$warning("Unaligned memory write");
|
||||
end
|
||||
assert (2**s_axi_awsize <= DWIDTH/8) else begin
|
||||
$fatal(1, "AWSIZE must not be larger than DWIDTH");
|
||||
end
|
||||
assert ($cast(burst, s_axi_awburst)) else begin
|
||||
$fatal(1, "Invalid AWBURST value");
|
||||
end
|
||||
|
||||
if (DEBUG) begin
|
||||
$display("WRITE REQ: id=%X, addr=%X, len=%X, size=%X, burst=%s, %t, %m",
|
||||
req.id, req.addr, req.len, req.size, req.burst.name, $realtime);
|
||||
end
|
||||
|
||||
req_count++;
|
||||
write_req.put(req);
|
||||
end
|
||||
|
||||
// Randomly deassert ready
|
||||
s_axi_awready <= $urandom_range(99) < waddr_stall_prob ? 0 : 1;
|
||||
end
|
||||
end
|
||||
end : write_req_proc
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Read Requests
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
initial begin : read_req_proc
|
||||
req_t req;
|
||||
burst_t burst;
|
||||
|
||||
s_axi_arready <= 0;
|
||||
|
||||
forever begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) continue;
|
||||
|
||||
if (s_axi_arvalid) begin
|
||||
if (s_axi_arready) begin
|
||||
req.count = req_count;
|
||||
req.id = s_axi_arid;
|
||||
req.addr = s_axi_araddr;
|
||||
req.len = s_axi_arlen + 1; // Per AXI4 spec, Burst_length = AxLEN[7:0] + 1
|
||||
req.size = 2**s_axi_arsize; // Store as true size in bytes, not clog2(size)
|
||||
req.burst = burst_t'(s_axi_arburst);
|
||||
|
||||
// Check that the request is valid
|
||||
assert(!$isunknown(req)) else begin
|
||||
$fatal(1, "Read request signals are unknown");
|
||||
end
|
||||
assert(s_axi_araddr % (DWIDTH/8) == 0) else begin
|
||||
$warning("Unaligned memory read");
|
||||
end
|
||||
assert(2**s_axi_arsize <= DWIDTH/8) else begin
|
||||
$fatal(1, "ARSIZE must not be larger than DWIDTH");
|
||||
end
|
||||
assert ($cast(burst, s_axi_awburst)) else begin
|
||||
$fatal(1, "Invalid ARBURST value");
|
||||
end
|
||||
|
||||
if (DEBUG) begin
|
||||
$display("READ REQ: id=%X, addr=%X, len=%X, size=%X, burst=%s, %t, %m",
|
||||
req.id, req.addr, req.len, req.size, req.burst.name, $realtime);
|
||||
end
|
||||
|
||||
req_count++;
|
||||
read_req.put(req);
|
||||
end
|
||||
|
||||
// Randomly deassert ready to cause a stall
|
||||
s_axi_arready <= $urandom_range(99) < raddr_stall_prob ? 0 : 1;
|
||||
end
|
||||
end
|
||||
end : read_req_proc
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Write Data
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
initial begin : write_data_proc
|
||||
req_t req;
|
||||
bit [AWIDTH-1:0] addr;
|
||||
|
||||
forever begin
|
||||
// Wait for the next write request
|
||||
s_axi_wready <= 0;
|
||||
write_req.get(req);
|
||||
|
||||
// Wait for previous requests to complete
|
||||
while (compl_count < req.count) begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end
|
||||
|
||||
// If reset was asserted, clear the request queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(write_req.try_get(req));
|
||||
continue;
|
||||
end
|
||||
|
||||
// Iterate over the number of words in the request
|
||||
for (int i = 0; i < req.len; ) begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
|
||||
// Check if we have a new data word
|
||||
if (s_axi_wvalid) begin
|
||||
if (s_axi_wready) begin
|
||||
// Check the inputs
|
||||
if ($isunknown(s_axi_wstrb)) begin
|
||||
$fatal(1, "WSTRB is unknown");
|
||||
end
|
||||
if ($isunknown(s_axi_wdata)) begin
|
||||
$warning(1, "WDATA is unknown; data will be changed to zero");
|
||||
end
|
||||
|
||||
case (req.burst)
|
||||
FIXED : begin
|
||||
addr = req.addr;
|
||||
end
|
||||
INCR : begin
|
||||
// If the address rolls over, we've reached the end of the
|
||||
// memory and we should stop here.
|
||||
addr = req.addr + i*req.size;
|
||||
if (addr < req.addr) break;
|
||||
end
|
||||
WRAP : begin
|
||||
// Allow roll-over
|
||||
addr = req.addr + i*req.size;
|
||||
end
|
||||
endcase
|
||||
|
||||
write_mem(addr, req.size, s_axi_wdata, s_axi_wstrb);
|
||||
|
||||
if (DEBUG) begin
|
||||
$display("WRITE: count=%3X, ADDR=%X, DATA=%X, SIZE=%X, STRB=%X, %t, %m",
|
||||
i, addr, s_axi_wdata, req.size, s_axi_wstrb, $realtime);
|
||||
end
|
||||
|
||||
i++;
|
||||
end
|
||||
|
||||
// Randomly deassert ready to cause a stall
|
||||
s_axi_wready <= $urandom_range(99) < wdata_stall_prob ? 0 : 1;
|
||||
end
|
||||
end // for
|
||||
|
||||
// If reset was asserted, clear the request queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(write_req.try_get(req));
|
||||
continue;
|
||||
end
|
||||
|
||||
compl_count++;
|
||||
|
||||
// Enqueue write response
|
||||
write_resp.put(req);
|
||||
|
||||
// Make sure WLAST asserted for the last word. If not we report an error.
|
||||
// Per the AXI4 standard, "a slave is not required to use the WLAST
|
||||
// signal" because "a slave can calculate the last write data transfer
|
||||
// from the burst length AWLEN".
|
||||
if (s_axi_wlast != 1'b1) begin
|
||||
$error("WLAST not asserted on last word of burst");
|
||||
end
|
||||
|
||||
end // forever
|
||||
end : write_data_proc
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Write Response
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
initial begin : write_resp_proc
|
||||
req_t resp;
|
||||
bit [AWIDTH-1:0] addr;
|
||||
|
||||
forever begin
|
||||
s_axi_bid <= 'X;
|
||||
s_axi_bresp <= 'X;
|
||||
s_axi_bvalid <= 0;
|
||||
|
||||
// Wait for the next write response
|
||||
write_resp.get(resp);
|
||||
@(posedge s_aclk);
|
||||
|
||||
// If there's a reset, clear the response queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(write_resp.try_get(resp));
|
||||
continue;
|
||||
end
|
||||
|
||||
// Randomly keep bvalid deasserted for next word to cause a stall
|
||||
if ($urandom_range(99) < wresp_stall_prob) begin
|
||||
do begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end while ($urandom_range(99) < wresp_stall_prob);
|
||||
|
||||
// If reset was asserted, clear the response queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(write_resp.try_get(resp));
|
||||
continue;
|
||||
end
|
||||
end
|
||||
|
||||
// Output the next response
|
||||
s_axi_bid <= resp.id;
|
||||
s_axi_bresp <= OKAY;
|
||||
s_axi_bvalid <= 1;
|
||||
|
||||
if (DEBUG) begin
|
||||
$display("WRITE RESP: ID=%X, %t, %m", resp.id, $realtime);
|
||||
end
|
||||
|
||||
// Wait for the response to be accepted
|
||||
do begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end while (!s_axi_bready);
|
||||
|
||||
// Output the next response
|
||||
s_axi_bid <= 'X;
|
||||
s_axi_bresp <= 'X;
|
||||
s_axi_bvalid <= 0;
|
||||
|
||||
// If reset was asserted, clear the response queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(write_resp.try_get(resp));
|
||||
continue;
|
||||
end
|
||||
end // forever
|
||||
end : write_resp_proc
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Read Data
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
initial begin : read_data_proc
|
||||
req_t req;
|
||||
bit [AWIDTH-1:0] addr;
|
||||
logic [DWIDTH-1:0] data;
|
||||
|
||||
forever begin
|
||||
s_axi_rid <= 'X;
|
||||
s_axi_rdata <= 'X;
|
||||
s_axi_rresp <= 'X;
|
||||
s_axi_rlast <= 'X;
|
||||
s_axi_rvalid <= 0;
|
||||
|
||||
// Wait for the next read request
|
||||
read_req.get(req);
|
||||
|
||||
// Wait for previous requests to complete
|
||||
do begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end while (compl_count < req.count);
|
||||
|
||||
// If reset was asserted, clear the request queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(read_req.try_get(req));
|
||||
continue;
|
||||
end
|
||||
|
||||
for (int i = 0; i < req.len; i++) begin
|
||||
// Randomly keep rvalid deasserted for next word to cause a stall
|
||||
if ($urandom_range(99) < rdata_stall_prob) begin
|
||||
do begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end while ($urandom_range(99) < rdata_stall_prob);
|
||||
if (!s_aresetn) break;
|
||||
end
|
||||
|
||||
case (req.burst)
|
||||
FIXED : begin
|
||||
addr = req.addr;
|
||||
end
|
||||
INCR : begin
|
||||
// If the address rolls over, we've reached the end of the memory
|
||||
// and we should stop here.
|
||||
addr = req.addr + i*req.size;
|
||||
if (addr < req.addr) break;
|
||||
end
|
||||
WRAP : begin
|
||||
// Allow roll-over
|
||||
addr = req.addr + i*req.size;
|
||||
end
|
||||
endcase
|
||||
|
||||
// Read the memory
|
||||
data = read_mem(addr, req.size);
|
||||
|
||||
// Output the next word
|
||||
s_axi_rid <= req.id;
|
||||
s_axi_rdata <= data;
|
||||
s_axi_rresp <= OKAY;
|
||||
s_axi_rlast <= (i == req.len-1);
|
||||
s_axi_rvalid <= 1;
|
||||
|
||||
if (DEBUG) begin
|
||||
$display("READ: count=%3X, ADDR=%X, DATA=%X, SIZE=%X, %t, %m", i, addr, data, req.size, $realtime);
|
||||
end
|
||||
|
||||
// Wait for the word to be captured
|
||||
do begin
|
||||
@(posedge s_aclk);
|
||||
if (!s_aresetn) break;
|
||||
end while (!s_axi_rready);
|
||||
|
||||
s_axi_rid <= 'X;
|
||||
s_axi_rdata <= 'X;
|
||||
s_axi_rresp <= 'X;
|
||||
s_axi_rlast <= 'X;
|
||||
s_axi_rvalid <= 0;
|
||||
end // for
|
||||
|
||||
// If reset was asserted, clear the request queue and start over
|
||||
if (!s_aresetn) begin
|
||||
while(read_req.try_get(req));
|
||||
end
|
||||
|
||||
compl_count++;
|
||||
|
||||
end // forever
|
||||
end : read_data_proc
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user