diff options
Diffstat (limited to 'fpga/usrp3/sim/axi')
-rw-r--r-- | fpga/usrp3/sim/axi/Makefile.srcs | 12 | ||||
-rw-r--r-- | fpga/usrp3/sim/axi/sim_axi4_lib.svh | 93 | ||||
-rw-r--r-- | fpga/usrp3/sim/axi/sim_axis_lib.svh | 219 | ||||
-rw-r--r-- | fpga/usrp3/sim/axi/sim_cvita_lib.svh | 440 |
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 |