Files
b210-k7-fpga/sim/rfnoc/PkgAxisCtrlBfm.sv
Wade Fife 37b8b0d017 fpga: rfnoc: Move synthesizable code from sim to lib
Original-commit: d9f8c08dfb1afe98c35c5911125c6eead869713f
2025-03-17 17:47:16 -05:00

233 lines
7.0 KiB
Systemverilog

//
// Copyright 2019 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: PkgAxisCtrlBfm
//
// Description: Package for an AXIS-Ctrl bus functional model (BFM), which
// consists primarily of the AxisCtrlPacket and AxisCtrlBfm classes.
//
package PkgAxisCtrlBfm;
import rfnoc_chdr_utils_pkg::*;
import PkgAxiStreamBfm::*;
export PkgAxiStreamBfm::*;
//---------------------------------------------------------------------------
// AXIS-Ctrl Packet Class
//---------------------------------------------------------------------------
class AxisCtrlPacket;
//------------
// Properties
//------------
axis_ctrl_header_t header;
chdr_timestamp_t timestamp;
ctrl_op_word_t op_word;
ctrl_word_t data[$];
//---------
// Methods
//---------
// Return a handle to a copy of this transaction
function AxisCtrlPacket copy();
AxisCtrlPacket temp;
temp = new();
temp.header = this.header;
temp.timestamp = this.timestamp;
temp.op_word = this.op_word;
temp.data = this.data;
return temp;
endfunction
// Return true if this packet equals that of the argument
function bit equal(AxisCtrlPacket packet);
if (header != packet.header) return 0;
if (op_word != packet.op_word) return 0;
if (data.size() != packet.data.size()) return 0;
if (header.has_time && timestamp != packet.timestamp) return 0;
foreach (data[i]) begin
if (data[i] != packet.data[i]) return 0;
end
return 1;
endfunction : equal
// Format the contents of the packet into a string
function string sprint();
string str;
str = {str, $sformatf("AxisCtrlPacket:\n")};
str = {str, $sformatf("- header: %p\n", header) };
if (header.has_time)
str = {str, $sformatf("- timestamp: %0d\n", timestamp) };
str = {str, $sformatf("- op_word: '{status:%s,op_code:%s,byte_enable:0b%4b,address:0x%05x}\n",
op_word.status.name, op_word.op_code.name, op_word.byte_enable, op_word.address)};
str = {str, $sformatf("- data:\n") };
foreach (data[i]) begin
str = {str, $sformatf("%5d> 0x%08x\n", i, data[i]) };
end
return str;
endfunction : sprint
// Print the contents of the packet
function void print();
$display(sprint());
endfunction : print
function void write_ctrl(
ref axis_ctrl_header_t header,
ref ctrl_op_word_t op_word,
ref ctrl_word_t data[$],
input chdr_timestamp_t timestamp = 0
);
this.header = header;
this.data = data;
this.timestamp = timestamp;
this.op_word = op_word;
endfunction : write_ctrl
endclass : AxisCtrlPacket;
//---------------------------------------------------------------------------
// AXIS-Ctrl Bus Functional Model Class
//---------------------------------------------------------------------------
class AxisCtrlBfm extends AxiStreamBfm #(32);
extern function new (
virtual AxiStreamIf #(32).master master,
virtual AxiStreamIf #(32).slave slave
);
extern task put_ctrl(AxisCtrlPacket ctrl_packet);
extern task try_put_ctrl(AxisCtrlPacket ctrl_packet);
extern task get_ctrl(output AxisCtrlPacket ctrl_packet);
extern function bit try_get_ctrl(output AxisCtrlPacket ctrl_packet);
extern function AxisPacket_t axis_ctrl_to_axis(AxisCtrlPacket ctrl_packet);
extern function AxisCtrlPacket axis_to_axis_ctrl(AxisPacket_t axis_packet);
endclass : AxisCtrlBfm
//---------------------------------------------------------------------------
// AXIS-Ctrl BFM Methods
//---------------------------------------------------------------------------
// Class constructor. This must be given an interface for the master
// connection and an interface for the slave connection.
function AxisCtrlBfm::new (
virtual AxiStreamIf #(32).master master,
virtual AxiStreamIf #(32).slave slave
);
super.new(master, slave);
endfunction : new
// Queue the provided packet for transmission
task AxisCtrlBfm::put_ctrl(AxisCtrlPacket ctrl_packet);
AxisPacket_t axis_packet;
axis_packet = axis_ctrl_to_axis(ctrl_packet);
super.put(axis_packet);
endtask : put_ctrl
// Attempt to queue the provided packet for transmission. Return 1 if
// successful, return 0 if the queue is full.
task AxisCtrlBfm::try_put_ctrl(AxisCtrlPacket ctrl_packet);
AxisPacket_t axis_packet;
axis_packet = axis_ctrl_to_axis(ctrl_packet);
super.put(axis_packet);
endtask : try_put_ctrl
// Get the next packet when it becomes available (waits if necessary)
task AxisCtrlBfm::get_ctrl(output AxisCtrlPacket ctrl_packet);
AxisPacket_t axis_packet;
super.get(axis_packet);
ctrl_packet = axis_to_axis_ctrl(axis_packet);
endtask : get_ctrl
// Get the next packet if there's one available and return 1. Return 0 if
// there's no packet available.
function bit AxisCtrlBfm::try_get_ctrl(output AxisCtrlPacket ctrl_packet);
AxisPacket_t axis_packet;
if(!super.try_get(axis_packet)) return 0;
ctrl_packet = axis_to_axis_ctrl(axis_packet);
return 1;
endfunction : try_get_ctrl
// Convert an AXIS-Ctrl packet data structure to an AXI-Stream packet data
// structure.
function AxisCtrlBfm::AxisPacket_t AxisCtrlBfm::axis_ctrl_to_axis(AxisCtrlPacket ctrl_packet);
AxisPacket_t axis_packet = new();
int index;
// Insert words 0 and 1 (header)
axis_packet.data.push_back(ctrl_packet.header[31: 0]);
axis_packet.data.push_back(ctrl_packet.header[63:32]);
// Insert timestamp if has_time is set (words 2 and 3)
if (ctrl_packet.header.has_time) begin
axis_packet.data.push_back(ctrl_packet.timestamp[31: 0]);
axis_packet.data.push_back(ctrl_packet.timestamp[63:32]);
end
// Insert word 4 (operation word)
axis_packet.data.push_back(ctrl_packet.op_word[31: 0]);
// Insert data
foreach (ctrl_packet.data[i]) begin
axis_packet.data.push_back(ctrl_packet.data[i]);
end
return axis_packet;
endfunction : axis_ctrl_to_axis
// Convert an AXI-Stream packet data structure to an AXIS-Ctrl packet data
// structure.
function AxisCtrlPacket AxisCtrlBfm::axis_to_axis_ctrl(AxisPacket_t axis_packet);
AxisCtrlPacket ctrl_packet = new();
int i; // Use an index instead of pop_front() to workaround a ModelSim bug
// Grab words 0 and 1 (header)
ctrl_packet.header[31: 0] = axis_packet.data[0];
ctrl_packet.header[63:32] = axis_packet.data[1];
// If has_time is set, grab timestamp (words 2 and 3)
i = 2;
if (ctrl_packet.header.has_time) begin
ctrl_packet.timestamp[31: 0] = axis_packet.data[2];
ctrl_packet.timestamp[63:32] = axis_packet.data[3];
i += 2;
end
// Grab word 4 (operation word)
ctrl_packet.op_word[31: 0] = axis_packet.data[i];
// Grab data
ctrl_packet.data = axis_packet.data[(i+1):$];
return ctrl_packet;
endfunction : axis_to_axis_ctrl
endpackage : PkgAxisCtrlBfm