This replaces chdr_word_t, which was a statically defined 64-bit data type, with a paramaterizable data type that matches the defined CHDR_W. Code that formerly referenced the chdr_word_t data type can now define the data type for their desired CHDR_W and ITEM_W as follows: // Define the CHDR word and item/sample data types typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; typedef ChdrData #(CHDR_W, ITEM_W)::item_t item_t; ITEM_W is optional when defining chdr_word_t if items are not needed. Static methods in the ChdrData class also provide the ability to convert between CHDR words and data items. For example: // Convert CHDR data buffer to a buffer of samples samples = ChdrData#(CHDR_W, ITEM_W)::chdr_to_item(data); Original-commit: fc895feacb8dde3b02c9a4eccb4b4f4a654f2881
233 lines
7.0 KiB
Systemverilog
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 PkgChdrUtils::*;
|
|
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 axis_ctrl_to_axis(AxisCtrlPacket ctrl_packet);
|
|
|
|
extern function AxisCtrlPacket axis_to_axis_ctrl(AxisPacket 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 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 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 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 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 AxisCtrlBfm::axis_ctrl_to_axis(AxisCtrlPacket ctrl_packet);
|
|
AxisPacket 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 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
|