aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/sim/axi/sim_axis_lib.svh
blob: bdee113de7799edde15e7066342bb93169d2142f (plain)
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
212
213
214
215
216
217
218
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