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