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