// // 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_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