AXI muckbucket
axi_pipelined_reads_seq.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 
35 class axi_pipelined_reads_seq : public axi_seq { public:
36 
38 
39  axi_seq_item read_item [];
40 
42 
43  // all write responses have been received
44  // Reads can go ahead
45  event reads_done;
46 
47 
48  typedef struct {
49  bit <ADDR_WIDTH-1:0> laddr;
50  bit <ADDR_WIDTH-1:0> uaddr;
51  } mem_chk_s;
52 
54 
55  new (string name="axi_pipelined_reads_seq");
56  task body();
57  void response_handler(uvm_sequence_item response);
58 
59 };
60 
61 
62 // This response_handler function is enabled to keep the sequence response FIFO empty
66  automatic void axi_pipelined_reads_seq::response_handler(uvm_sequence_item response) {
67 
68  axi_seq_item item;
69  int xfer_cnt;
70  int id;
71 
72  bit <ADDR_WIDTH-1:0> lower_addr;
73  bit <ADDR_WIDTH-1:0> upper_addr;
74 
75  $cast(item,response);
76 
77  xfer_cnt=item.id;
78 
79 
80  if (item.cmd == e_READ_DATA) {
81 
82  xfers_done++;
83 
84  id=item.get_transaction_id();
85 
86  lower_addr = mem_chk_array[id].laddr;
87  upper_addr = mem_chk_array[id].uaddr;
88 
89 
90  uvm_info("LLLLLLLLLLLLLLL",
91  $sformatf("SEQ_response_handler id:%0d uaddr=0x%0x laddr=0x%0x",
92  id, lower_addr, upper_addr),
93  UVM_INFO)
94 
95  if (!m_memory.seq_item_check(.item (item),
96  .lower_addr (lower_addr),
97  .upper_addr (upper_addr))) {
98  uvm_info("MISCOMPARE","Miscompare error", UVM_INFO)
99  }
100 
101  if (xfers_done >= xfers_to_send) {
102  uvm_info("axi_seq::response_handler::sending event ",
103  $sformatf("xfers_done:%0d xfers_to_send: %0d sending event",
105  UVM_INFO)
106  ->reads_done;
107  }
108 
109 }
110  uvm_info(this.get_type_name(),
111  $sformatf("SEQ_response_handler xfers_done=%0d/%0d. Item: %s",
113  UVM_INFO)
114 
115 
116 }
117 
122  axi_pipelined_reads_seq::new (string name="axi_pipelined_reads_seq") {
123  super.new(name);
124 }
125 
126 
141 
142  string s;
143 
144  bit <ADDR_WIDTH-1:0> addr_lo;
145  bit <ADDR_WIDTH-1:0> addr_hi;
146  bit <ID_WIDTH-1:0> xid;
147 
148  int max_beat_cnt;
149  int dtsize;
150  bit <ADDR_WIDTH-1:0> Lower_Wrap_Boundary;
151  bit <ADDR_WIDTH-1:0> Upper_Wrap_Boundary;
152  bit <ADDR_WIDTH-1:0> write_addr;
153 
154 
155  xfers_done=0;
156 
157  read_item = new [xfers_to_send];
158 
159  //mem_chk_array = new [xfers_to_send];
160 
161 
162 
163  use_response_handler(1); // Enable Response Handler
164 
165  if (!uvm_config_db <memory> ::get(null, "", "m_memory", m_memory)) {
166  uvm_fatal(this.get_type_name, "Unable to fetch m_memory from config db.")
167  }
168 
169 
170 
171  // Clear memory
172  // AXI write
173  // direct readback of memory
174  // check that addresses before Axi start address are still 0
175  // chck expected data
176  // check that addresses after axi start_addres+length are still 0
177 
178  for (int xfer_cnt=0;xfer_cnt <xfers_to_send;xfer_cnt++) {
179 
180  // clear memory
181  if (clearmemory==1) {
182  for (int i=0;i <window_size;i++) {
183  m_memory.write(i, 0x0);
184  }
185  }
186 
187  read_item[xfer_cnt] = axi_seq_item::type_id::create("read_item");
188  read_item[xfer_cnt].set_transaction_id(transaction_id++);
189 
190  // Not sure why I have to define and set these and
191  // then use them in the randomize with {} but
192  // Riviera Pro works better like this.
193  addr_lo=xfer_cnt*window_size;
194  addr_hi=addr_lo+0x100;
195  xid =xfer_cnt[ID_WIDTH-1:0];
196 
197 
198  mem_chk_array[read_item[xfer_cnt].get_transaction_id()].laddr =addr_lo;
199  mem_chk_array[read_item[xfer_cnt].get_transaction_id()].uaddr =addr_lo+window_size;
200 
201 
202  assert( read_item[xfer_cnt].randomize() with {
203  cmd == e_READ;
204  burst_size <= local::max_burst_size;
205  id == local::xid;
206  addr >= local::addr_lo;
207  addr < local::addr_hi;
208  len < 5;
209  })
210 
211 
212 
213 
214  //backdoor fill memory
215  case (read_item[xfer_cnt].burst_type) {
216  e_FIXED : {
217 
218  Lower_Wrap_Boundary = read_item[xfer_cnt].addr;
219  Upper_Wrap_Boundary = Lower_Wrap_Boundary + (2**read_item[xfer_cnt].burst_size);
220 
221  }
222  e_INCR : {
223  Lower_Wrap_Boundary = read_item[xfer_cnt].addr;
224  Upper_Wrap_Boundary = Lower_Wrap_Boundary + read_item[xfer_cnt].len;
225 
226  }
227  e_WRAP : {
228  max_beat_cnt = axi_pkg::calculate_axlen(.addr(read_item[xfer_cnt].addr),
229  .burst_size(read_item[xfer_cnt].burst_size),
230  .burst_length(read_item[xfer_cnt].len)) + 1;
231 
232  dtsize = (2**read_item[xfer_cnt].burst_size) * max_beat_cnt;
233 
234  Lower_Wrap_Boundary = (int(read_item[xfer_cnt].addr/dtsize) * dtsize);
235  Upper_Wrap_Boundary = Lower_Wrap_Boundary + dtsize;
236 
237  }
238  }
239 
240  write_addr = read_item[xfer_cnt].addr;
241  for (int i=0;i <read_item[xfer_cnt].len;i++) {
242  m_memory.write(write_addr, i[8]);
243  write_addr++;
244  if (write_addr >= Upper_Wrap_Boundary) {
245  write_addr = Lower_Wrap_Boundary;
246  }
247  }
248 
249  start_item(read_item[xfer_cnt]);
250 
251  uvm_info("YOYOYOYOYOYO",
252  $sformatf("Transactionid: %0d", read_item[xfer_cnt].get_transaction_id()),
253  UVM_INFO)
254 
255  uvm_info(this.get_type_name(),
256  $sformatf("item %0d id:0x%0x addr_lo: 0x%0x addr_hi: 0x%0x",
257  xfer_cnt, xid, addr_lo,addr_hi),
258  UVM_INFO)
259 
260 
261 
262  // If valid specified, then pass it to seq item.
263  if (valid.size() > 0) {
264  read_item[xfer_cnt].valid = new[valid.size()](valid);
265  }
266 
267  uvm_info("DATA", $sformatf("\n\n\nItem %0d: %s", xfer_cnt, read_item[xfer_cnt].convert2string()), UVM_INFO)
268  finish_item(read_item[xfer_cnt]);
269 
270  } //for
271 
272 
273  uvm_info("READBACK", "writes done. waiting for event trigger", UVM_INFO)
274  wait (reads_done.triggered);
275  uvm_info("READBACK", "event trigger detected1111", UVM_INFO)
276 
277  uvm_info(this.get_type_name(), "SEQ ALL DONE", UVM_INFO)
278 
279 }
280 
rand cmd_t cmd
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
string convert2string()
Convert item&#39;s variable into one printable string.
int xfers_to_send
Definition: axi_seq.svh:40
int xfers_done
Definition: axi_seq.svh:46
rand bit< ID_WIDTH-1:0 > id
Backdoor memory writes, then reads from memory over AXI.
localparam ID_WIDTH
Definition: axi_uvm_pkg.sv:40
bit seq_item_check(ref axi_seq_item item, input bit< ADDR_WIDTH-1:0 > lower_addr, input bit< ADDR_WIDTH-1:0 > upper_addr)
Compares an axi_seq_item&#39;s data and burst_type against expected matching memory contents.
Definition: memory.svh:85
uvm_object_utils(axi_pipelined_reads_seq) axi_seq_item read_item[]
virtual void write(input bit< ADDR_WIDTH-1:0 > addr, input bit< 7:0 > data)
Writes into memory.
Definition: memory.svh:58
const int window_size
Definition: axi_seq.svh:39
new(string name="axi_pipelined_reads_seq")
Constructor.
memory m_memory
Definition: axi_seq.svh:48
task body()
Does all the work.
bit valid[]
Definition: axi_seq.svh:42
void response_handler(uvm_sequence_item response)
Handles write responses, including verifying memory via backdoor reads.
Writes to memory over AXI, backdoor readback, then AXI readback.
Definition: axi_seq.svh:33
contains all data and functions related to axi and usage
localparam ADDR_WIDTH
Definition: axi_uvm_pkg.sv:39