AXI muckbucket
memory.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 
32 class memory : public uvm_component { public:
33  uvm_component_utils(memory)
34 
35  bit <7:0> mem[*];
36 
37  //localparam addr_width=params_pkg::AXI_ADDR_WIDTH;//64;
38 
39  new(string name="memory", uvm_component parent=null);
40  virtual void write(input bit <ADDR_WIDTH-1:0> addr, input bit <7:0> data);
41  virtual bit <7:0> read (input bit <ADDR_WIDTH-1:0> addr);
42  bit seq_item_check(ref axi_seq_item item,
43  input bit <ADDR_WIDTH-1:0> lower_addr,
44  input bit <ADDR_WIDTH-1:0> upper_addr);
45 
46 };
47 
51  memory::new(string name="memory", uvm_component parent=null) {
52  super.new(name, parent);
53 }
54 
58  automatic void memory::write(input bit <ADDR_WIDTH-1:0> addr, input bit <7:0> data) {
59  uvm_info(this.get_type_name(), $sformatf("write mem(0x%0x)=0x%0x", addr, data), UVM_HIGH)
60  mem[addr] = data;
61 }
62 
67  automatic bit <7:0> memory::read(input bit <ADDR_WIDTH-1:0> addr) {
68  if (mem.exists(addr)) {
69  uvm_info(this.get_type_name(), $sformatf("read mem(0x%0x)=0x%0x", addr, mem[addr]), UVM_HIGH)
70 
71  return mem[addr];
72  } else {
73  uvm_info(this.get_type_name(),
74  $sformatf("read unwritten memory address [0x%0x]", addr),
75  UVM_HIGH)
76  return z;
77  }
78 }
79 
85  automatic bit memory::seq_item_check(
86  ref axi_seq_item item,
87  input bit <ADDR_WIDTH-1:0> lower_addr,
88  input bit <ADDR_WIDTH-1:0> upper_addr) {
89 
90 
91  const int postcheck = 1;
92  const int precheck = 1;
93 
94 
95  int max_beat_cnt;
96  int dtsize;
97 
98  bit <ADDR_WIDTH-1:0> Lower_Wrap_Boundary;
99  bit <ADDR_WIDTH-1:0> Upper_Wrap_Boundary;
100  bit <ADDR_WIDTH-1:0> iaddr;
101 
102  bit <ADDR_WIDTH-1:0> pre_check_start_addr;
103  bit <ADDR_WIDTH-1:0> pre_check_stop_addr;
104 
105  bit <ADDR_WIDTH-1:0> check_start_addr;
106  bit <ADDR_WIDTH-1:0> check_stop_addr;
107 
108  bit <ADDR_WIDTH-1:0> post_check_start_addr;
109  bit <ADDR_WIDTH-1:0> post_check_stop_addr;
110 
111 
112  // string write_item_s;
113  int idatacntr;
114  int miscompare_cntr;
115  string write_item_s;
116  string read_item_s;
117  string expected_data_s;
118  string actual_data_s;
119  string msg_s;
120  string localbuffer_s;
121  int rollover_cnt;
122 
123  bit <7:0> expected_data_array [];
124  bit <7:0> actual_data_array [];
125 
126  bit <2:0> max_burst_size;
127  int yy;
128  bit <7:0> localbuffer [];
129  bit <7:0> read_data;
130  bit <7:0> expected_data;
131 
132 
133  assert (item != null);
134 
135  if (item == null) {
136  uvm_fatal(this.get_type_name(), "Item is null")
137  }
138 
139 
140 
141 
142  //***** Readback
143  uvm_info("...", "Now reading back from memory to verify", UVM_LOW)
144 
145 
146  if (item.burst_type == e_WRAP) {
147 
148 
149  max_beat_cnt = axi_pkg::calculate_axlen(.addr(item.addr),
150  .burst_size(item.burst_size),
151  .burst_length(item.len)) + 1;
152 
153  dtsize = (2**item.burst_size) * max_beat_cnt;
154 
155  Lower_Wrap_Boundary = (int(item.addr/dtsize) * dtsize);
156  Upper_Wrap_Boundary = Lower_Wrap_Boundary + dtsize;
157 
158  pre_check_start_addr = lower_addr;
159  pre_check_stop_addr = Lower_Wrap_Boundary;
160 
161  check_start_addr = Lower_Wrap_Boundary;
162  check_stop_addr = Upper_Wrap_Boundary;
163 
164  post_check_start_addr = Upper_Wrap_Boundary;
165  post_check_stop_addr = upper_addr;
166 
167  } else {
168  pre_check_start_addr = lower_addr;
169  pre_check_stop_addr = item.addr; // only different if burst_type=e_WRAP;
170 
171  check_start_addr = item.addr;
172  check_stop_addr = item.addr+item.len;
173 
174  post_check_start_addr = item.addr+item.len;
175  post_check_stop_addr = upper_addr;
176  }
177 
178  msg_s="";
179  $sformat(msg_s, "%s Item: %s", msg_s, item.convert2string());
180  $sformat(msg_s, "%s pre_check_start_addr: 0x%0x", msg_s, pre_check_start_addr);
181  $sformat(msg_s, "%s pre_check_stop_addr: 0x%0x", msg_s, pre_check_stop_addr);
182  $sformat(msg_s, "%s check_start_addr: 0x%0x", msg_s, check_start_addr);
183  $sformat(msg_s, "%s check_stop_addr: 0x%0x", msg_s, check_stop_addr);
184  $sformat(msg_s, "%s post_check_start_addr: 0x%0x", msg_s, post_check_start_addr);
185  $sformat(msg_s, "%s post_check_stop_addr: 0x%0x", msg_s, post_check_stop_addr);
186  $sformat(msg_s, "%s Lower_Wrap_Boundary: 0x%0x", msg_s, Lower_Wrap_Boundary);
187  $sformat(msg_s, "%s Upper_Wrap_Boundary: 0x%0x", msg_s, Upper_Wrap_Boundary);
188 
189 
190  uvm_info("CHECK MEMORY",
191  msg_s,
192  UVM_INFO)
193 
194 
195 
196  miscompare_cntr=0;
197 
198  // compare pre-data
199  if (precheck==1) {
200  expected_data=0x0;
201  for (int i=pre_check_start_addr;i <pre_check_stop_addr;i++) {
202  read_data=read(i);
203  assert(expected_data==read_data) else {
204  miscompare_cntr++;
205  uvm_error("MEMORY PRE-CHECK miscompare",
206  $sformatf("Address: 0x%0x expected: 0x%0x actual:0x%0x",
207  i,
208  expected_data,
209  read_data))
210  }
211  }
212  } // if precheck
213 
214  // compare data
215  if (item.burst_type == e_FIXED) {
216 
217  expected_data_array = new[2**item.burst_size];
218  actual_data_array = new[2**item.burst_size];
219  localbuffer = new[2**item.burst_size];
220  // brute force, not elegant at all.
221  // write to local buffer, then compare that buffer (repeated) with the axi readback
222 
223 
224  yy=0;
225 
226  for (int y=0;y <localbuffer.size();y++) {
227  localbuffer[y]=0x0;
228  }
229  for (int y=0;y <item.len;y++) {
230  localbuffer[yy++]=item.data[y];
231  if (yy >= 2**item.burst_size) {
232  yy=0;
233  }
234  }
235 
236  yy=0;
237  for (int y=0; y <expected_data_array.size(); y++) {
238  expected_data_array[y]=localbuffer[yy++];
239  if (yy >= localbuffer.size()) {
240  yy=0;
241  }
242  }
243 /*
244  for (int y=0;y<item.data.size();y++) begin
245  expected_data = expected_data_array[y];
246  read_data = read(item.addr+y);
247  actual_data_array[y] = read_data;
248  if (expected_data!=read_data) begin
249  miscompare_cntr++;
250  end
251  end
252 */
253 
254  // on a fixed burst, we only need to compare last beat of data
255  for (int y=0;y <localbuffer.size();y++) {
256  expected_data = expected_data_array[y];
257  read_data = read(item.addr+y);
258  actual_data_array[y] = read_data;
259  if (expected_data!=read_data) {
260  miscompare_cntr++;
261  }
262  }
263 
264  assert (miscompare_cntr==0) else {
265  write_item_s="";
266 // read_item_s="";
267  expected_data_s="";
268  actual_data_s="";
269  localbuffer_s="";
270 
271  for (int z=0;z <item.data.size();z++) {
272  $sformat(write_item_s, "%s 0x%2x", write_item_s, item.data[z]);
273  }
274 
275 
276  for (int z=0;z <expected_data_array.size();z++) {
277  $sformat(expected_data_s, "%s 0x%2x", expected_data_s, expected_data_array[z]);
278  }
279 
280  for (int z=0;z <actual_data_array.size();z++) {
281  $sformat(actual_data_s, "%s 0x%2x", actual_data_s, actual_data_array[z]);
282  }
283 
284  for (int z=0;z <localbuffer.size();z++) {
285  $sformat(localbuffer_s, "%s 0x%2x", localbuffer_s, localbuffer[z]);
286  }
287 
288  msg_s="";
289  $sformat(msg_s, "%s %0d miscompares between expected and actual data items.", msg_s, miscompare_cntr );
290  $sformat(msg_s, "%s \nExpected: %s", msg_s, expected_data_s);
291  $sformat(msg_s, "%s \nActual: %s", msg_s, actual_data_s);
292  $sformat(msg_s, "%s \nWritten: %s", msg_s, write_item_s);
293  $sformat(msg_s, "%s \nLocalbuffer: %s", msg_s, localbuffer_s);
294 
295  uvm_error("READBACK e_FIXED miscompare", msg_s);
296  }
297 
298 
299 
300 
301  } else if (item.burst_type == e_INCR) {
302  for (int z=0;z <item.len;z++) {
303  expected_data=item.data[z];
304  read_data=read(item.addr+z);
305  //s=$sformatf("%s 0x%0x", s, read_data);
306  assert(expected_data==read_data) else {
307  miscompare_cntr++;
308  uvm_error("e_INCR miscompare",
309  $sformatf("addr:0x%0x expected: 0x%0x actual:0x%0x",
310  item.addr+z,
311  expected_data,
312  read_data))
313  }
314  }
315  } else if (item.burst_type == e_WRAP) {
316 
317  if (item.addr + item.len < Upper_Wrap_Boundary) {
318  expected_data=0x0;
319  for (int z=Lower_Wrap_Boundary;z <item.addr;z++) {
320  read_data=read(z);
321  assert(expected_data==read_data) else {
322  miscompare_cntr++;
323  uvm_fatal("e_WRAP miscompare",
324  $sformatf("expected: 0x%0x actual:0x%0x",
325  expected_data,
326  read_data))
327  }
328  }
329 
330  for (int z=0;z <item.len;z++) {
331  expected_data=item.data[z];
332  read_data=read(item.addr+z);
333  assert(expected_data==read_data) else {
334  miscompare_cntr++;
335  uvm_fatal("e_WRAP miscompare",
336  $sformatf("expected: 0x%0x actual:0x%0x",
337  expected_data,
338  read_data))
339  }
340  }
341 
342  expected_data=0x0;
343  for (int z=item.addr+item.len;z <Upper_Wrap_Boundary;z++) {
344  read_data=read(z);
345  assert(expected_data==read_data) else {
346  miscompare_cntr++;
347  uvm_fatal("e_WRAP miscompare",
348  $sformatf("expected: 0x%0x actual:0x%0x",
349  expected_data,
350  read_data))
351  }
352  }
353 
354 
355  } else { // data actually wraps.
356 
357  // compare beginning of data, which is towards the end of the boundary window
358  for (int i=item.addr; i <Upper_Wrap_Boundary; i++) {
359  expected_data=item.data[i-item.addr];
360  read_data=read(i);
361  assert(expected_data==read_data) else {
362  miscompare_cntr++;
363  uvm_error("e_WRAP miscompare",
364  $sformatf("expected: 0x%0x actual:0x%0x",
365  expected_data,
366  read_data))
367  }
368  }
369 
370  // at which offset did the wrap occur? compar that starting at lower_wrap_boundary
371 
372  rollover_cnt=item.len-((item.addr+item.len)-Upper_Wrap_Boundary);
373  for (int i=rollover_cnt;i <item.len;i++) {
374  expected_data=item.data[i];
375  read_data=read(Lower_Wrap_Boundary+(i-rollover_cnt));
376  assert(expected_data==read_data) else {
377  miscompare_cntr++;
378  msg_s="";
379  for (int j=Lower_Wrap_Boundary;j <Upper_Wrap_Boundary;j++) {
380  $sformat(msg_s, "%s 0x%2x", msg_s, read(j));
381  }
382  uvm_fatal("e_WRAP miscompare",
383  $sformatf("Wrap Window contents: [0x%0x - 0x%0x]: %s expected: 0x%0x actual:[0x%0x]=0x%0x (rollover_cnt: 0x%0x)",
384  Lower_Wrap_Boundary,
385  Upper_Wrap_Boundary-1,
386  msg_s,
387  expected_data,
388  Lower_Wrap_Boundary+(i-rollover_cnt),
389  read_data,
390  rollover_cnt))
391  }
392  }
393 
394  // `uvm_warning(this.get_type_name(),
395  // "Not currently verifying eWRAP AXi readback data if data actually wraps.")
396  }
397 
398 
399 
400 
401  } else {
402  miscompare_cntr++;
403  uvm_fatal(this.get_type_name(), $sformatf("Invalid burst_type: %0d", item.burst_type))
404  }
405 
406 
407  // compare post-data
408  if (postcheck==1) {
409  expected_data=0x0;
410  for (int i=post_check_start_addr;i <post_check_stop_addr;i++) {
411  read_data=read(i);
412  assert(expected_data==read_data) else {
413  miscompare_cntr++;
414  uvm_error("MEMORY POST-CHECK miscompare",
415  $sformatf("expected: 0x%0x actual:0x%0x",
416  expected_data,
417  read_data))
418  }
419  }
420  } // if postcheck
421 
422 
423 return (miscompare_cntr == 0);
424 
425 }
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
Extremely simple memory model with just write() and read() methods.
Definition: memory.svh:32
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
virtual void write(input bit< ADDR_WIDTH-1:0 > addr, input bit< 7:0 > data)
Writes into memory.
Definition: memory.svh:58
virtual bit< 7:0 > read(input bit< ADDR_WIDTH-1:0 > addr)
Reads from memory.
Definition: memory.svh:67
uvm_component_utils(memory) bit<7 new(string name="memory", uvm_component parent=null)
Constructor.
Definition: memory.svh:51
contains all data and functions related to axi and usage
localparam ADDR_WIDTH
Definition: axi_uvm_pkg.sv:39