aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/sim/axi
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/sim/axi')
-rw-r--r--fpga/usrp3/sim/axi/Makefile.srcs12
-rw-r--r--fpga/usrp3/sim/axi/sim_axi4_lib.svh93
-rw-r--r--fpga/usrp3/sim/axi/sim_axis_lib.svh219
-rw-r--r--fpga/usrp3/sim/axi/sim_cvita_lib.svh440
4 files changed, 764 insertions, 0 deletions
diff --git a/fpga/usrp3/sim/axi/Makefile.srcs b/fpga/usrp3/sim/axi/Makefile.srcs
new file mode 100644
index 000000000..96f7eb196
--- /dev/null
+++ b/fpga/usrp3/sim/axi/Makefile.srcs
@@ -0,0 +1,12 @@
+#
+# Copyright 2015 Ettus Research LLC
+#
+
+##################################################
+# Simulation Libraries/Headers for AXI based interfaces
+##################################################
+SIM_AXI_SRCS = $(abspath $(addprefix $(BASE_DIR)/../sim/axi/, \
+sim_axi4_lib.svh \
+sim_axis_lib.svh \
+sim_cvita_lib.svh \
+))
diff --git a/fpga/usrp3/sim/axi/sim_axi4_lib.svh b/fpga/usrp3/sim/axi/sim_axi4_lib.svh
new file mode 100644
index 000000000..588c8d367
--- /dev/null
+++ b/fpga/usrp3/sim/axi/sim_axi4_lib.svh
@@ -0,0 +1,93 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+
+interface axi4_addr_t #(parameter AWIDTH=32, parameter IDWIDTH=4)
+ (input clk);
+
+ logic [IDWIDTH-1:0] id;
+ logic [AWIDTH-1:0] addr;
+ logic [7:0] len;
+ logic [2:0] size;
+ logic [1:0] burst;
+ logic lock;
+ logic [3:0] cache;
+ logic [2:0] prot;
+ logic [3:0] qos;
+ logic [3:0] region;
+ logic user;
+ logic valid;
+ logic ready;
+
+// modport master(output id,addr,len,size,burst,lock,cache,prot,qos,valid, input ready);
+// modport slave(input id,addr,len,size,burst,lock,cache,prot,qos,valid, output ready);
+
+endinterface
+
+interface axi4_wdata_t #(parameter DWIDTH=64)
+ (input clk);
+
+ logic [DWIDTH-1:0] data;
+ logic [(DWIDTH/8)-1:0] strb;
+ logic last;
+ logic user;
+ logic valid;
+ logic ready;
+
+// modport master(output data,strb,last,valid, input ready);
+// modport slave(input data,strb,last,valid, output ready);
+
+endinterface
+
+interface axi4_resp_t #(parameter IDWIDTH=4)
+ (input clk);
+
+ logic ready;
+ logic [IDWIDTH-1:0] id;
+ logic [1:0] resp;
+ logic user;
+ logic valid;
+
+// modport master(output ready, input id,resp,valid);
+// modport slave(input ready, output id,resp,valid);
+
+endinterface
+
+interface axi4_rdata_t #(parameter DWIDTH=64, parameter IDWIDTH=4)
+ (input clk);
+
+ logic ready;
+ logic [IDWIDTH-1:0] id;
+ logic [DWIDTH-1:0] data;
+ logic [1:0] resp;
+ logic user;
+ logic last;
+ logic valid;
+
+// modport master(output ready, input id,data,resp,last,valid);
+// modport slave(input ready, output id,data,resp,last,valid);
+
+endinterface
+
+interface axi4_wr_t #(parameter DWIDTH=64, parameter AWIDTH=32, parameter IDWIDTH=4)
+ (input clk);
+
+ axi4_addr_t #(.AWIDTH(AWIDTH), .IDWIDTH(IDWIDTH)) addr (.clk(clk));
+ axi4_wdata_t #(.DWIDTH(DWIDTH)) data (.clk(clk));
+ axi4_resp_t #(.IDWIDTH(IDWIDTH)) resp (.clk(clk));
+
+// modport master(output addr, output data, input resp);
+// modport slave(input addr, input data, output resp);
+
+endinterface
+
+interface axi4_rd_t #(parameter DWIDTH=64, parameter AWIDTH=32, parameter IDWIDTH=4)
+ (input clk);
+
+ axi4_addr_t #(.AWIDTH(AWIDTH), .IDWIDTH(IDWIDTH)) addr (.clk(clk));
+ axi4_rdata_t #(.DWIDTH(DWIDTH), .IDWIDTH(IDWIDTH)) data (.clk(clk));
+
+// modport master(output addr, output data);
+// modport slave(input addr, input data);
+
+endinterface
diff --git a/fpga/usrp3/sim/axi/sim_axis_lib.svh b/fpga/usrp3/sim/axi/sim_axis_lib.svh
new file mode 100644
index 000000000..bdee113de
--- /dev/null
+++ b/fpga/usrp3/sim/axi/sim_axis_lib.svh
@@ -0,0 +1,219 @@
+//
+// Copyright 2016 Ettus Research
+//
+`ifndef INCLUDED_SIM_AXIS_LIB
+`define INCLUDED_SIM_AXIS_LIB
+
+interface axis_t #(parameter DWIDTH = 32, parameter NUM_STREAMS = 1)(input clk);
+ logic [NUM_STREAMS*DWIDTH-1:0] tdata;
+ logic [NUM_STREAMS-1:0] tvalid;
+ logic [NUM_STREAMS-1:0] tlast;
+ logic [NUM_STREAMS-1:0] tready;
+
+ modport master (
+ output tdata,
+ output tvalid,
+ output tlast,
+ input tready);
+
+ modport slave (
+ input tdata,
+ input tvalid,
+ input tlast,
+ output tready);
+endinterface
+
+// Interface to push data onto a master AXI-stream bus
+interface axis_master #(parameter DWIDTH = 32, parameter NUM_STREAMS = 1)(input clk);
+ axis_t #(.DWIDTH(DWIDTH), .NUM_STREAMS(NUM_STREAMS)) axis(.clk(clk));
+
+ // Check that stream is actually in use
+ function void check_stream(int stream);
+ assert (stream < NUM_STREAMS) else
+ $error("axis_master::check_stream(): Tried to perform operation on unused stream %0d", stream);
+ endfunction
+
+ // Reset signals / properties used by this interface
+ task automatic reset;
+ begin
+ axis.tvalid = 0;
+ axis.tlast = 0;
+ axis.tdata = 0;
+ end
+ endtask
+
+ // Push a word onto the AXI-Stream bus and wait for it to transfer
+ // Args:
+ // - word: The data to push onto the bus
+ // - eop (optional): End of packet (asserts tlast)
+ // - stream: Stream to use (Optional)
+ task automatic push_word (
+ input logic [DWIDTH-1:0] word,
+ input logic eop = 1'b0,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ if (clk) @(negedge clk); // Align with negative edge
+ axis.tvalid[stream] = 1;
+ axis.tlast[stream] = eop;
+ axis.tdata[DWIDTH*stream +: DWIDTH] = word;
+ @(posedge clk); // Put sample on data bus
+ while(~axis.tready[stream]) @(posedge clk); // Wait until receiver ready
+ @(negedge clk); // Put sample on data bus
+ axis.tvalid[stream] = 0;
+ axis.tlast[stream] = 0;
+ end
+ endtask
+
+ // Push a bubble cycle onto the AXI-Stream bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic push_bubble (input int stream = 0);
+ begin
+ check_stream(stream);
+ axis.tvalid[stream] = 0;
+ @(negedge clk);
+ end
+ endtask
+
+ // Push a packet with random data onto to the AXI Stream bus
+ // Args:
+ // - num_samps: Packet size.
+ task automatic push_rand_pkt (
+ input int num_samps,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ if (clk) @(negedge clk);
+ repeat(num_samps-1) begin
+ push_word({(((DWIDTH-1)/32)+1){$random}}, 0, stream);
+ end
+ push_word({(((DWIDTH-1)/32)+1){$random}}, 1, stream);
+ end
+ endtask
+
+ // Push a packet with a ramp on to the AXI Stream bus
+ // Args:
+ // - num_samps: Packet size.
+ // - ramp_start: Start value for the ramp
+ // - ramp_inc: Increment per clock cycle
+ // - stream: Stream to use (Optional)
+ task automatic push_ramp_pkt (
+ input integer num_samps,
+ input [DWIDTH-1:0] ramp_start,
+ input [DWIDTH-1:0] ramp_inc,
+ input int stream = 0);
+ begin
+ automatic integer counter = 0;
+ check_stream(stream);
+ if (clk) @(negedge clk);
+ repeat(num_samps-1) begin
+ push_word(ramp_start+(counter*ramp_inc), 0, stream);
+ counter = counter + 1;
+ end
+ push_word(ramp_start+(counter*ramp_inc), 1, stream);
+ end
+ endtask
+
+endinterface
+
+
+// Interface to push data onto a master AXI-stream bus
+interface axis_slave #(parameter DWIDTH = 32, parameter NUM_STREAMS = 1)(input clk);
+ axis_t #(.DWIDTH(DWIDTH), .NUM_STREAMS(NUM_STREAMS)) axis(.clk(clk));
+
+ // Check that stream is actually in use
+ function void check_stream(int stream);
+ assert (stream < NUM_STREAMS) else
+ $error("axis_slave::check_stream(): Tried to perform operation on unused stream %0d", stream);
+ endfunction
+
+ // Reset signals / properties used by this interface
+ task automatic reset;
+ begin
+ axis.tready = 0;
+ end
+ endtask
+
+ // Pull a word from the AXI Stream bus and
+ // return the data and last
+ // Args:
+ // - word: The data pulled from the bus
+ // - eop: End of packet (tlast)
+ // - stream: Stream to use (Optional)
+ task automatic pull_word (
+ output logic [DWIDTH-1:0] word,
+ output logic eop,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ if (clk) @(negedge clk);
+ axis.tready[stream] = 1;
+ while(~axis.tvalid[stream]) @(posedge clk);
+ word = axis.tdata[DWIDTH*stream +: DWIDTH];
+ eop = axis.tlast[stream];
+ @(negedge clk);
+ axis.tready[stream] = 0;
+ end
+ endtask
+
+ // Wait for a sample to be transferred on the AXI Stream
+ // bus and return the data and last. Note, this task only
+ // observes the bus and does not affect the AXI control
+ // signals.
+ // Args:
+ // - word: The data pulled from the bus
+ // - eop: End of packet (tlast)
+ // - stream: Stream to use (Optional)
+ task automatic copy_word (
+ output logic [DWIDTH-1:0] word,
+ output logic eop,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(~(axis.tready[stream]&axis.tvalid[stream])) @(posedge clk); // Wait until sample is transferred
+ word = axis.tdata[DWIDTH*stream +: DWIDTH];
+ eop = axis.tlast[stream];
+ @(negedge clk);
+ end
+ endtask
+
+ // Wait for a bubble cycle on the AXI Stream bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic wait_for_bubble (
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(axis.tready[stream]&axis.tvalid[stream]) @(posedge clk);
+ @(negedge clk);
+ end
+ endtask
+
+ // Wait for a packet to finish on the bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic wait_for_pkt (
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(~(axis.tready[stream]&axis.tvalid[stream]&axis.tlast[stream])) @(posedge clk);
+ @(negedge clk);
+ end
+ endtask
+
+ // Drop a word on the bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic drop_word (
+ input int stream = 0);
+ begin
+ logic [DWIDTH-1:0] dropped_word;
+ logic dropped_eop;
+ pull_word(dropped_word, dropped_eop, stream);
+ end
+ endtask
+
+endinterface
+
+`endif \ No newline at end of file
diff --git a/fpga/usrp3/sim/axi/sim_cvita_lib.svh b/fpga/usrp3/sim/axi/sim_cvita_lib.svh
new file mode 100644
index 000000000..97e3d9cd2
--- /dev/null
+++ b/fpga/usrp3/sim/axi/sim_cvita_lib.svh
@@ -0,0 +1,440 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+`ifndef INCLUDED_SIM_CVITA_LIB
+`define INCLUDED_SIM_CVITA_LIB
+
+`include "sim_axis_lib.svh"
+
+typedef logic [63:0] cvita_payload_t[$];
+
+// CVITA packet types
+typedef enum logic [1:0] {
+ DATA=2'b00, FC=2'b01, CMD=2'b10, RESP=2'b11
+} cvita_pkt_type_t;
+
+// CVITA Header
+typedef struct packed {
+ cvita_pkt_type_t pkt_type;
+ logic has_time;
+ logic eob;
+ logic [11:0] seqnum;
+ logic [15:0] length;
+ logic [15:0] src_sid;
+ logic [15:0] dst_sid;
+ logic [63:0] timestamp;
+} cvita_hdr_t;
+
+// CVITA Packet, Header + Payload
+typedef struct {
+ cvita_hdr_t hdr;
+ cvita_payload_t payload;
+} cvita_pkt_t;
+
+// CVITA packet metadata
+typedef struct {
+ logic eob = 1'b0;
+ logic has_time = 1'b0;
+ logic [63:0] timestamp = 'd0;
+} cvita_metadata_t;
+
+function logic[63:0] flatten_chdr_no_ts(input cvita_hdr_t hdr);
+ return {hdr.pkt_type, hdr.has_time, hdr.eob, hdr.seqnum, hdr.length, hdr.src_sid, hdr.dst_sid};
+endfunction
+
+//TODO: This should be a function but it segfaults XSIM.
+task automatic unflatten_chdr_no_ts;
+ input logic[63:0] hdr_bits;
+ output cvita_hdr_t hdr;
+ begin
+ hdr = '{
+ pkt_type:cvita_pkt_type_t'(hdr_bits[63:62]), has_time:hdr_bits[61], eob:hdr_bits[60],
+ seqnum:hdr_bits[59:48], length:hdr_bits[47:32], src_sid:hdr_bits[31:16], dst_sid:hdr_bits[15:0], timestamp:0 //Default timestamp
+ };
+ end
+endtask
+
+// Extracts header from CVITA packets.
+// Args:
+// - pkt: CVITA packet
+// - hdr: CVITA header
+task automatic extract_chdr(ref logic [63:0] pkt[$], ref cvita_hdr_t hdr);
+ begin
+ unflatten_chdr_no_ts(pkt[0],hdr);
+ if (hdr.has_time) begin
+ hdr.timestamp = pkt[1];
+ // Delete both header and time stamp
+ pkt = pkt[2:pkt.size-1];
+ end else begin
+ // Delete header
+ pkt = pkt[1:pkt.size-1];
+ end
+ end
+endtask
+
+// Drops header from CVITA packets leaving only payload data.
+// Args:
+// - pkt: CVITA packet
+task automatic drop_chdr(ref logic [63:0] pkt[$]);
+ begin
+ automatic cvita_hdr_t hdr;
+ extract_chdr(pkt,hdr);
+ end
+endtask
+
+task automatic unflatten_chdr;
+ input logic[63:0] hdr_bits;
+ input logic[63:0] timestamp;
+ output cvita_hdr_t hdr;
+ begin
+ hdr = '{
+ pkt_type:cvita_pkt_type_t'(hdr_bits[63:62]), has_time:hdr_bits[61], eob:hdr_bits[60],
+ seqnum:hdr_bits[59:48], length:hdr_bits[47:32], src_sid:hdr_bits[31:16], dst_sid:hdr_bits[15:0], timestamp:timestamp
+ };
+ end
+endtask
+
+function logic chdr_compare(input cvita_hdr_t a, input cvita_hdr_t b);
+ return ((a.pkt_type == b.pkt_type) && (a.has_time == b.has_time) && (a.eob == b.eob) &&
+ (a.seqnum == b.seqnum) && (a.length == b.length) && (a.src_sid == b.src_sid) && (a.dst_sid == b.dst_sid));
+endfunction
+
+typedef struct packed {
+ logic [31:0] count;
+ logic [63:0] sum;
+ logic [63:0] min;
+ logic [63:0] max;
+ logic [63:0] crc;
+} cvita_stats_t;
+
+// Interface and tasks to send CVITA packets over a master AXI-Stream bus
+interface cvita_master #(parameter DWIDTH = 64, parameter NUM_STREAMS = 1)(input clk);
+ axis_t #(.DWIDTH(DWIDTH), .NUM_STREAMS(NUM_STREAMS)) axis(.clk(clk));
+
+ // Check that stream is actually in use
+ function void check_stream(int stream);
+ assert (stream < NUM_STREAMS) else
+ $error("cvita_master::check_stream(): Tried to perform operation on unused stream %0d", stream);
+ endfunction
+
+ // Reset signals / properties used by this interface
+ task automatic reset;
+ begin
+ axis.tvalid = 0;
+ axis.tlast = 0;
+ axis.tdata = 0;
+ end
+ endtask
+
+ // Push a word onto the AXI-Stream bus and wait for it to transfer
+ // Args:
+ // - word: The data to push onto the bus
+ // - eop: End of packet (asserts tlast) (Optional)
+ // - stream: Stream to use (Optional)
+ task automatic push_word (
+ input logic [DWIDTH-1:0] word,
+ input logic eop = 1'b0,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ if (clk) @(negedge clk); // Align with negative edge
+ axis.tvalid[stream] = 1;
+ axis.tlast[stream] = eop;
+ axis.tdata[DWIDTH*stream +: DWIDTH] = word;
+ @(posedge clk); // Put sample on data bus
+ while(~axis.tready[stream]) @(posedge clk); // Wait until receiver ready
+ @(negedge clk); // Put sample on data bus
+ axis.tvalid[stream] = 0;
+ axis.tlast[stream] = 0;
+ end
+ endtask
+
+ // Push a bubble cycle onto the AXI-Stream bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic push_bubble (input int stream = 0);
+ begin
+ check_stream(stream);
+ axis.tvalid[stream] = 0;
+ @(negedge clk);
+ end
+ endtask
+
+ // Push a CVITA header into the stream
+ // Args:
+ // - hdr: The header to push
+ // - stream: Stream to use (Optional)
+ task automatic push_hdr (
+ input cvita_hdr_t hdr,
+ input int stream = 0);
+ push_word(flatten_chdr_no_ts(hdr), 0, stream);
+ endtask
+
+ // Push a packet with random data onto to the AXI Stream bus
+ // Args:
+ // - num_samps: Packet size.
+ // - hdr: Header to attach to packet (length will be ignored)
+ // - stream: Stream to use (Optional)
+ task automatic push_rand_pkt (
+ input integer num_samps,
+ input cvita_hdr_t hdr,
+ input int stream = 0);
+ begin
+ cvita_hdr_t tmp_hdr = hdr;
+ tmp_hdr.length = (num_samps * 8) + (hdr.has_time ? 16 : 8);
+ @(negedge clk);
+ push_hdr(tmp_hdr);
+ if (hdr.has_time) push_word(hdr.timestamp, 0, stream);
+ repeat(num_samps-1) begin
+ push_word({$random,$random}, 0, stream);
+ end
+ push_word({$random,$random}, 1, stream);
+ end
+ endtask
+
+ // Push a packet with a ramp on to the AXI Stream bus
+ // Args:
+ // - num_samps: Packet size.
+ // - ramp_start: Start value for the ramp
+ // - ramp_inc: Increment per clock cycle
+ // - hdr: Header to attach to packet (length will be ignored)
+ // - stream: Stream to use (Optional)
+ task automatic push_ramp_pkt (
+ input integer num_samps,
+ input logic [63:0] ramp_start,
+ input logic [63:0] ramp_inc,
+ input cvita_hdr_t hdr,
+ input int stream = 0);
+ begin
+ automatic integer counter = 0;
+ cvita_hdr_t tmp_hdr = hdr;
+ tmp_hdr.length = (num_samps * 8) + (hdr.has_time ? 16 : 8);
+ @(negedge clk);
+ push_hdr(tmp_hdr);
+ if (hdr.has_time) push_word(hdr.timestamp, 0, stream);
+ repeat(num_samps-1) begin
+ push_word(ramp_start+(counter*ramp_inc), 0, stream);
+ counter = counter + 1;
+ end
+ push_word(ramp_start+(counter*ramp_inc), 1, stream);
+ end
+ endtask
+
+ // Push a packet on to the AXI Stream bus.
+ // Args:
+ // - pkt: Packet data (queue)
+ // - stream: Stream to use (Optional)
+ task automatic push_pkt (
+ input cvita_pkt_t pkt,
+ input int stream = 0);
+ begin
+ // Use $ceil() to match packets with partial lines
+ int pkt_size;
+ // Vivado XSIM workaround
+ cvita_payload_t payload = pkt.payload;
+ pkt_size = (pkt.hdr.has_time ? payload.size() + 2 : payload.size() + 1);
+ assert (pkt.hdr.length == 8*pkt_size || pkt.hdr.length == 8*pkt_size-4)
+ else $error("cvita_master::push_pkt(): Packet size does not match packet length in header! Header: %0d, Actual: %0d",
+ pkt.hdr.length, 8*pkt_size);
+ if (pkt.hdr.length == 8) begin
+ push_word(pkt.hdr[127:64], 1, stream);
+ end else begin
+ push_word(pkt.hdr[127:64], 0, stream);
+ if (pkt.hdr.has_time) begin
+ push_word(pkt.hdr[63:0], (pkt.hdr.length == 16), stream);
+ end
+ for (int i = 0; i < pkt.payload.size()-1; i = i + 1) begin
+ push_word(pkt.payload[i], 0, stream);
+ end
+ push_word(pkt.payload[pkt.payload.size()-1], 1, stream);
+ end
+ end
+ endtask
+
+endinterface
+
+
+// Interface and tasks to receive CVITA packets over a slave AXI-Stream bus
+interface cvita_slave #(parameter DWIDTH = 64, parameter NUM_STREAMS = 1)(input clk);
+ axis_t #(.DWIDTH(DWIDTH), .NUM_STREAMS(NUM_STREAMS)) axis(.clk(clk));
+
+ // Check that stream is actually in use
+ function void check_stream(int stream);
+ assert (stream < NUM_STREAMS) else
+ $error("cvita_slave::check_stream(): Tried to perform operation on unused stream %0d", stream);
+ endfunction
+
+ // Reset signals / properties used by this interface
+ task automatic reset;
+ begin
+ axis.tready = 0;
+ end
+ endtask
+
+ // Accept a sample on the AXI Stream bus and
+ // return the data and last
+ // Args:
+ // - word: The data pulled from the bus
+ // - eop: End of packet (tlast)
+ // - stream: Stream to use (Optional)
+ task automatic pull_word (
+ output logic [DWIDTH-1:0] word,
+ output logic eop,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ if (clk) @(negedge clk);
+ axis.tready[stream] = 1;
+ while(~axis.tvalid[stream]) @(posedge clk);
+ word = axis.tdata[DWIDTH*stream +: DWIDTH];
+ eop = axis.tlast[stream];
+ @(negedge clk);
+ axis.tready[stream] = 0;
+ end
+ endtask
+
+ // Wait for a sample to be transferred on the AXI Stream
+ // bus and return the data and last. Note, this task only
+ // observes the bus and does not affect the AXI control
+ // signals.
+ // Args:
+ // - word: The data pulled from the bus
+ // - eop: End of packet (tlast)
+ // - stream: Stream to use (Optional)
+ task automatic copy_word (
+ output logic [DWIDTH-1:0] word,
+ output logic eop,
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(~(axis.tready[stream]&axis.tvalid[stream])) @(posedge clk); // Wait until sample is transferred
+ word = axis.tdata[DWIDTH*stream +: DWIDTH];
+ eop = axis.tlast[stream];
+ @(negedge clk);
+ end
+ endtask
+
+ // Wait for a bubble cycle on the AXI Stream bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic wait_for_bubble (
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(axis.tready[stream]&axis.tvalid[stream]) @(posedge clk);
+ @(negedge clk);
+ end
+ endtask
+
+ // Wait for a packet to finish on the bus
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic wait_for_pkt (
+ input int stream = 0);
+ begin
+ check_stream(stream);
+ while(~(axis.tready[stream]&axis.tvalid[stream]&axis.tlast[stream])) @(posedge clk);
+ @(negedge clk);
+ end
+ endtask
+
+ // Pull a packet from the AXI Stream bus.
+ // Args:
+ // - pkt: Packet data (queue)
+ // - stream: Stream to use (Optional)
+ task automatic pull_pkt (
+ output cvita_pkt_t pkt,
+ input int stream = 0);
+ begin
+ cvita_payload_t payload; // Vivado XSIM work around
+ logic [63:0] word;
+ int i = 0;
+ logic eop = 0;
+ int pkt_size;
+
+ while(~eop) begin
+ pull_word(word, eop, stream);
+ if (i == 0) begin
+ pkt.hdr[127:64] = word;
+ end else if ((i == 1) && pkt.hdr.has_time) begin
+ pkt.hdr[63:0] = word;
+ end else begin
+ payload.push_back(word);
+ end
+ i++;
+ end
+ pkt.payload = payload;
+ pkt_size = (pkt.hdr.has_time ? payload.size() + 2 : payload.size() + 1);
+ assert (pkt.hdr.length == 8*pkt_size || pkt.hdr.length == 8*pkt_size-4)
+ else $error("cvita_slave::pull_pkt(): Packet size does not match packet length in header! Header: %0d, Actual: %0d",
+ pkt.hdr.length, pkt_size*8);
+ end
+ endtask
+
+ // Pull a packet from the AXI Stream bus and
+ // drop it instead of passing data to the user.
+ // Args:
+ // - stream: Stream to use (Optional)
+ task automatic drop_pkt (
+ input int stream = 0);
+ begin
+ cvita_pkt_t pkt;
+ pull_pkt(pkt, stream);
+ end
+ endtask
+
+ // Vivado XSIM workaround, cannot be made into a task (with ref inputs) due to segfault
+ `define WAIT_FOR_PKT_GET_INFO__UPDATE \
+ stats.count = stats.count + 1; \
+ stats.sum = stats.sum + axis.tdata[DWIDTH*stream +: DWIDTH]; \
+ stats.crc = stats.crc ^ axis.tdata[DWIDTH*stream +: DWIDTH]; \
+ if (axis.tdata < stats.min) stats.min = axis.tdata[DWIDTH*stream +: DWIDTH]; \
+ if (axis.tdata > stats.max) stats.max = axis.tdata[DWIDTH*stream +: DWIDTH];
+
+ // Wait for a packet to finish on the bus
+ task automatic wait_for_pkt_get_info (
+ output cvita_hdr_t hdr,
+ output cvita_stats_t stats,
+ input int stream = 0);
+ begin
+ automatic logic is_hdr = 1;
+ automatic logic is_time = 0;
+ stats.count = 32'h0;
+ stats.sum = 64'h0;
+ stats.min = 64'h7FFFFFFFFFFFFFFF;
+ stats.max = 64'h0;
+ stats.crc = 64'h0;
+ check_stream(stream);
+ @(posedge clk);
+ //Corner case. We are already looking at the end
+ //of a packet i.e. its just a header
+ if (axis.tready[stream]&axis.tvalid[stream]&axis.tlast[stream]) begin
+ unflatten_chdr_no_ts(axis.tdata[DWIDTH*stream +: DWIDTH], hdr);
+ @(negedge clk);
+ end else begin
+ while(~(axis.tready[stream]&axis.tvalid[stream]&axis.tlast[stream])) begin
+ if (axis.tready[stream]&axis.tvalid[stream]) begin
+ if (is_hdr) begin
+ unflatten_chdr_no_ts(axis.tdata[DWIDTH*stream +: DWIDTH], hdr);
+ is_time = hdr.has_time;
+ is_hdr = 0;
+ end else if (is_time) begin
+ hdr.timestamp = axis.tdata[DWIDTH*stream +: DWIDTH];
+ is_time = 0;
+ end else begin
+ `WAIT_FOR_PKT_GET_INFO__UPDATE
+ end
+ end
+ @(posedge clk);
+ end
+ `WAIT_FOR_PKT_GET_INFO__UPDATE
+ @(negedge clk);
+ end
+ end
+ endtask
+
+ `undef WAIT_FOR_PKT_GET_INFO__UPDATE
+
+endinterface
+
+`endif \ No newline at end of file