1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
//
// Copyright 2015 Ettus Research LLC
//
`include "sim_axis_lib.svh"
typedef enum logic [1:0] {
DATA=2'b00, FC=2'b01, CMD=2'b10, RESP=2'b11
} cvita_pkt_t;
typedef struct packed {
logic [31:0] sid;
logic [15:0] length;
logic [11:0] seqno;
logic eob;
logic has_time;
cvita_pkt_t pkt_type;
logic [63:0] timestamp;
} cvita_hdr_t;
function logic[63:0] flatten_chdr_no_ts(input cvita_hdr_t hdr);
return {hdr.pkt_type, hdr.has_time, hdr.eob, hdr.seqno, hdr.length, hdr.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_t'(hdr_bits[63:62]), has_time:hdr_bits[61], eob:hdr_bits[60],
seqno:hdr_bits[59:48], length:hdr_bits[47:32], sid:hdr_bits[31:0], timestamp:0 //Default timestamp
};
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_t'(hdr_bits[63:62]), has_time:hdr_bits[61], eob:hdr_bits[60],
seqno:hdr_bits[59:48], length:hdr_bits[47:32], sid:hdr_bits[31: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.seqno == b.seqno) && (a.length == b.length) && (a.sid == b.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 cvita_stream_t (input clk);
axis_t #(.DWIDTH(64)) axis (.clk(clk));
// Push a CVITA header into the stream
// Args:
// - hdr: The header to push
task automatic push_hdr;
input cvita_hdr_t hdr;
axis.push_word(flatten_chdr_no_ts(hdr), 0);
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)
task automatic push_data;
input logic [63:0] word;
input logic eop;
axis.push_word(word, eop);
endtask
// Push a bubble cycle on the AXI-Stream bus
task automatic push_bubble;
axis.push_bubble();
endtask
// Wait for a sample to be transferred on the AXI Stream
// bus and return the data and last
// Args:
// - word: The data pulled from the bus
// - eop: End of packet (tlast)
task automatic pull_word;
output logic [63:0] word;
output logic eop;
axis.pull_word(word, eop);
endtask
// Wait for a bubble cycle on the AXI Stream bus
task automatic wait_for_bubble;
axis.wait_for_bubble();
endtask
// Wait for a packet to finish on the bus
task automatic wait_for_pkt;
axis.wait_for_pkt();
endtask
`define WAIT_FOR_PKT_GET_INFO__UPDATE \
stats.count = stats.count + 1; \
stats.sum = stats.sum + axis.tdata; \
stats.crc = stats.crc ^ axis.tdata; \
if (axis.tdata < stats.min) stats.min = axis.tdata; \
if (axis.tdata > stats.max) stats.max = axis.tdata;
// 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;
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;
@(posedge clk);
//Corner case. We are already looking at the end
//of a packet i.e. its just a header
if (axis.tready&axis.tvalid&axis.tlast) begin
unflatten_chdr_no_ts(axis.tdata, hdr);
@(negedge clk);
end else begin
while(~(axis.tready&axis.tvalid&axis.tlast)) begin
if (axis.tready&axis.tvalid) begin
if (is_hdr) begin
unflatten_chdr_no_ts(axis.tdata, hdr);
is_time = hdr.has_time;
is_hdr = 0;
end else if (is_time) begin
hdr.timestamp = axis.tdata;
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
// 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)
// - timestamp: Optional timestamp
task automatic push_rand_pkt;
input integer num_samps;
input cvita_hdr_t hdr;
begin
cvita_hdr_t tmp_hdr = hdr;
tmp_hdr.length = num_samps + (hdr.has_time ? 16 : 8);
@(negedge clk);
push_hdr(tmp_hdr);
if (hdr.has_time) axis.push_word(hdr.timestamp, 0);
repeat(num_samps-1) begin
axis.push_word({$random,$random}, 0);
end
axis.push_word({$random,$random}, 1);
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)
// - timestamp: Optional timestamp
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;
begin
automatic integer counter = 0;
cvita_hdr_t tmp_hdr = hdr;
tmp_hdr.length = num_samps + (hdr.has_time ? 16 : 8);
@(negedge clk);
push_hdr(tmp_hdr);
if (hdr.has_time) axis.push_word(hdr.timestamp, 0);
repeat(num_samps-1) begin
axis.push_word(ramp_start+(counter*ramp_inc), 0);
counter = counter + 1;
end
axis.push_word(ramp_start+(counter*ramp_inc), 1);
end
endtask
endinterface
|