00001 //
00002 // -------------------------------------------------------------
00003 // Copyright 2004-2008 Synopsys, Inc.
00004 // All Rights Reserved Worldwide
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the
00007 // "License"); you may not use this file except in
00008 // compliance with the License. You may obtain a copy of
00009 // the License at
00010 //
00011 // http://www.apache.org/licenses/LICENSE-2.0
00012 //
00013 // Unless required by applicable law or agreed to in
00014 // writing, software distributed under the License is
00015 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00016 // CONDITIONS OF ANY KIND, either express or implied. See
00017 // the License for the specific language governing
00018 // permissions and limitations under the License.
00019 // -------------------------------------------------------------
00020 //
00021
00022
00023 function vmm_ral_mem::new(vmm_ral_block parent,
00024 string name,
00025 vmm_ral::access_e access,
00026 longint unsigned size,
00027 int unsigned n_bits,
00028 bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00029 string domain = "",
00030 int cover_on = vmm_ral::NO_COVERAGE,
00031 bit [1:0] rights = 2'b11,
00032 bit unmapped = 0,
00033 int has_cover = vmm_ral::NO_COVERAGE);
00034
00035 this.name = name;
00036 this.locked = 0;
00037
00038 if (n_bits == 0) begin
00039 `vmm_error(this.log, $psprintf("Memory \"%s\" cannot have 0 bits", this.get_fullname()));
00040 n_bits = 1;
00041 end
00042 if (n_bits > `VMM_RAL_DATA_WIDTH) begin
00043 `vmm_error(this.log, $psprintf("Memory \"%s\" cannot have more than %0d bits (%0d)", this.get_fullname(), `VMM_RAL_DATA_WIDTH, n_bits));
00044 n_bits = `VMM_RAL_DATA_WIDTH;
00045 end
00046 if (access != vmm_ral::RW && access != vmm_ral::RO) begin
00047 `vmm_error(this.log, $psprintf("Memory %s can only be RW or RO",
00048 this.get_fullname()));
00049 access = vmm_ral::RW;
00050 end
00051
00052 this.parent = parent;
00053 this.size = size;
00054 this.access = access;
00055 this.n_bits = n_bits;
00056 this.backdoor = null;
00057
00058 this.parent.register_mem(this);
00059 this.add_domain(base_addr, domain, rights, unmapped);
00060
00061 this.is_powered_down = 0;
00062
00063 this.has_cover = has_cover;
00064 this.cover_on = vmm_ral::NO_COVERAGE;
00065 void'(this.set_cover(cover_on));
00066
00067 begin
00068 vmm_mam_cfg cfg = new;
00069
00070 cfg.n_bytes = ((n_bits-1) / 8) + 1;
00071 cfg.start_offset = 0;
00072 cfg.end_offset = size-1;
00073
00074 cfg.mode = vmm_mam::GREEDY;
00075 cfg.locality = vmm_mam::BROAD;
00076
00077 this.mam = new(this.get_fullname(), cfg, this);
00078 end
00079
00080 // Initialize Memory ID
00081 this.mem_id = ++this.mem_id_factory;
00082 all_mems[this.mem_id] = this;
00083 endfunction: new
00084
00085
00086 function void vmm_ral_mem::Xlock_modelX();
00087 this.locked = 1;
00088 endfunction: Xlock_modelX
00089
00090
00091 function void vmm_ral_mem::add_domain(bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00092 string domain,
00093 bit [1:0] rights,
00094 bit unmapped = 0);
00095 vmm_ral::access_e acc;
00096
00097 // Verify that this is a valid domain in the block
00098 string domains[];
00099
00100 if (this.locked) begin
00101 `vmm_error(this.log, $psprintf("Cannot add domain to locked memory %s", this.get_fullname()));
00102 return;
00103 end
00104
00105 case (rights)
00106 2'b11: acc = vmm_ral::RW;
00107 2'b10: acc = vmm_ral::RO;
00108 2'b01: acc = vmm_ral::WO;
00109 default:
00110 `vmm_error(this.log,
00111 $psprintf("Memory %s has no access rights in domain \"%s\"",
00112 this.get_fullname(), domain));
00113 endcase
00114
00115 this.parent.get_domains(domains);
00116 foreach(domains[i]) begin
00117 if (domains[i] == domain) begin
00118 automatic int n = this.offset_in_block.size();
00119
00120 this.offset_in_block = new [n + 1] (this.offset_in_block);
00121 this.offset_in_block[n] = (unmapped) ? 'X : base_addr;
00122
00123 this.domains = new [n + 1] (this.domains);
00124 this.domains[n] = domain;
00125
00126 this.rights = new [n + 1] (this.rights);
00127 this.rights[n] = acc;
00128
00129 this.frontdoor = new [n + 1] (this.frontdoor);
00130 this.frontdoor[n] = null;
00131 return;
00132 end
00133 end
00134 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in parent block %s of memory %s",
00135 domain, this.parent.get_name(), this.get_fullname()));
00136 endfunction: add_domain
00137
00138
00139 function void vmm_ral_mem::Xregister_ral_accessX(vmm_ral_access access);
00140 // There can only be one RAL Access on a RAL model
00141 if (this.ral_access != null && this.ral_access != access) begin
00142 `vmm_fatal(this.log, $psprintf("Memory %s is already used by another RAL access instance", this.get_fullname()));
00143 end
00144 this.ral_access = access;
00145 endfunction: Xregister_ral_accessX
00146
00147
00148 function string vmm_ral_mem::get_name();
00149 get_name = this.name;
00150 endfunction: get_name
00151
00152
00153 function string vmm_ral_mem::get_fullname();
00154 vmm_ral_block blk;
00155
00156 get_fullname = this.get_name();
00157
00158 // Do not include top-level name in full name
00159 blk = this.get_block();
00160 if (blk == null) return get_fullname;
00161 if (blk.get_parent() == null) return get_fullname;
00162
00163 get_fullname = {this.parent.get_fullname(), ".", get_fullname};
00164 endfunction: get_fullname
00165
00166
00167 function int vmm_ral_mem::get_n_domains();
00168 get_n_domains = this.domains.size();
00169 endfunction: get_n_domains
00170
00171
00172 function void vmm_ral_mem::get_domains(ref string domains[]);
00173 domains = new [this.domains.size()] (this.domains);
00174 endfunction: get_domains
00175
00176
00177 function vmm_ral::access_e vmm_ral_mem::get_access(string domain = "");
00178 get_access = this.access;
00179 if (this.get_n_domains() == 1) return get_access;
00180
00181 // Is the memory restricted in this domain?
00182 case (this.get_rights(domain))
00183 vmm_ral::RW:
00184 // No restrictions
00185 return get_access;
00186
00187 vmm_ral::RO:
00188 case (get_access)
00189 vmm_ral::RW,
00190 vmm_ral::RO: get_access = vmm_ral::RO;
00191
00192 vmm_ral::WO: begin
00193 `vmm_error(this.log,
00194 $psprintf("WO memory %s restricted to RO in domain \"%s\"",
00195 this.get_fullname(), domain));
00196 end
00197
00198 default:
00199 `vmm_error(this.log,
00200 $psprintf("Invalid memory %s access mode \"%s\"",
00201 this.get_fullname(), get_access.name()));
00202 endcase
00203
00204 vmm_ral::WO:
00205 case (get_access)
00206 vmm_ral::RW,
00207 vmm_ral::WO: get_access = vmm_ral::WO;
00208
00209 vmm_ral::RO: begin
00210 `vmm_error(this.log,
00211 $psprintf("RO memory %s restricted to WO in domain \"%s\"",
00212 this.get_fullname(), get_access.name(), domain));
00213 end
00214
00215 default:
00216 `vmm_error(this.log,
00217 $psprintf("Invalid memory %s access mode \"%s\"",
00218 this.get_fullname(), get_access.name()));
00219 endcase
00220
00221 default:
00222 `vmm_error(this.log,
00223 $psprintf("Shared memory \"%s\" is not shared in domain \"%s\"",
00224 this.get_fullname(), domain));
00225 endcase
00226 endfunction: get_access
00227
00228
00229 function vmm_ral::access_e vmm_ral_mem::get_rights(string domain = "");
00230 int i;
00231
00232 // No right restrictions if not shared
00233 if (this.domains.size() == 1) begin
00234 return vmm_ral::RW;
00235 end
00236
00237 i = this.get_domain_index(domain);
00238 if (i < 0) return vmm_ral::RW;
00239
00240 get_rights = this.rights[i];
00241 endfunction: get_rights
00242
00243
00244 function void vmm_ral_mem::get_virtual_fields(ref vmm_ral_vfield fields[]);
00245 vmm_ral_vfield vfields[];
00246
00247 fields = new[0];
00248 foreach (this.XvregsX[i]) begin
00249 int n = fields.size();
00250 this.XvregsX[i].get_fields(vfields);
00251 fields = new[n + vfields.size()] (fields);
00252 foreach(vfields[j]) begin
00253 fields[n+j] = vfields[j];
00254 end
00255 end
00256 endfunction: get_virtual_fields
00257
00258
00259 // Return first occurrence of vfield matching name
00260 function vmm_ral_vfield vmm_ral_mem::get_virtual_field_by_name(string name);
00261 vmm_ral_vfield vfields[];
00262
00263 this.get_virtual_fields(vfields);
00264 foreach (vfields[i]) begin
00265 if (vfields[i].get_name() == name) return vfields[i];
00266 end
00267 `vmm_warning(this.log,
00268 $psprintf("Unable to find virtual field \"%s\" in memory %s.",
00269 name, this.get_fullname()));
00270 return null;
00271 endfunction: get_virtual_field_by_name
00272
00273
00274 function void vmm_ral_mem::get_virtual_registers(ref vmm_ral_vreg regs[]);
00275 regs = new[this.XvregsX.size()];
00276 foreach (this.XvregsX[i]) begin
00277 regs[i] = this.XvregsX[i];
00278 end
00279 endfunction: get_virtual_registers
00280
00281
00282 function vmm_ral_vreg vmm_ral_mem::get_vreg_by_name(string name);
00283 foreach (this.XvregsX[i]) begin
00284 if (this.XvregsX[i].get_name() == name) return this.XvregsX[i];
00285 end
00286 `vmm_warning(this.log,
00287 $psprintf("Unable to find virtual register \"%s\" in memory %s.",
00288 name, this.get_fullname()));
00289
00290 endfunction: get_vreg_by_name
00291
00292
00293 function vmm_ral_vreg vmm_ral_mem::get_vreg_by_offset(bit [63:0] offset,
00294 string domain = "");
00295 `vmm_error(this.log, "vmm_ral_mem::get_vreg_by_offset() not yet implemented");
00296 return null;
00297 endfunction: get_vreg_by_offset
00298
00299
00300 function vmm_ral_block vmm_ral_mem::get_block();
00301 get_block = this.parent;
00302 endfunction: get_block
00303
00304
00305 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_mem::get_offset_in_block(bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr = 0,
00306 string domain = "");
00307 foreach (this.domains[i]) begin
00308 if (this.domains[i] == domain) begin
00309 if (this.offset_in_block[i] === 'x) begin
00310 `vmm_warning(this.log, $psprintf("Memory \"%s\" is unmapped in domain \"%s\".", this.get_name(), domain));
00311 return '0;
00312 end
00313
00314 return this.offset_in_block[i];
00315 end
00316 end
00317 `vmm_warning(this.log, $psprintf("Unable to find offset within domain \"%s\" in memory %s.",
00318 domain, this.get_fullname()));
00319 get_offset_in_block = '1;
00320 endfunction: get_offset_in_block
00321
00322
00323 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_mem::get_address_in_system(bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr = 0,
00324 string domain = "");
00325 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00326
00327 int i = this.get_domain_index(domain);
00328 if (i < 0) return 0;
00329
00330 if (this.ral_access == null) begin
00331 `vmm_fatal(this.parent.log,
00332 "RAL model is not associated with an access transactor");
00333 return 0;
00334 end
00335
00336 if (this.offset_in_block[i] === 'x) begin
00337 `vmm_error(this.log, $psprintf("Memory \"%s\" is unmapped in domain \"%s\".", this.get_name(), this.domains[i]));
00338 return '1;
00339 end
00340
00341 void'(this.ral_access.Xget_physical_addressesX(this.offset_in_block[i],
00342 mem_addr, this.get_n_bytes(),
00343 this.parent,
00344 this.domains[i],
00345 addr));
00346
00347 get_address_in_system = addr[0];
00348 endfunction: get_address_in_system
00349
00350
00351 function longint unsigned vmm_ral_mem::get_size();
00352 get_size = this.size;
00353 endfunction: get_size
00354
00355
00356 function int unsigned vmm_ral_mem::get_n_bits();
00357 get_n_bits = this.n_bits;
00358 endfunction: get_n_bits
00359
00360
00361 function int unsigned vmm_ral_mem::get_n_bytes();
00362 get_n_bytes = (this.n_bits - 1) / 8 + 1;
00363 endfunction: get_n_bytes
00364
00365
00366 function void vmm_ral_mem::display(string prefix = "",
00367 string domain = "");
00368 $write("%s\n", this.psdisplay(prefix, domain));
00369 endfunction: display
00370
00371
00372 function string vmm_ral_mem::psdisplay(string prefix = "",
00373 string domain = "");
00374 $sformat(psdisplay, "%sMemory %s -- %0dx%0d bits @", prefix,
00375 this.get_fullname(), this.get_size(), this.get_n_bits());
00376 foreach (this.domains[i]) begin
00377 if (this.domains[i] == domain) begin
00378 if (this.offset_in_block[i] === 'x) begin
00379 psdisplay = {psdisplay, "none"};
00380 end
00381 else begin
00382 $sformat(psdisplay, "%s'h%h", psdisplay,
00383 this.get_address_in_system(0, domain));
00384 end
00385 break;
00386 end
00387 end
00388 endfunction: psdisplay
00389
00390
00391 function void vmm_ral_mem::set_attribute(string name,
00392 string value);
00393 if (name == "") begin
00394 `vmm_error(this.log, $psprintf("Cannot set anonymous attribute \"\" in memory \"%s\". Please specify an attribute name.",
00395 name, this.get_fullname()));
00396 return;
00397 end
00398
00399 if (this.attributes.exists(name)) begin
00400 if (value != "") begin
00401 `vmm_warning(this.log, $psprintf("Redefining attributed \"%s\" in memory \"%s\" to \"%s\".",
00402 name, this.get_fullname(), value));
00403 this.attributes[name] = value;
00404 end
00405 else begin
00406 this.attributes.delete(name);
00407 end
00408 return;
00409 end
00410
00411 if (value == "") begin
00412 `vmm_warning(this.log, $psprintf("Attempting to delete non-existent attribute \"%s\" in memory \"%s\".",
00413 name, this.get_fullname()));
00414 return;
00415 end
00416
00417 this.attributes[name] = value;
00418 endfunction: set_attribute
00419
00420
00421 function string vmm_ral_mem::get_attribute(string name,
00422 bit inherited = 1);
00423 if (this.attributes.exists(name)) begin
00424 return this.attributes[name];
00425 end
00426
00427 if (inherited) return this.parent.get_attribute(name);
00428
00429 return "";
00430 endfunction: get_attribute
00431
00432
00433 function void vmm_ral_mem::get_all_attributes(ref string names[],
00434 input bit inherited = 1);
00435 string tmp[];
00436 string name;
00437 bit ok;
00438 int i;
00439
00440 if (inherited) this.parent.get_all_attributes(tmp);
00441
00442 i = tmp.size();
00443 tmp = new [tmp.size() + this.attributes.num()] (tmp);
00444
00445 ok = this.attributes.first(name);
00446 while (ok) begin
00447 int found = 0;
00448 foreach (tmp[j]) begin
00449 if (tmp[j] == name) begin
00450 found = 1;
00451 break;
00452 end
00453 end
00454 if (!found) tmp[i++] = name;
00455 ok = this.attributes.next(name);
00456 end
00457 names = new [i] (tmp);
00458 endfunction: get_all_attributes
00459
00460
00461 function void vmm_ral_mem::power_down();
00462 this.is_powered_down = 1;
00463 endfunction: power_down
00464
00465
00466 function void vmm_ral_mem::power_up();
00467 this.is_powered_down = 0;
00468 endfunction: power_up
00469
00470
00471 function bit vmm_ral_mem::can_cover(int models);
00472 return ((this.has_cover & models) == models);
00473 endfunction: can_cover
00474
00475
00476 function int vmm_ral_mem::set_cover(int is_on);
00477 if (is_on == vmm_ral::NO_COVERAGE) begin
00478 this.cover_on = is_on;
00479 return this.cover_on;
00480 end
00481
00482 if (is_on & vmm_ral::ADDR_MAP) begin
00483 if (this.has_cover & vmm_ral::ADDR_MAP) begin
00484 this.cover_on |= vmm_ral::ADDR_MAP;
00485 end else begin
00486 `vmm_warning(this.log, $psprintf("\"%s\" - Cannot turn ON Address Map coverage becasue the corresponding coverage model was not generated.", this.get_fullname()));
00487 end
00488 end else begin
00489 return this.cover_on;
00490 end
00491
00492 set_cover = this.cover_on;
00493 endfunction: set_cover
00494
00495
00496 function bit vmm_ral_mem::is_cover_on(int is_on);
00497 if (this.can_cover(is_on) == 0) return 0;
00498 return ((this.cover_on & is_on) == is_on);
00499 endfunction: is_cover_on
00500
00501
00502 task vmm_ral_mem::init(output bit is_ok,
00503 input init_e pattern,
00504 input bit [`VMM_RAL_DATA_WIDTH-1:0] data);
00505 int incr;
00506 is_ok = 0;
00507
00508 if (this.backdoor == null) begin
00509 `vmm_error(this.log, $psprintf("No backdoor available to initialize memory %s", this.get_fullname()));
00510 return;
00511 end
00512
00513 case (pattern)
00514 UNKNOWNS:
00515 begin
00516 data = 'x;
00517 incr = 0;
00518 end
00519
00520 ZEROES:
00521 begin
00522 data = '0;
00523 incr = 0;
00524 end
00525
00526 ONES:
00527 begin
00528 data = '1;
00529 incr = 0;
00530 end
00531
00532 VALUE:
00533 begin
00534 incr = 0;
00535 end
00536
00537 INCR:
00538 begin
00539 incr = 1;
00540 end
00541
00542 DECR:
00543 begin
00544 incr = -1;
00545 end
00546 endcase
00547
00548 // ToDo...
00549 endtask:init
00550
00551
00552 task vmm_ral_mem::write(output vmm_rw::status_e status,
00553 input bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00554 input bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00555 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00556 input string domain = "",
00557 input int data_id = -1,
00558 input int scenario_id = -1,
00559 input int stream_id = -1);
00560 status = vmm_rw::ERROR;
00561
00562 if (this.ral_access == null) begin
00563 `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00564 return;
00565 end
00566
00567 if (this.is_powered_down) begin
00568 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
00569 return;
00570 end
00571
00572 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00573
00574 `vmm_callback(vmm_ral_mem_callbacks,
00575 pre_write(this, mem_addr, value, path, domain));
00576
00577 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00578
00579 if (path == vmm_ral::BACKDOOR &&
00580 this.backdoor == null) begin
00581 `vmm_warning(this.log, $psprintf("No backdoor access available for memory \"%s\". Using frontdoor instead.", this.get_name()));
00582 path = vmm_ral::BFM;
00583 end
00584
00585 case (path)
00586
00587 vmm_ral::BFM: begin
00588 int di = this.get_domain_index(domain);
00589 if (di < 0) return;
00590
00591 if (this.frontdoor[di] != null) begin
00592 this.frontdoor[di].write(status, mem_addr, value,
00593 data_id, scenario_id, stream_id);
00594 end
00595 else begin
00596 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00597 int w, j;
00598 int n_bits;
00599
00600 if (this.offset_in_block[di] === 'x) begin
00601 `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00602 this.get_name(),
00603 this.domains[di]));
00604 return;
00605 end
00606
00607 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00608 mem_addr,
00609 this.get_n_bytes(),
00610 this.parent,
00611 this.domains[di],
00612 addr);
00613 j = 0;
00614 n_bits = this.get_n_bits;
00615 foreach (addr[i]) begin
00616 bit [`VMM_RAL_DATA_WIDTH-1:0] data;
00617 data = value >> (j*8);
00618 this.ral_access.write(status, addr[i], data,
00619 (n_bits > w*8) ? w*8 : n_bits,
00620 this.parent.get_external_domain(this.domains[di]),
00621 data_id, scenario_id, stream_id);
00622 if (status != vmm_rw::IS_OK) break;
00623 j += w;
00624 n_bits -= w * 8;
00625 end
00626 end
00627
00628 if (this.cover_on)
00629 this.parent.XsampleX(this.offset_in_block[di] +
00630 mem_addr * (((this.get_n_bytes()-1)/this.parent.get_n_bytes(domain))+1), di);
00631 end
00632
00633 vmm_ral::BACKDOOR: begin
00634 // Mimick front door access: Do not write read-only memories
00635 if (this.get_access(domain) == vmm_ral::RW) begin
00636 this.poke(status, mem_addr, value,
00637 data_id, scenario_id, stream_id);
00638 end else status = vmm_rw::IS_OK;
00639 end
00640 endcase
00641
00642 `vmm_callback(vmm_ral_mem_callbacks,
00643 post_write(this, mem_addr, value, path, domain, status));
00644
00645 `vmm_trace(this.log, $psprintf("Wrote memory \"%s\"[%0d] via %s: with 'h%h",
00646 this.get_fullname(), mem_addr,
00647 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00648 value));
00649 endtask: write
00650
00651
00652 task vmm_ral_mem::read(output vmm_rw::status_e status,
00653 input bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00654 output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00655 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00656 input string domain = "",
00657 input int data_id = -1,
00658 input int scenario_id = -1,
00659 input int stream_id = -1);
00660 status = vmm_rw::ERROR;
00661
00662 if (this.ral_access == null) begin
00663 `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00664 return;
00665 end
00666
00667 if (this.is_powered_down) begin
00668 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
00669 return;
00670 end
00671
00672 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00673
00674 `vmm_callback(vmm_ral_mem_callbacks,
00675 pre_read(this, mem_addr, path, domain));
00676
00677 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00678
00679 if (path == vmm_ral::BACKDOOR &&
00680 this.backdoor == null) begin
00681 `vmm_warning(this.log, $psprintf("No backdoor access available for memory \"%s\". Using frontdoor instead.", this.get_name()));
00682 path = vmm_ral::BFM;
00683 end
00684
00685 case (path)
00686
00687 vmm_ral::BFM: begin
00688 int di = this.get_domain_index(domain);
00689 if (di < 0) return;
00690
00691 if (this.frontdoor[di] != null) begin
00692 this.frontdoor[di].read(status, mem_addr, value,
00693 data_id, scenario_id, stream_id);
00694 end
00695 else begin
00696 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00697 int w, j;
00698 int n_bits;
00699
00700 if (this.offset_in_block[di] === 'x) begin
00701 `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00702 this.get_name(),
00703 this.domains[di]));
00704 return;
00705 end
00706
00707 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00708 mem_addr,
00709 this.get_n_bytes(),
00710 this.parent,
00711 this.domains[di],
00712 addr);
00713 j = 0;
00714 n_bits = this.get_n_bits();
00715 value = 0;
00716 foreach (addr[i]) begin
00717 bit [`VMM_RAL_DATA_WIDTH-1:0] data;
00718 this.ral_access.read(status, addr[i], data,
00719 (n_bits > w*8) ? w*8 : n_bits,
00720 this.parent.get_external_domain(this.domains[di]),
00721 data_id, scenario_id, stream_id);
00722 if (status != vmm_rw::IS_OK) break;
00723 value |= (data & ((1 << (w*8)) - 1)) << (j*8);
00724 j += w;
00725 n_bits -= w * 8;
00726 end
00727 end
00728
00729 if (this.cover_on)
00730 this.parent.XsampleX(this.offset_in_block[di] +
00731 mem_addr * (((this.get_n_bytes()-1)/this.parent.get_n_bytes(domain))+1), di);
00732 end
00733
00734 vmm_ral::BACKDOOR: begin
00735 this.peek(status, mem_addr, value,
00736 data_id, scenario_id, stream_id);
00737 end
00738 endcase
00739
00740 `vmm_callback(vmm_ral_mem_callbacks,
00741 post_read(this, mem_addr, value, path, domain, status));
00742
00743 `vmm_trace(this.log, $psprintf("Read memory \"%s\"[%0d] via %s: 'h%h",
00744 this.get_fullname(), mem_addr,
00745 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00746 value));
00747 endtask: read
00748
00749
00750 function bit vmm_ral_mem::validate_burst(vmm_ral_mem_burst burst);
00751 if (burst.start_offset >= this.get_size()) begin
00752 `vmm_error(this.log, $psprintf("Starting burst offset 'h%0h is greater than number of memory locations ('h%0h)",
00753 burst.start_offset, this.get_size()));
00754 return 0;
00755 end
00756
00757 if (burst.max_offset >= this.get_size()) begin
00758 `vmm_error(this.log, $psprintf("Maximum burst offset 'h%0h is greater than number of memory locations ('h%0h)",
00759 burst.max_offset, this.get_size()));
00760 return 0;
00761 end
00762
00763 if (burst.n_beats == 0) begin
00764 `vmm_error(this.log, "Zero-length burst");
00765 return 0;
00766 end
00767
00768 if (burst.start_offset > burst.max_offset) begin
00769 `vmm_error(this.log, $psprintf("Starting burst offset ('h%0h) greater than maximum burst offset ('h%0h)",
00770 burst.start_offset, burst.max_offset));
00771 return 0;
00772 end
00773
00774 if (burst.n_beats > 1 &&
00775 burst.start_offset + burst.incr_offset >= burst.max_offset) begin
00776 `vmm_error(this.log, $psprintf("First burst offset increment 'h%0h+%0h is greater than maximum burst offset ('h%0h)",
00777 burst.start_offset, burst.incr_offset,
00778 burst.max_offset));
00779 return 0;
00780 end
00781
00782 return 1;
00783 endfunction: validate_burst
00784
00785
00786 task vmm_ral_mem::burst_write(output vmm_rw::status_e status,
00787 input vmm_ral_mem_burst burst,
00788 input bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00789 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00790 input string domain = "",
00791 input int data_id = -1,
00792 input int scenario_id = -1,
00793 input int stream_id = -1);
00794 status = vmm_rw::ERROR;
00795
00796 if (this.ral_access == null) begin
00797 `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00798 return;
00799 end
00800
00801 if (this.is_powered_down) begin
00802 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
00803 return;
00804 end
00805
00806 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00807
00808 `vmm_callback(vmm_ral_mem_callbacks,
00809 pre_burst(this, vmm_rw::WRITE, burst, value, path, domain));
00810
00811 if (!this.validate_burst(burst)) return;
00812
00813 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00814
00815 case (path)
00816
00817 vmm_ral::BFM: begin
00818 int di = this.get_domain_index(domain);
00819 if (di < 0) return;
00820
00821 if (this.frontdoor[di] != null) begin
00822 this.frontdoor[di].burst_write(status, burst, value,
00823 data_id, scenario_id, stream_id);
00824 end
00825 else begin
00826 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00827 int w;
00828 int n_bits;
00829
00830 if (this.offset_in_block[di] === 'x) begin
00831 `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00832 this.get_name(),
00833 this.domains[di]));
00834 return;
00835 end
00836
00837 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00838 burst.start_offset,
00839 this.get_n_bytes(),
00840 this.parent,
00841 this.domains[di],
00842 addr);
00843 n_bits = this.get_n_bits;
00844 // Cannot burst memory through a narrower datapath
00845 if (n_bits > w*8) begin
00846 `vmm_error(this.log, $psprintf("Cannot burst-write a %0d-bit memory through a narrower data path (%0d bytes)",
00847 n_bits, w));
00848 return;
00849 end
00850 // Translate offsets into addresses
00851 begin
00852 bit [`VMM_RAL_ADDR_WIDTH-1:0] start, incr, max;
00853
00854 start = addr[0];
00855
00856 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00857 burst.start_offset + burst.incr_offset,
00858 this.get_n_bytes(),
00859 this.parent,
00860 this.domains[di],
00861 addr);
00862 incr = addr[0] - start;
00863
00864 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00865 burst.max_offset,
00866 this.get_n_bytes(),
00867 this.parent,
00868 this.domains[di],
00869 addr);
00870
00871 max = addr[addr.size()-1];
00872
00873 this.ral_access.burst_write(status, start, incr, max, value,
00874 burst.user_data, n_bits,
00875 this.parent.get_external_domain(this.domains[di]),
00876 data_id, scenario_id, stream_id);
00877 end
00878 end
00879
00880 if (this.cover_on) begin
00881 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00882 for (addr = burst.start_offset;
00883 addr <= burst.max_offset;
00884 addr += burst.incr_offset) begin
00885 this.parent.XsampleX(this.offset_in_block[di] + addr, di);
00886 end
00887 end
00888 end
00889
00890 vmm_ral::BACKDOOR: begin
00891 // Mimick front door access: Do not write read-only memories
00892 if (this.get_access(domain) == vmm_ral::RW) begin
00893 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00894 addr = burst.start_offset;
00895 foreach (value[i]) begin
00896 this.poke(status, addr, value[i],
00897 data_id, scenario_id, stream_id);
00898 if (status != vmm_rw::IS_OK) return;
00899 addr += burst.incr_offset;
00900 if (addr > burst.max_offset) begin
00901 addr -= (burst.max_offset - burst.start_offset - 1);
00902 end
00903 end
00904 end
00905 else status = vmm_rw::IS_OK;
00906 end
00907 endcase
00908
00909 `vmm_callback(vmm_ral_mem_callbacks,
00910 post_burst(this, vmm_rw::WRITE, burst, value,
00911 path, domain, status));
00912 endtask: burst_write
00913
00914
00915 task vmm_ral_mem::burst_read(output vmm_rw::status_e status,
00916 input vmm_ral_mem_burst burst,
00917 output bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00918 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00919 input string domain = "",
00920 input int data_id = -1,
00921 input int scenario_id = -1,
00922 input int stream_id = -1);
00923 status = vmm_rw::ERROR;
00924
00925 if (this.ral_access == null) begin
00926 `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00927 return;
00928 end
00929
00930 if (this.is_powered_down) begin
00931 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
00932 return;
00933 end
00934
00935 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00936
00937 begin
00938 bit [`VMM_RAL_DATA_WIDTH-1:0] junk[];
00939
00940 `vmm_callback(vmm_ral_mem_callbacks,
00941 pre_burst(this, vmm_rw::READ, burst, junk, path, domain));
00942 end
00943
00944 if (!this.validate_burst(burst)) return;
00945
00946 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00947
00948 case (path)
00949
00950 vmm_ral::BFM: begin
00951 int di = this.get_domain_index(domain);
00952 if (di < 0) return;
00953
00954 if (this.frontdoor[di] != null) begin
00955 this.frontdoor[di].burst_read(status, burst, value,
00956 data_id, scenario_id, stream_id);
00957 end
00958 else begin
00959 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00960 int n_bits, w;
00961
00962 if (this.offset_in_block[di] === 'x) begin
00963 `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00964 this.get_name(),
00965 this.domains[di]));
00966 return;
00967 end
00968
00969 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00970 burst.start_offset,
00971 this.get_n_bytes(),
00972 this.parent,
00973 this.domains[di],
00974 addr);
00975 n_bits = this.get_n_bits();
00976 // Cannot burst memory through a narrower datapath
00977 if (n_bits > w*8) begin
00978 `vmm_error(this.log, $psprintf("Cannot burst-write a %0d-bit memory through a narrower data path (%0d bytes)",
00979 n_bits, w));
00980 return;
00981 end
00982 // Translate the offset-based burst into address-based burst
00983 begin
00984 bit [`VMM_RAL_ADDR_WIDTH-1:0] start, incr, max;
00985
00986 start = addr[0];
00987
00988 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00989 burst.start_offset + burst.incr_offset,
00990 this.get_n_bytes(),
00991 this.parent,
00992 this.domains[di],
00993 addr);
00994 incr = addr[0] - start;
00995
00996 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00997 burst.max_offset,
00998 this.get_n_bytes(),
00999 this.parent,
01000 this.domains[di],
01001 addr);
01002
01003 max = addr[addr.size()-1];
01004
01005 this.ral_access.burst_read(status, start, incr, max,
01006 burst.n_beats, value,
01007 burst.user_data, n_bits,
01008 this.parent.get_external_domain(this.domains[di]),
01009 data_id, scenario_id, stream_id);
01010 end
01011 end
01012
01013 if (this.cover_on) begin
01014 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
01015 for (addr = burst.start_offset;
01016 addr <= burst.max_offset;
01017 addr += burst.incr_offset) begin
01018 this.parent.XsampleX(this.offset_in_block[di] + addr, di);
01019 end
01020 end
01021 end
01022
01023 vmm_ral::BACKDOOR: begin
01024 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
01025 value = new [burst.n_beats];
01026 addr = burst.start_offset;
01027 foreach (value[i]) begin
01028 this.peek(status, addr, value[i],
01029 data_id, scenario_id, stream_id);
01030 if (status != vmm_rw::IS_OK) return;
01031 addr += burst.incr_offset;
01032 if (addr > burst.max_offset) begin
01033 addr -= (burst.max_offset - burst.start_offset - 1);
01034 end
01035 end
01036 end
01037 endcase
01038
01039 `vmm_callback(vmm_ral_mem_callbacks,
01040 post_burst(this, vmm_rw::READ, burst, value,
01041 path, domain, status));
01042 endtask: burst_read
01043
01044
01045 task vmm_ral_mem::poke(output vmm_rw::status_e status,
01046 input bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
01047 input bit [`VMM_RAL_DATA_WIDTH-1:0] value,
01048 input int data_id = -1,
01049 input int scenario_id = -1,
01050 input int stream_id = -1);
01051 if (this.backdoor == null) begin
01052 `vmm_error(this.log, $psprintf("No backdoor access available in memory %s", this.get_fullname()));
01053 status = vmm_rw::ERROR;
01054 return;
01055 end
01056 if (this.is_powered_down) begin
01057 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
01058 return;
01059 end
01060
01061 this.backdoor.write(status, mem_addr, value, data_id, scenario_id, stream_id);
01062
01063 `vmm_trace(this.log, $psprintf("Poked memory \"%s\"[%0d] with: 'h%h",
01064 this.get_fullname(), mem_addr, value));
01065 endtask: poke
01066
01067
01068 task vmm_ral_mem::peek(output vmm_rw::status_e status,
01069 input bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
01070 output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
01071 input int data_id = -1,
01072 input int scenario_id = -1,
01073 input int stream_id = -1);
01074 if (this.backdoor == null) begin
01075 `vmm_error(this.log, $psprintf("No backdoor access available in memory %s", this.get_fullname()));
01076 status = vmm_rw::ERROR;
01077 return;
01078 end
01079 if (this.is_powered_down) begin
01080 `vmm_error(this.log, $psprintf("Memory %s cannot be accessed when it is powered down", this.get_fullname()));
01081 return;
01082 end
01083
01084 this.backdoor.read(status, mem_addr, value, data_id, scenario_id, stream_id);
01085
01086 `vmm_trace(this.log, $psprintf("Peeked memory \"%s\"[%0d]: 'h%h",
01087 this.get_fullname(), mem_addr, value));
01088 endtask: peek
01089
01090
01091 task vmm_ral_mem::readmemh(string filename);
01092 endtask: readmemh
01093
01094
01095 task vmm_ral_mem::writememh(string filename);
01096 endtask: writememh
01097
01098
01099 function void vmm_ral_mem::set_frontdoor(vmm_ral_mem_frontdoor ftdr,
01100 string domain = "");
01101 foreach(this.domains[i]) begin
01102 if (this.domains[i] == domain) begin
01103 this.frontdoor[i] = ftdr;
01104 return;
01105 end
01106 end
01107 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in memory %s", domain, this.get_fullname()));
01108 endfunction: set_frontdoor
01109
01110
01111 function vmm_ral_mem_frontdoor vmm_ral_mem::get_frontdoor(string domain = "");
01112 foreach(this.domains[i]) begin
01113 if (this.domains[i] == domain) begin
01114 return this.frontdoor[i];
01115 end
01116 end
01117 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in memory %s", domain, this.get_fullname()));
01118 endfunction: get_frontdoor
01119
01120
01121 function void vmm_ral_mem::set_backdoor(vmm_ral_mem_backdoor bkdr);
01122 this.backdoor = bkdr;
01123 endfunction: set_backdoor
01124
01125
01126 function vmm_ral_mem_backdoor vmm_ral_mem::get_backdoor();
01127 get_backdoor = this.backdoor;
01128 endfunction: get_backdoor
01129
01130
01131 function void vmm_ral_mem::prepend_callback(vmm_ral_mem_callbacks cb);
01132 foreach (this.callbacks[i]) begin
01133 if (this.callbacks[i] == cb) begin
01134 `vmm_warning(this.log, $psprintf("Callback has already been registered with memory %s", this.get_fullname()));
01135 return;
01136 end
01137 end
01138
01139 // Prepend new callback
01140 this.callbacks.push_front(cb);
01141 endfunction: prepend_callback
01142
01143
01144 function void vmm_ral_mem::append_callback(vmm_ral_mem_callbacks cb);
01145 foreach (this.callbacks[i]) begin
01146 if (this.callbacks[i] == cb) begin
01147 `vmm_warning(this.log, $psprintf("Callback has already been registered with memory %s", this.get_fullname()));
01148 return;
01149 end
01150 end
01151
01152 // Append new callback
01153 this.callbacks.push_back(cb);
01154 endfunction: append_callback
01155
01156
01157 function void vmm_ral_mem::unregister_callback(vmm_ral_mem_callbacks cb);
01158 foreach (this.callbacks[i]) begin
01159 if (this.callbacks[i] == cb) begin
01160 int j = i;
01161 // Unregister it
01162 this.callbacks.delete(j);
01163 return;
01164 end
01165 end
01166
01167 `vmm_warning(this.log, $psprintf("Callback was not registered with memory %s", this.get_fullname()));
01168 endfunction: unregister_callback
01169
01170
01171 function int vmm_ral_mem::get_domain_index(string domain);
01172 // If the domain is "" and there is only one domain,
01173 // assume it is the one domain available to avoid
01174 // having to always have to specify domains
01175 if (domain == "" && this.domains.size() == 1) return 0;
01176
01177 foreach (this.domains[i]) begin
01178 if (this.domains[i] == domain) return i;
01179 end
01180 `vmm_warning(this.log, $psprintf("Unknown domain name \"%s\" in memory %s.", domain, this.get_fullname()));
01181 return -1;
01182 endfunction: get_domain_index
01183
01184
01185 task vmm_ral_mem_frontdoor::write(output vmm_rw::status_e status,
01186 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
01187 input bit [`VMM_RAL_DATA_WIDTH-1:0] data,
01188 input int data_id = -1,
01189 input int scenario_id = -1,
01190 input int stream_id = -1);
01191 `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::write() method has not been overloaded");
01192 endtask: write
01193
01194
01195 task vmm_ral_mem_frontdoor::read(output vmm_rw::status_e status,
01196 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
01197 output bit [`VMM_RAL_DATA_WIDTH-1:0] data,
01198 input int data_id = -1,
01199 input int scenario_id = -1,
01200 input int stream_id = -1);
01201 `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::read() method has not been overloaded");
01202 endtask: read
01203
01204 task vmm_ral_mem_frontdoor::burst_write(output vmm_rw::status_e status,
01205 input vmm_ral_mem_burst burst,
01206 input bit [`VMM_RAL_DATA_WIDTH-1:0] data[],
01207 input int data_id = -1,
01208 input int scenario_id = -1,
01209 input int stream_id = -1);
01210 `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::burst_write() method has not been overloaded");
01211 endtask
01212
01213 task vmm_ral_mem_frontdoor::burst_read(output vmm_rw::status_e status,
01214 input vmm_ral_mem_burst burst,
01215 output bit [`VMM_RAL_DATA_WIDTH-1:0] data[],
01216 input int data_id = -1,
01217 input int scenario_id = -1,
01218 input int stream_id = -1);
01219 `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::burst_read() method has not been overloaded");
01220 endtask
01221
01222
01223 function int unsigned vmm_ral_mem::get_mem_ID();
01224 get_mem_ID = this.mem_id;
01225 endfunction
01226
01227 function vmm_ral_mem vmm_ral_get_mem_by_ID(int unsigned id);
01228 vmm_ral_mem m;
01229 if (m.all_mems.exists(id))
01230 vmm_ral_get_mem_by_ID = m.all_mems[id];
01231 else vmm_ral_get_mem_by_ID = null;
01232 endfunction