AXI muckbucket
axi_responder.svh
Go to the documentation of this file.
1 //
3 // Copyright (C) 2017, Matt Dew @ Dew Technologies, LLC
4 //
5 // This program is free software (logic verification): you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public License (LGPL)
7 // as published by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 // for more details.
14 //
15 // License: LGPL, v3, as defined and found on www.gnu.org,
16 // http://www.gnu.org/licenses/lgpl.html
17 //
18 //
19 // Author's intent: If you use this AXI verification code and find or fix bugs
20 // or make improvements, then share those fixes or improvements.
21 // If you use this in a bigger project, I don't care about,
22 // or want, any changes or code outside this block.
23 // Example: If you use this in an SoC simulation/testbench
24 // I don't want, or care about, your SoC or other blocks.
25 // I just care about the enhancements to these AXI files.
26 // That's why I have choosen the LGPL instead of the GPL.
28 
31 class axi_responder : public uvm_driver <axi_seq_item> { public:
33 
34  axi_if_abstract vif;
37 
38  mailbox <axi_seq_item> writeaddress_mbx = new(0); //unbounded mailboxes
39  mailbox <axi_seq_item> writedata_mbx = new(0);
40  mailbox <axi_seq_item> writeresponse_mbx = new(0);
41  mailbox <axi_seq_item> readaddress_mbx = new(0);
42  mailbox <axi_seq_item> readdata_mbx = new(0);
43 
44  new (string name="axi_responder", uvm_component parent=null);
45 
46  void build_phase (uvm_phase phase);
47  void connect_phase (uvm_phase phase);
48  task run_phase (uvm_phase phase);
49 
50  task write_address ();
51  task write_data ();
52  task write_response ();
53  task read_address ();
54  task read_data ();
55 
56 };
57 
61  axi_responder::new (string name = "axi_responder", uvm_component parent = null) {
62  super.new(name, parent);
63 }
64 
66  void axi_responder::build_phase (uvm_phase phase) {
67  super.build_phase(phase);
68 
69  vif = axi_if_abstract::type_id::create("vif", this);
70 }
71 
76  void axi_responder::connect_phase (uvm_phase phase) {
77  super.connect_phase(phase);
78 }
79 
90 task axi_responder::run_phase(uvm_phase phase) {
91 
92  axi_seq_item item;
93 
94  fork
95  write_address();
96  write_data();
98  read_address();
99  read_data();
100  join_none
101 
102  forever {
103 
104  seq_item_port.get(item);
105 
106  uvm_info(this.get_type_name(),
107  $sformatf("Item: %s", item.convert2string()),
108  UVM_INFO)
109 
110  case (item.cmd) {
111 
113  writeaddress_mbx.put(item);
114  }
115 
117  readdata_mbx.put(item);
118  }
119 
120  }
121 
122  } // forever
123 
124 }
125 
135 
136  axi_seq_item item;
138 
139  vif.enable_awready_toggle_pattern(m_config.awready_toggle_pattern);
140 
141  forever {
142  writeaddress_mbx.get(item);
143 
144  writedata_mbx.put(item);
145  }
146 }
147 
148 
149 
159 
160  int i;
161  axi_seq_item item;
162  axi_seq_item litem;
163  int datacnt;
165  bit foo;
166  bit wlast;
167 
168  vif.enable_wready_toggle_pattern(m_config.wready_toggle_pattern);
169 
170  forever {
171  writedata_mbx.get(item);
172  uvm_info(this.get_type_name(),
173  $sformatf("axi_responder::write_data - Waiting for data for %s",
174  item.convert2string()),
175  UVM_INFO)
176  wlast=0b0;
177  while (wlast != 0b1) {
178  vif.wait_for_write_data(.s(s));
179  wlast=s.wlast;
180  }
181  // \todo: Dont rely on wlast
182 
183  writeresponse_mbx.put(item);
184  }
185 }
186 
200  axi_seq_item item=null;
202 
203 
204  bit <ADDR_WIDTH-1:0> aligned_addr;
205 
206  int minval;
207  int maxval;
208  int wait_clks_before_next_b;
209 
210  vif.set_bvalid(0b0);
211  forever {
212 
213  if (item == null) {
214  writeresponse_mbx.get(item);
215  uvm_info(this.get_type_name(),
216  $sformatf("axi_responder::write_response - Waiting for data for %s",
217  item.convert2string()),
218  UVM_INFO)
219  }
220 
221  vif.wait_for_clks(.cnt(1));
222 
223  // if done with this xfer (write address is only one clock, done with valid & ready
224  if (vif.get_bready_bvalid == 0b1) {
225 
226  item=null;
227 
230  wait_clks_before_next_b=$urandom_range(maxval,minval);
231 
232  // Check if delay wanted
233  if (wait_clks_before_next_b==0) {
234  // if not, check if there's another item
235 
236  if (writeresponse_mbx.try_get(item)) {
237 
238  }
239  }
240  }
241 
242  // Initialize values
243 
244  // Update values <- No need in write address (only one clk per)
245 
246  // Write out
247  if (item != null) {
248  s.bid = 0x3;
249  s.bresp = 0x1;
250  vif.write_b(.s(s), .valid(0b1));
251  if (wait_clks_before_next_b > 0) {
252  vif.wait_for_clks(.cnt(wait_clks_before_next_b-1)); // -1 because another wait
253  // at beginning of loop
254  }
255  } // if (item != null)
256 
257  // No item for next clock, so close out bus
258  if (item == null) {
259  s.bid = 0x0;
260  s.bresp = 0x0;
261  vif.write_b(.s(s), .valid(0b0));
262  vif.wait_for_clks(.cnt(1));
263  }
264 
265  } // forever
266 
267 }
268 
275  vif.enable_arready_toggle_pattern(m_config.arready_toggle_pattern);
276 }
277 
289  axi_seq_item item=null;
290  axi_seq_item cloned_item;
292 
293 
294  int n=0;
295  int j;
296 
297  int minval;
298  int maxval;
299  int wait_clks_before_next_r;
300  int offset;
301  int beat_cntr=0;
302  int beat_cntr_max;
303  bit <7:0> rdata[];
304  bit strb []; // throwaway
305  int validcntr;
306  int validcntr_max;
307  int valid_assert_bit;
308  int clks_without_rvalid_or_rready;
309 
310  vif.set_rvalid(0b0);
311  forever {
312 
313  if (item == null) {
314  readdata_mbx.get(item);
315  beat_cntr=0;
316  beat_cntr_max=axi_pkg::calculate_axlen(.addr(item.addr),
317  .burst_size(item.burst_size),
318  .burst_length(item.len)) + 1;
319  validcntr=0;
320  validcntr_max=item.valid.size();
321  clks_without_rvalid_or_rready=0;
322  }
323  // Look at this only one per loop, so there's no race condition of it
324  // changing mid-loop.
325 
326  vif.wait_for_clks(.cnt(1));
327 
328  // defaults. not needed but I think is cleaner in sim
329  s.rvalid = 0b0;
330  s.rdata = 0xfeed_beef;
331  s.rid = 0x0;
332  // s.rstrb = 'h0;
333  s.rlast = 0b0;
334 
335  // Check if done with this transfer
336  if (vif.get_rready()==0b1 && vif.get_rvalid() == 10b1) {
337 /*
338  if (iaxi_incompatible_rready_toggling_mode == 1'b0) begin
339  if (++validcntr >= validcntr_max) begin
340  validcntr=0;
341  end
342  end
343 */
344  beat_cntr++;
345 
346 
347  if (beat_cntr >= beat_cntr_max) {
348 
349  item = null;
350 
351 
354  wait_clks_before_next_r=$urandom_range(maxval,minval);
355 
356  // Check if delay wanted
357  if (wait_clks_before_next_r==0) {
358  // if not, check if there's another item
359 
360  if (readdata_mbx.try_get(item)) {
361  beat_cntr=0;
362  beat_cntr_max=axi_pkg::calculate_axlen(.addr(item.addr),
363  .burst_size(item.burst_size),
364  .burst_length(item.len)) + 1;
365  validcntr=0;
366  validcntr_max=item.valid.size();
367  clks_without_rvalid_or_rready=0;
368  }
369 
370  }
371  }
372  } // (vif.get_rready()==1'b1 && vif.get_rvalid() == 1'b1)
373 
374 
375 
376 
377  // Update values
378  if (item != null) {
379  // if too long withoutsending any data, then add an extra valid.
380  // it is entirely possible for ready and valid to not have overlap,
381  // which will hang the sim. Add additional valids to counteract.
382  // \Todo: Need to report all this to help with reproducing bugs
383  if (vif.get_rready()==0b0 && vif.get_rvalid() == 10b0) {
384  clks_without_rvalid_or_rready++;
385  if (clks_without_rvalid_or_rready > m_config.clks_without_rvalid_or_rready_max) {
386  j=item.valid.size();
387 
388  valid_assert_bit=$urandom_range(j-1,0);
389  item.valid[valid_assert_bit] = 0b1;
390  uvm_info("axi_driver::write_data",
391  $sformatf("%0d clocks without ready/valid overlap. Setting another valid[], bit %0d, to 1", clks_without_rvalid_or_rready, valid_assert_bit),
392  UVM_INFO)
393  clks_without_rvalid_or_rready=0;
394  }
395  }
396 
397  s.rvalid = item.valid[validcntr];
398 
399 
400 
401  uvm_info(this.get_type_name(),
402  $sformatf("Calling get_beat_N_data: %s",
403  item.convert2string()),
404  UVM_HIGH)
405 
406  item.get_beat_N_data(.beat_cnt(beat_cntr),
407  .data_bus_bytes(vif.get_data_bus_width()/8),
408  .data(rdata),
409  .wstrb(strb),
410  .wlast(s.rlast));
411 
412  for (int x=0;x <vif.get_data_bus_width()/8;x++) {
413  s.rdata[x*8+:8] = rdata[x];
414  }
415 
416  // Write out
417  vif.write_r(.s(s));
418 
419 
420  // if invalid-toggling-mode is enabled, then allow deasserting valid
421  // before ready asserts.
422  // Default is to stay asserted, and only allow deasssertion after ready asserts.
423  // if invalid-toggling-mode is enabled, then allow deasserting valid
424  // before ready asserts.
425  // Default is to stay asserted, and only allow deasssertion after ready asserts.
426  if (vif.get_rready()==0b1 && vif.get_rvalid() == 10b1) {
427  validcntr++;
428  uvm_info(this.get_type_name(),
429  $sformatf("debuga validcntr=%0d",validcntr),
430  UVM_HIGH)
432  validcntr++;
433  uvm_info(this.get_type_name(),
434  $sformatf("debugb validcntr=%0d",validcntr),
435  UVM_HIGH)
436  } else if (vif.get_rvalid() == 0b0) {
437  validcntr++;
438  uvm_info(this.get_type_name(),
439  $sformatf("debugc validcntr=%0d",validcntr),
440  UVM_HIGH)
441 
442  }
443  if (validcntr >= validcntr_max) {
444  validcntr=0;
445  }
446 
447 
448 
449  } // (item != null)
450 
451  // No item for next clock, so close out bus
452  if (item == null) {
453  s.rvalid = 0b0;
454  s.rlast = 0b0;
455  s.rdata = 0x0;
456  // s.wid = 'h0; AXI3 only
457  // s.rstrb = 'h0;
458 
459  vif.write_r(.s(s));
460 
461  if (wait_clks_before_next_r > 0) {
462  vif.wait_for_clks(.cnt(wait_clks_before_next_r-1));
463  // -1 because another wait
464  // at beginning of loop
465  }
466  } // if (item == null
467  } // forever
468 }
Logic to act as an AXI slave (responder) for all 5 channels.
rand cmd_t cmd
task run_phase(uvm_phase phase)
Launches channel responder threads and then acts as a dispatcher.
bit< C_AXI_LEN_WIDTH-1:0 > calculate_axlen(input bit< C_AXI_ADDR_WIDTH-1:0 > addr, input bit< 2:0 > burst_size, input shortint burst_length)
calculate awlen or arlen
Definition: axi_pkg.sv:320
mailbox< axi_seq_item > writedata_mbx
rand bit< 31:0 > arready_toggle_pattern
rand int len
string convert2string()
Convert item&#39;s variable into one printable string.
byte clks_without_rvalid_or_rready_max
Extremely simple memory model with just write() and read() methods.
Definition: memory.svh:32
logic< C_AXI_ID_WIDTH-1:0 > bid
Definition: axi_pkg.sv:163
task write_address()
Write Address channel thread.
This packed struct is used to send read data channel information between the DUT and TB...
Definition: axi_pkg.sv:205
mailbox< axi_seq_item > writeresponse_mbx
rand bit< 31:0 > awready_toggle_pattern
This packed struct is used to send write address channel information between the DUT and TB...
Definition: axi_pkg.sv:113
logic< 1:0 > bresp
Definition: axi_pkg.sv:164
mailbox< axi_seq_item > readdata_mbx
logic< C_AXI_DATA_WIDTH-1:0 > rdata
Definition: axi_pkg.sv:206
mailbox< axi_seq_item > writeaddress_mbx
rand bit< ADDR_WIDTH-1:0 > addr
void build_phase(uvm_phase phase)
Creates the virtual interface.
void connect_phase(uvm_phase phase)
Nothing to connect so doesn&#39;t actually do anything except call parent connect phase.
rand byte max_clks_between_r_transfers
abstract base class for polymorphic interface class (axi_if_concrete) for AXI UVM environment ...
rand byte max_clks_between_b_transfers
task read_address()
Read Address channel thread.
bit axi_incompatible_rvalid_toggling_mode
rand logic< 2:0 > burst_size
void get_beat_N_data(input int beat_cnt, input int data_bus_bytes, ref bit< 7:0 > data[], ref bit wstrb[], output bit wlast)
return beat values for write data and read data channels
task write_response()
Write Response channel thread.
logic< C_AXI_ID_WIDTH-1:0 > rid
Definition: axi_pkg.sv:210
rand bit valid[]
mailbox< axi_seq_item > readaddress_mbx
rand byte min_clks_between_r_transfers
This packed struct is used to send write data channel information between the DUT and TB...
Definition: axi_pkg.sv:141
uvm_component_utils(axi_responder) axi_if_abstract vif
task write_data()
Write Data channel thread.
axi_agent_config m_config
This packed struct is used to send write response channel information between the DUT and TB...
Definition: axi_pkg.sv:162
Configuration object for an axi_agent.
rand bit< 31:0 > wready_toggle_pattern
new(string name="axi_responder", uvm_component parent=null)
Constructor.
rand byte min_clks_between_b_transfers
contains all data and functions related to axi and usage
task read_data()
Read Data channel thread.
localparam ADDR_WIDTH
Definition: axi_uvm_pkg.sv:39