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 class vmm_ral_block extends vmm_ral_block_or_sys; 00024 00025 local vmm_ral_reg regs[$]; 00026 local vmm_ral_vreg vregs[$]; 00027 local vmm_ral_mem mems[$]; 00028 static local vmm_ral_block __vmm_all_blocks[*]; // Keeps track of all Blocks in the RAL Model 00029 local int unsigned __vmm_block_id = 0; 00030 00031 extern function new(vmm_ral_sys parent, 00032 string name, 00033 string typename, 00034 int unsigned n_bytes, 00035 vmm_ral::endianness_e endian, 00036 bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr, 00037 string domain = "", 00038 bit cover_on = 1); 00039 00040 /*local*/ extern virtual function void Xlock_modelX(); 00041 /*local*/ extern function void register_reg(vmm_ral_reg register); 00042 /*local*/ extern function void register_vreg(vmm_ral_vreg register); 00043 /*local*/ extern function void register_mem(vmm_ral_mem memory); 00044 /*local*/ extern virtual function void Xregister_ral_accessX(vmm_ral_access access); 00045 00046 extern virtual function string psdisplay(string prefix = "", 00047 string domain = ""); 00048 00049 extern virtual function void get_fields(ref vmm_ral_field fields[], 00050 input string domain = ""); 00051 extern virtual function void get_virtual_fields(ref vmm_ral_vfield fields[], 00052 input string domain = ""); 00053 extern virtual function vmm_ral_field get_field_by_name(string name); 00054 extern virtual function vmm_ral_vfield get_virtual_field_by_name(string name); 00055 00056 extern virtual function void get_registers(ref vmm_ral_reg regs[], 00057 input string domain = ""); 00058 extern virtual function void get_virtual_registers(ref vmm_ral_vreg vregs[], 00059 input string domain = ""); 00060 extern virtual function vmm_ral_reg get_reg_by_name(string name); 00061 extern virtual function vmm_ral_vreg get_vreg_by_name(string name); 00062 extern virtual function vmm_ral_reg get_reg_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00063 string domain = ""); 00064 00065 extern virtual function void get_memories(ref vmm_ral_mem mems[], 00066 input string domain = ""); 00067 extern virtual function vmm_ral_mem get_mem_by_name(string name); 00068 extern virtual function vmm_ral_mem get_mem_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00069 string domain = ""); 00070 00071 extern virtual function void get_constraints(ref string names[]); 00072 00073 extern virtual function bit set_cover(bit is_on); 00074 00075 extern virtual function void reset(string domain = "", 00076 vmm_ral::reset_e kind = vmm_ral::HARD); 00077 extern virtual function bit needs_update(); 00078 00079 extern virtual task update(output vmm_rw::status_e status, 00080 input vmm_ral::path_e path = vmm_ral::DEFAULT); 00081 extern virtual task mirror(output vmm_rw::status_e status, 00082 input vmm_ral::check_e check = vmm_ral:: QUIET, 00083 input vmm_ral::path_e path = vmm_ral::DEFAULT); 00084 00085 extern virtual task readmemh(string filename); 00086 extern virtual task writememh(string filename); 00087 00088 extern virtual /*local*/ function void XsampleX(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00089 int domain); 00090 extern protected virtual function void sample(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00091 int domain); 00092 00093 extern function int unsigned get_block_ID(); 00094 00095 extern /*static*/ function vmm_ral_block get_block_by_ID(int unsigned id); 00096 endclass: vmm_ral_block 00097 00098 00099 function vmm_ral_block::new(vmm_ral_sys parent, 00100 string name, 00101 string typename, 00102 int unsigned n_bytes, 00103 vmm_ral::endianness_e endian, 00104 bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr, 00105 string domain, 00106 bit cover_on); 00107 super.new(parent, "RAL Block", name, typename, 00108 n_bytes, endian, base_addr, domain, 00109 cover_on); 00110 00111 // Initialize Block ID 00112 this.__vmm_block_id = ++this.__vmm_block_or_sys_id_factory; 00113 __vmm_all_blocks[this.__vmm_block_id] = this; 00114 endfunction: new 00115 00116 00117 function void vmm_ral_block::Xlock_modelX(); 00118 if (this.Xis_lockedX()) return; 00119 00120 super.Xlock_modelX(); 00121 foreach (this.regs[i]) begin 00122 this.regs[i].Xlock_modelX(); 00123 end 00124 foreach (this.mems[i]) begin 00125 this.mems[i].Xlock_modelX(); 00126 end 00127 endfunction: Xlock_modelX 00128 00129 00130 function void vmm_ral_block::register_reg(vmm_ral_reg register); 00131 if (this.Xis_lockedX()) begin 00132 `vmm_error(this.log, "Cannot add register to locked block model"); 00133 return; 00134 end 00135 00136 // Check if this register has already been registered with this block 00137 foreach (this.regs[i]) begin 00138 if (this.regs[i] == register) begin 00139 `vmm_error(this.log, $psprintf("Register \"%s\" has already been registered with block \"%s\".\n", 00140 register.get_name(), this.get_name())); 00141 return; 00142 end 00143 end 00144 this.regs.push_back(register); 00145 endfunction: register_reg 00146 00147 function void vmm_ral_block::register_vreg(vmm_ral_vreg register); 00148 if (this.Xis_lockedX()) begin 00149 `vmm_error(this.log, "Cannot add virtual register to locked block model"); 00150 return; 00151 end 00152 00153 // Check if this register has already been registered with this block 00154 foreach (this.vregs[i]) begin 00155 if (this.vregs[i] == register) begin 00156 `vmm_error(this.log, $psprintf("Virtual register \"%s\" has already been registered with block \"%s\".\n", 00157 register.get_name(), this.get_name())); 00158 return; 00159 end 00160 end 00161 this.vregs.push_back(register); 00162 endfunction: register_vreg 00163 00164 function void vmm_ral_block::register_mem(vmm_ral_mem memory); 00165 if (this.Xis_lockedX()) begin 00166 `vmm_error(this.log, "Cannot add memory to locked block model"); 00167 return; 00168 end 00169 00170 // Check if this memory has already been registered with this block 00171 foreach (this.mems[i]) begin 00172 if (this.mems[i] == memory) begin 00173 `vmm_error(this.log, $psprintf("Memory \"%s\" has already been registered with block \"%s\".\n", 00174 memory.get_name(), this.get_name())); 00175 return; 00176 end 00177 end 00178 this.mems.push_back(memory); 00179 endfunction: register_mem 00180 00181 00182 function void vmm_ral_block::Xregister_ral_accessX(vmm_ral_access access); 00183 // There can only be one RAL Access on a RAL model 00184 if (this.ral_access != null && this.ral_access != access) begin 00185 `vmm_fatal(this.log, $psprintf("Block %s is already used by another RAL access instance", this.get_fullname())); 00186 end 00187 this.ral_access = access; 00188 00189 // Register all sub-elements 00190 begin 00191 vmm_ral_reg regs[]; 00192 vmm_ral_mem mems[]; 00193 00194 this.get_registers(regs); 00195 foreach (regs[i]) begin 00196 regs[i].Xregister_ral_accessX(access); 00197 end 00198 00199 this.get_memories(mems); 00200 foreach (mems[i]) begin 00201 mems[i].Xregister_ral_accessX(access); 00202 end 00203 end 00204 endfunction: Xregister_ral_accessX 00205 00206 00207 function string vmm_ral_block::psdisplay(string prefix, 00208 string domain); 00209 string domains[]; 00210 vmm_ral_reg regs[]; 00211 vmm_ral_vreg vregs[]; 00212 vmm_ral_mem mems[]; 00213 bit single_domain; 00214 vmm_ral::endianness_e endian; 00215 00216 single_domain = 1; 00217 if (domain == "") begin 00218 this.get_domains(domains); 00219 if (domains.size() > 1) single_domain = 0; 00220 end 00221 if (single_domain) begin 00222 $sformat(psdisplay, "%sBlock %s", prefix, this.get_fullname()); 00223 if (domain != "") $sformat(psdisplay, "%s.%s", psdisplay, domain); 00224 endian = this.get_endian(domain); 00225 $sformat(psdisplay, "%s -- %0d bytes (%s)", psdisplay, 00226 this.get_n_bytes(domain), endian.name()); 00227 this.get_registers(regs, domain); 00228 foreach (regs[j]) begin 00229 $sformat(psdisplay, "%s\n%s", psdisplay, 00230 regs[j].psdisplay({prefix, " "}, domain)); 00231 end 00232 this.get_virtual_registers(vregs, domain); 00233 foreach (vregs[j]) begin 00234 $sformat(psdisplay, "%s\n%s", psdisplay, 00235 vregs[j].psdisplay({prefix, " "}, domain)); 00236 end 00237 this.get_memories(mems, domain); 00238 foreach (mems[j]) begin 00239 $sformat(psdisplay, "%s\n%s", psdisplay, 00240 mems[j].psdisplay({prefix, " "}, domain)); 00241 end 00242 end 00243 else begin 00244 $sformat(psdisplay, "%sBlock %s", prefix, this.get_fullname()); 00245 foreach (domains[i]) begin 00246 endian = this.get_endian(domains[i]); 00247 $sformat(psdisplay, "%s\n%s Domain \"%s\" -- %0d bytes (%s)", 00248 psdisplay, prefix, domains[i], 00249 this.get_n_bytes(domains[i]), endian.name()); 00250 this.get_registers(regs, domains[i]); 00251 foreach (regs[j]) begin 00252 $sformat(psdisplay, "%s\n%s", psdisplay, 00253 regs[j].psdisplay({prefix, " "}, 00254 domains[i])); 00255 end 00256 this.get_virtual_registers(vregs, domains[i]); 00257 foreach (vregs[j]) begin 00258 $sformat(psdisplay, "%s\n%s", psdisplay, 00259 vregs[j].psdisplay({prefix, " "}, 00260 domains[i])); 00261 end 00262 this.get_memories(mems, domains[i]); 00263 foreach (mems[j]) begin 00264 $sformat(psdisplay, "%s\n%s", psdisplay, 00265 mems[j].psdisplay({prefix, " "}, domains[i])); 00266 end 00267 end 00268 end 00269 endfunction: psdisplay 00270 00271 00272 function void vmm_ral_block::get_fields(ref vmm_ral_field fields[], 00273 input string domain); 00274 int n; 00275 vmm_ral_reg r[]; 00276 vmm_ral_field f[]; 00277 00278 fields = new [0]; 00279 this.get_registers(r, domain); 00280 foreach (r[i]) begin 00281 r[i].get_fields(f); 00282 n = fields.size(); 00283 fields = new [n + f.size()] (fields); 00284 00285 foreach (f[j]) begin 00286 fields[n++] = f[j]; 00287 end 00288 end 00289 endfunction: get_fields 00290 00291 function void vmm_ral_block::get_virtual_fields(ref vmm_ral_vfield fields[], 00292 input string domain); 00293 int n; 00294 vmm_ral_vreg r[]; 00295 vmm_ral_vfield f[]; 00296 00297 fields = new [0]; 00298 this.get_virtual_registers(r, domain); 00299 foreach (r[i]) begin 00300 r[i].get_fields(f); 00301 n = fields.size(); 00302 fields = new [n + f.size()] (fields); 00303 00304 foreach (f[j]) begin 00305 fields[n++] = f[j]; 00306 end 00307 end 00308 endfunction: get_virtual_fields 00309 00310 function vmm_ral_field vmm_ral_block::get_field_by_name(string name); 00311 // Search the registers to find the first field of the specified name 00312 foreach (this.regs[i]) begin 00313 vmm_ral_field fields[]; 00314 this.regs[i].get_fields(fields); 00315 foreach (fields[j]) begin 00316 if (fields[j].get_name() == name) begin 00317 return fields[j]; 00318 end 00319 end 00320 end 00321 `vmm_warning(this.log, $psprintf("Unable to locate field \"%s\" in block \"%s\".", 00322 name, this.get_fullname())); 00323 get_field_by_name = null; 00324 endfunction: get_field_by_name 00325 00326 function vmm_ral_vfield vmm_ral_block::get_virtual_field_by_name(string name); 00327 // Search the registers to find the first field of the specified name 00328 foreach (this.vregs[i]) begin 00329 vmm_ral_vfield fields[]; 00330 this.vregs[i].get_fields(fields); 00331 foreach (fields[j]) begin 00332 if (fields[j].get_name() == name) begin 00333 return fields[j]; 00334 end 00335 end 00336 end 00337 `vmm_warning(this.log, $psprintf("Unable to locate virtual field \"%s\" in block \"%s\".", 00338 name, this.get_fullname())); 00339 get_virtual_field_by_name = null; 00340 endfunction: get_virtual_field_by_name 00341 00342 00343 function void vmm_ral_block::get_registers(ref vmm_ral_reg regs[], 00344 input string domain); 00345 if (domain == "") begin 00346 regs = new [this.regs.size()]; 00347 foreach(this.regs[i]) begin 00348 regs[i] = this.regs[i]; 00349 end 00350 end 00351 else begin 00352 int n = 0; 00353 regs = new [this.regs.size()]; 00354 foreach(this.regs[i]) begin 00355 // Is the register in the specified domain? 00356 string domains[]; 00357 this.regs[i].get_domains(domains); 00358 foreach(domains[j]) begin 00359 if (domains[j] == domain) begin 00360 regs[n++] = this.regs[i]; 00361 break; 00362 end 00363 end 00364 end 00365 regs = new [n] (regs); 00366 end 00367 endfunction: get_registers 00368 00369 function void vmm_ral_block::get_virtual_registers(ref vmm_ral_vreg vregs[], 00370 input string domain); 00371 if (domain == "") begin 00372 vregs = new [this.vregs.size()]; 00373 foreach(this.vregs[i]) begin 00374 vregs[i] = this.vregs[i]; 00375 end 00376 end 00377 else begin 00378 int n = 0; 00379 vregs = new [this.vregs.size()]; 00380 foreach(this.vregs[i]) begin 00381 // Is the register in the specified domain? 00382 string domains[]; 00383 this.vregs[i].get_domains(domains); 00384 foreach(domains[j]) begin 00385 if (domains[j] == domain) begin 00386 vregs[n++] = this.vregs[i]; 00387 break; 00388 end 00389 end 00390 end 00391 vregs = new [n] (vregs); 00392 end 00393 endfunction: get_virtual_registers 00394 00395 function vmm_ral_reg vmm_ral_block::get_reg_by_name(string name); 00396 foreach (this.regs[i]) begin 00397 if (this.regs[i].get_name() == name) begin 00398 return this.regs[i]; 00399 end 00400 end 00401 `vmm_warning(this.log, $psprintf("Unable to locate register \"%s\" in block \"%s\".", 00402 name, this.get_fullname())); 00403 get_reg_by_name = null; 00404 endfunction: get_reg_by_name 00405 00406 function vmm_ral_vreg vmm_ral_block::get_vreg_by_name(string name); 00407 foreach (this.vregs[i]) begin 00408 if (this.vregs[i].get_name() == name) begin 00409 return this.vregs[i]; 00410 end 00411 end 00412 `vmm_warning(this.log, $psprintf("Unable to locate virtual register \"%s\" in block \"%s\".", 00413 name, this.get_fullname())); 00414 get_vreg_by_name = null; 00415 endfunction: get_vreg_by_name 00416 00417 function vmm_ral_reg vmm_ral_block::get_reg_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00418 string domain); 00419 foreach (this.regs[i]) begin 00420 if (this.regs[i].get_offset_in_block(domain) == offset) begin 00421 return this.regs[i]; 00422 end 00423 end 00424 `vmm_warning(this.log, $psprintf("Unable to locate register at offset 0x%h %0sin block \"%s\".", 00425 offset, ((domain == "") ? "" : $psprintf("in domain \"%s\" ", 00426 domain)), 00427 this.get_fullname())); 00428 get_reg_by_offset = null; 00429 endfunction: get_reg_by_offset 00430 00431 00432 function void vmm_ral_block::get_memories(ref vmm_ral_mem mems[], 00433 input string domain); 00434 if (domain == "") begin 00435 mems = new [this.mems.size()]; 00436 foreach(this.mems[i]) begin 00437 mems[i] = this.mems[i]; 00438 end 00439 end 00440 else begin 00441 int n = 0; 00442 mems = new [this.mems.size()]; 00443 foreach(this.mems[i]) begin 00444 // Is the memory in the specified domain? 00445 string domains[]; 00446 this.mems[i].get_domains(domains); 00447 foreach(domains[j]) begin 00448 if (domains[j] == domain) begin 00449 mems[n++] = this.mems[i]; 00450 break; 00451 end 00452 end 00453 end 00454 mems = new [n] (mems); 00455 end 00456 endfunction: get_memories 00457 00458 00459 function vmm_ral_mem vmm_ral_block::get_mem_by_name(string name); 00460 foreach (this.mems[i]) begin 00461 if (this.mems[i].get_name() == name) begin 00462 return this.mems[i]; 00463 end 00464 end 00465 `vmm_warning(this.log, $psprintf("Unable to locate memory \"%s\" in block \"%s\".", 00466 name, this.get_fullname())); 00467 get_mem_by_name = null; 00468 endfunction: get_mem_by_name 00469 00470 00471 function vmm_ral_mem vmm_ral_block::get_mem_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00472 string domain); 00473 //get_mem_by_offset = this.mems.first() with index: (this.mems[index].offset_in_block == offset); 00474 endfunction: get_mem_by_offset 00475 00476 00477 function void vmm_ral_block::get_constraints(ref string names[]); 00478 endfunction: get_constraints 00479 00480 00481 function bit vmm_ral_block::set_cover(bit is_on); 00482 set_cover = super.set_cover(is_on); 00483 00484 if (is_on && !super.is_cover_on()) return set_cover; 00485 00486 foreach (this.regs[i]) begin 00487 this.regs[i].set_cover(is_on); 00488 end 00489 foreach (this.mems[i]) begin 00490 this.mems[i].set_cover(is_on); 00491 end 00492 endfunction: set_cover 00493 00494 00495 function void vmm_ral_block::reset(string domain, 00496 vmm_ral::reset_e kind); 00497 vmm_ral_reg regs[]; 00498 vmm_ral_mem mems[]; 00499 00500 this.get_registers(regs, domain); 00501 foreach (regs[i]) begin 00502 regs[i].reset(kind); 00503 end 00504 00505 this.get_memories(mems, domain); 00506 foreach (mems[i]) begin 00507 vmm_ral_vreg vregs[]; 00508 mems[i].get_virtual_registers(vregs); 00509 foreach (vregs[j]) begin 00510 vregs[j].reset(kind); 00511 end 00512 end 00513 endfunction: reset 00514 00515 00516 function bit vmm_ral_block::needs_update(); 00517 needs_update = 0; 00518 foreach (this.regs[i]) begin 00519 if (this.regs[i].needs_update()) begin 00520 return 1; 00521 end 00522 end 00523 endfunction: needs_update 00524 00525 00526 task vmm_ral_block::update(output vmm_rw::status_e status, 00527 input vmm_ral::path_e path); 00528 string domains[]; 00529 bit updated; 00530 00531 status = vmm_rw::IS_OK; 00532 foreach (this.regs[i]) begin 00533 if (!this.regs[i].needs_update()) continue; 00534 00535 if (path == vmm_ral::BACKDOOR) begin 00536 this.regs[i].update(status, path); 00537 if (status != vmm_rw::IS_OK) return; 00538 continue; 00539 end 00540 00541 // Find the first writeable domain to 00542 // perform the update through 00543 this.regs[i].get_domains(domains); 00544 updated = 0; 00545 foreach (domains[j]) begin 00546 if (this.regs[i].get_rights(domains[j]) != vmm_ral::RO) begin 00547 this.regs[i].update(status, path, domains[j]); 00548 if (status == vmm_rw::IS_OK) begin 00549 updated = 1; 00550 break; 00551 end 00552 end 00553 end 00554 if (!updated) begin 00555 `vmm_error(this.log, $psprintf("Register \"%s\" could not be updated", 00556 regs[i].get_fullname())); 00557 if (status == vmm_rw::IS_OK) status = vmm_rw::ERROR; 00558 return; 00559 end 00560 end 00561 endtask: update 00562 00563 00564 task vmm_ral_block::mirror(output vmm_rw::status_e status, 00565 input vmm_ral::check_e check, 00566 input vmm_ral::path_e path); 00567 string domains[]; 00568 bit mirrored; 00569 00570 status = vmm_rw::IS_OK; 00571 foreach (this.regs[i]) begin 00572 00573 if (path == vmm_ral::BACKDOOR) begin 00574 this.regs[i].mirror(status, check, path); 00575 if (status != vmm_rw::IS_OK) return; 00576 continue; 00577 end 00578 00579 // Find the first readable domain to 00580 // perform the update through 00581 this.regs[i].get_domains(domains); 00582 mirrored = 0; 00583 foreach (domains[j]) begin 00584 if (this.regs[i].get_rights(domains[j]) != vmm_ral::WO) begin 00585 this.regs[i].mirror(status, check, path, domains[0]); 00586 if (status == vmm_rw::IS_OK) begin 00587 mirrored = 1; 00588 break; 00589 end 00590 end 00591 end 00592 if (!mirrored) begin 00593 `vmm_error(this.log, $psprintf("Register \"%s\" could not be mirrored", 00594 regs[i].get_fullname())); 00595 if (status == vmm_rw::IS_OK) status = vmm_rw::ERROR; 00596 return; 00597 end 00598 end 00599 endtask: mirror 00600 00601 00602 task vmm_ral_block::readmemh(string filename); 00603 endtask: readmemh 00604 00605 00606 task vmm_ral_block::writememh(string filename); 00607 endtask: writememh 00608 00609 00610 function void vmm_ral_block::XsampleX(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00611 int domain); 00612 this.sample(addr, domain); 00613 endfunction 00614 00615 00616 function void vmm_ral_block::sample(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00617 int domain); 00618 // Nothing to do in this base class 00619 endfunction 00620 00621 00622 function int unsigned vmm_ral_block::get_block_ID(); 00623 get_block_ID = this.__vmm_block_id; 00624 endfunction 00625 00626 function vmm_ral_block vmm_ral_block::get_block_by_ID(int unsigned id); 00627 if (__vmm_all_blocks.exists(id)) get_block_by_ID = __vmm_all_blocks[id]; 00628 else get_block_by_ID = null; 00629 endfunction