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_reg_callbacks extends vmm_ral_callbacks; 00024 00025 virtual task pre_write(vmm_ral_reg rg, 00026 ref bit [`VMM_RAL_DATA_WIDTH-1:0] wdat, 00027 ref vmm_ral::path_e path, 00028 ref string domain); 00029 endtask: pre_write 00030 00031 virtual task post_write(vmm_ral_reg rg, 00032 bit [`VMM_RAL_DATA_WIDTH-1:0] wdat, 00033 vmm_ral::path_e path, 00034 string domain, 00035 ref vmm_rw::status_e status); 00036 endtask: post_write 00037 00038 virtual task pre_read(vmm_ral_reg rg, 00039 ref vmm_ral::path_e path, 00040 ref string domain); 00041 endtask: pre_read 00042 00043 virtual task post_read(vmm_ral_reg rg, 00044 ref bit [`VMM_RAL_DATA_WIDTH-1:0] rdat, 00045 input vmm_ral::path_e path, 00046 input string domain, 00047 ref vmm_rw::status_e status); 00048 endtask: post_read 00049 endclass: vmm_ral_reg_callbacks 00050 00051 00052 virtual class vmm_ral_reg_frontdoor; 00053 static vmm_log log = new("vmm_ral_reg_frontdoor", "class"); 00054 00055 extern virtual task write(output vmm_rw::status_e status, 00056 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00057 input int data_id = -1, 00058 input int scenario_id = -1, 00059 input int stream_id = -1); 00060 extern virtual task read(output vmm_rw::status_e status, 00061 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00062 input int data_id = -1, 00063 input int scenario_id = -1, 00064 input int stream_id = -1); 00065 endclass: vmm_ral_reg_frontdoor 00066 00067 00068 00069 class vmm_ral_reg; 00070 static vmm_log log = new("RAL", "register"); 00071 00072 static local vmm_ral_reg __vmm_all_regs[*]; // Keeps track of all registers in the RAL Model 00073 static int unsigned __vmm_reg_id_factory = 0; 00074 local int unsigned __vmm_reg_id = 0; 00075 local bit locked; 00076 local vmm_ral_block parent; 00077 local string name; 00078 local int unsigned n_bits; 00079 local int unsigned n_used_bits; 00080 00081 local logic [`VMM_RAL_ADDR_WIDTH-1:0] offset_in_block[]; 00082 local string domains[]; 00083 local vmm_ral::access_e rights[]; 00084 00085 local vmm_ral_field fields[$]; // Fields in LSB to MSB order 00086 local string constr[]; 00087 local event value_change; 00088 00089 local vmm_ral_access ral_access; 00090 local vmm_ral_reg_frontdoor frontdoor[]; 00091 local vmm_ral_reg_backdoor backdoor; 00092 00093 local vmm_ral_reg_callbacks callbacks[$]; 00094 00095 local int has_cover; 00096 local int cover_on; 00097 00098 local semaphore atomic; 00099 00100 /*local*/ bit Xis_busyX; 00101 00102 extern function new(vmm_ral_block parent, 00103 string name, 00104 int unsigned n_bits, 00105 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00106 string domain = "", 00107 int cover_on = vmm_ral::NO_COVERAGE, 00108 bit [1:0] rights = 2'b11, 00109 bit unmapped = 0); 00110 00111 /*local*/ extern function void Xlock_modelX(); 00112 /*local*/ extern function void add_domain(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00113 string domain, 00114 bit [1:0] rights, 00115 bit unmapped = 0); 00116 00117 local virtual function void domain_coverage(string domain, 00118 bit rights, 00119 int idx); 00120 endfunction 00121 00122 /*local*/ extern function void register_field(vmm_ral_field field); 00123 /*local*/ extern function void Xregister_ral_accessX(vmm_ral_access access); 00124 /*local*/ extern function void Xadd_constraintsX(string name); 00125 /*local*/ extern task XatomicX(bit on); 00126 /*local*/ extern task XwriteX(output vmm_rw::status_e status, 00127 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00128 input vmm_ral::path_e path, 00129 input string domain, 00130 input int data_id, 00131 input int scenario_id, 00132 input int stream_id); 00133 /*local*/ extern task XreadX(output vmm_rw::status_e status, 00134 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00135 input vmm_ral::path_e path, 00136 input string domain, 00137 input int data_id, 00138 input int scenario_id, 00139 input int stream_id); 00140 00141 extern virtual function string get_name(); 00142 extern virtual function string get_fullname(); 00143 extern virtual function int get_n_domains(); 00144 extern virtual function void get_domains(ref string domains[]); 00145 extern virtual function vmm_ral::access_e get_rights(string domain = ""); 00146 extern virtual function vmm_ral_block get_block(); 00147 extern virtual function bit [`VMM_RAL_ADDR_WIDTH-1:0] get_offset_in_block(string domain = ""); 00148 extern virtual function bit [`VMM_RAL_ADDR_WIDTH-1:0] get_address_in_system(string domain = ""); 00149 extern virtual function int unsigned get_n_bytes(); 00150 extern virtual function void get_constraints(ref string names[]); 00151 00152 extern virtual function void display(string prefix = "", 00153 string domain = ""); 00154 extern virtual function string psdisplay(string prefix = "", 00155 string domain = ""); 00156 00157 extern virtual function void get_fields(ref vmm_ral_field fields[]); 00158 extern virtual function vmm_ral_field get_field_by_name(string name); 00159 00160 extern virtual function bit can_cover(int models); 00161 extern virtual function int set_cover(int is_on); 00162 extern virtual function bit is_cover_on(int is_on); 00163 00164 extern local virtual function void XforceX(bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00165 vmm_ral::path_e path, 00166 string domain); 00167 extern local virtual function void XwroteX(bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00168 vmm_ral::path_e path, 00169 string domain); 00170 extern virtual function void set(bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00171 extern virtual function bit predict(bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00172 extern virtual function bit[`VMM_RAL_DATA_WIDTH-1:0] get(); 00173 extern virtual function void reset(vmm_ral::reset_e kind = vmm_ral::HARD); 00174 extern virtual function bit needs_update(); 00175 00176 extern virtual task update(output vmm_rw::status_e status, 00177 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00178 input string domain = ""); 00179 extern virtual task write(output vmm_rw::status_e status, 00180 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00181 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00182 input string domain = "", 00183 input int data_id = -1, 00184 input int scenario_id = -1, 00185 input int stream_id = -1); 00186 extern virtual task read(output vmm_rw::status_e status, 00187 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00188 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00189 input string domain = "", 00190 input int data_id = -1, 00191 input int scenario_id = -1, 00192 input int stream_id = -1); 00193 extern virtual task poke(output vmm_rw::status_e status, 00194 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00195 input int data_id = -1, 00196 input int scenario_id = -1, 00197 input int stream_id = -1); 00198 extern virtual task peek(output vmm_rw::status_e status, 00199 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00200 input int data_id = -1, 00201 input int scenario_id = -1, 00202 input int stream_id = -1); 00203 extern virtual task mirror(output vmm_rw::status_e status, 00204 input vmm_ral::check_e check = vmm_ral::QUIET, 00205 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00206 input string domain = ""); 00207 00208 extern function void set_frontdoor(vmm_ral_reg_frontdoor ftdr, 00209 string domain = ""); 00210 extern function vmm_ral_reg_frontdoor get_frontdoor(string domain = ""); 00211 extern function void set_backdoor(vmm_ral_reg_backdoor bkdr); 00212 extern function vmm_ral_reg_backdoor get_backdoor(); 00213 00214 extern function void prepend_callback(vmm_ral_reg_callbacks cb); 00215 extern function void append_callback(vmm_ral_reg_callbacks cb); 00216 extern function void unregister_callback(vmm_ral_reg_callbacks cb); 00217 00218 extern local function int get_domain_index(string domain); 00219 extern virtual local function void sample(bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00220 bit is_read, 00221 int domain); 00222 00223 extern function int unsigned get_reg_ID(); 00224 00225 extern /*static*/ function vmm_ral_reg get_reg_by_ID(int unsigned id); 00226 endclass: vmm_ral_reg 00227 00228 00229 function vmm_ral_reg::new(vmm_ral_block parent, 00230 string name, 00231 int unsigned n_bits, 00232 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00233 string domain, 00234 int cover_on, 00235 bit [1:0] rights, 00236 bit unmapped); 00237 this.locked = 0; 00238 00239 this.parent = parent; 00240 this.parent.register_reg(this); 00241 00242 this.name = name; 00243 this.cover_on = cover_on; 00244 this.has_cover = cover_on; 00245 00246 if (n_bits == 0) begin 00247 `vmm_error(this.log, $psprintf("Register \"%s\" cannot have 0 bits", this.get_name())); 00248 n_bits = 1; 00249 end 00250 if (n_bits > `VMM_RAL_DATA_WIDTH) begin 00251 `vmm_error(this.log, $psprintf("Register \"%s\" cannot have more than %0d bits (%0d)", this.get_name(), `VMM_RAL_DATA_WIDTH, n_bits)); 00252 n_bits = `VMM_RAL_DATA_WIDTH; 00253 end 00254 this.n_bits = n_bits; 00255 this.n_used_bits = 0; 00256 this.add_domain(offset, domain, rights, unmapped); 00257 00258 this.atomic = new(1); 00259 00260 this.Xis_busyX = 0; 00261 00262 // Initialize Register ID 00263 this.__vmm_reg_id = ++this.__vmm_reg_id_factory; 00264 __vmm_all_regs[this.__vmm_reg_id] = this; 00265 endfunction: new 00266 00267 00268 function void vmm_ral_reg::Xlock_modelX(); 00269 int idx; 00270 string fullname; 00271 00272 if (this.locked) return; 00273 00274 this.locked = 1; 00275 00276 endfunction: Xlock_modelX 00277 00278 00279 function void vmm_ral_reg::add_domain(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00280 string domain, 00281 bit [1:0] rights, 00282 bit unmapped); 00283 // Verify that this is a valid domain in the block 00284 string domains[]; 00285 vmm_ral::access_e acc; 00286 00287 if (this.locked) begin 00288 `vmm_error(this.log, "Cannot add domain to locked register model"); 00289 return; 00290 end 00291 00292 case (rights) 00293 2'b11: acc = vmm_ral::RW; 00294 2'b10: acc = vmm_ral::RO; 00295 2'b01: acc = vmm_ral::WO; 00296 default: 00297 `vmm_error(this.log, 00298 $psprintf("Register \"%s\" has no access rights in domain \"%s\"", 00299 this.get_name(), domain)); 00300 endcase 00301 00302 this.parent.get_domains(domains); 00303 foreach(domains[i]) begin 00304 if (domains[i] == domain) begin 00305 automatic int n = this.offset_in_block.size(); 00306 00307 this.offset_in_block = new [n + 1] (this.offset_in_block); 00308 this.offset_in_block[n] = (unmapped) ? 'x : offset; 00309 00310 this.domains = new [n + 1] (this.domains); 00311 this.domains[n] = domain; 00312 00313 this.rights = new [n + 1] (this.rights); 00314 this.rights[n] = acc; 00315 00316 this.frontdoor = new [n + 1] (this.frontdoor); 00317 this.frontdoor[n] = null; 00318 00319 this.domain_coverage(domain, rights, n); 00320 return; 00321 end 00322 end 00323 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in parent block %s of register \"%s\"", 00324 domain, this.parent.get_name(), this.get_name())); 00325 endfunction: add_domain 00326 00327 00328 function void vmm_ral_reg::register_field(vmm_ral_field field); 00329 int offset; 00330 int idx; 00331 00332 if (this.locked) begin 00333 `vmm_error(this.log, "Cannot add field to locked register model"); 00334 return; 00335 end 00336 00337 if (field == null) `vmm_fatal(this.log, "Attempting to register NULL field"); 00338 00339 // Store fields in LSB to MSB order 00340 offset = field.get_lsb_pos_in_register(); 00341 00342 idx = -1; 00343 foreach (this.fields[i]) begin 00344 if (offset < this.fields[i].get_lsb_pos_in_register()) begin 00345 int j = i; 00346 this.fields.insert(j, field); 00347 idx = i; 00348 break; 00349 end 00350 end 00351 if (idx < 0) begin 00352 this.fields.push_back(field); 00353 idx = this.fields.size()-1; 00354 end 00355 00356 this.n_used_bits += field.get_n_bits(); 00357 00358 // Check if there are too many fields in the register 00359 if (this.n_used_bits > this.n_bits) begin 00360 `vmm_error(this.log, $psprintf("Fields use more bits (%0d) than available in register \"%s\" (%0d)", 00361 this.n_used_bits, this.get_name(), this.n_bits)); 00362 end 00363 00364 // Check if there are overlapping fields 00365 if (idx > 0) begin 00366 if (this.fields[idx-1].get_lsb_pos_in_register() + 00367 this.fields[idx-1].get_n_bits() > offset) begin 00368 `vmm_error(this.log, $psprintf("Field %s overlaps field %s in register \"%s\"", 00369 this.fields[idx-1].get_name(), 00370 field.get_name(), this.get_name())); 00371 end 00372 end 00373 if (idx < this.fields.size()-1) begin 00374 if (offset + field.get_n_bits() > 00375 this.fields[idx+1].get_lsb_pos_in_register()) begin 00376 `vmm_error(this.log, $psprintf("Field %s overlaps field %s in register \"%s\"", 00377 field.get_name(), 00378 this.fields[idx+1].get_name(), 00379 00380 this.get_name())); 00381 end 00382 end 00383 endfunction: register_field 00384 00385 00386 function void vmm_ral_reg::Xregister_ral_accessX(vmm_ral_access access); 00387 // There can only be one RAL Access on a RAL model 00388 if (this.ral_access != null && this.ral_access != access) begin 00389 `vmm_fatal(this.log, $psprintf("Register \"%s\" is already used by another RAL access instance", this.get_name())); 00390 end 00391 this.ral_access = access; 00392 endfunction: Xregister_ral_accessX 00393 00394 00395 function void vmm_ral_reg::Xadd_constraintsX(string name); 00396 int n; 00397 00398 if (this.locked) begin 00399 `vmm_error(this.log, "Cannot add constraints to locked register model"); 00400 return; 00401 end 00402 00403 // Check if the constraint block already exists 00404 foreach (this.constr[i]) begin 00405 if (this.constr[i] == name) begin 00406 `vmm_warning(this.log, $psprintf("Constraint \"%s\" already added", 00407 name)); 00408 return; 00409 end 00410 end 00411 00412 // Append the constraint name to the list 00413 n = this.constr.size(); 00414 this.constr = new [n+1] (this.constr); 00415 this.constr[n] = name; 00416 endfunction: Xadd_constraintsX 00417 00418 00419 task vmm_ral_reg::XatomicX(bit on); 00420 if (on) this.atomic.get(1); 00421 else begin 00422 // Maybe a key was put back in by a spurious call to reset() 00423 this.atomic.try_get(1); 00424 this.atomic.put(1); 00425 end 00426 endtask: XatomicX 00427 00428 00429 function string vmm_ral_reg::get_name(); 00430 get_name = this.name; 00431 endfunction: get_name 00432 00433 00434 function string vmm_ral_reg::get_fullname(); 00435 vmm_ral_block blk; 00436 00437 get_fullname = this.get_name(); 00438 00439 // Do not include top-level name in full name 00440 blk = this.get_block(); 00441 if (blk == null) return get_fullname; 00442 if (blk.get_parent() == null) return get_fullname; 00443 00444 get_fullname = {this.parent.get_fullname(), ".", get_fullname}; 00445 endfunction: get_fullname 00446 00447 00448 function int vmm_ral_reg::get_n_domains(); 00449 get_n_domains = this.domains.size(); 00450 endfunction: get_n_domains 00451 00452 00453 function void vmm_ral_reg::get_domains(ref string domains[]); 00454 domains = new [this.domains.size()] (this.domains); 00455 endfunction: get_domains 00456 00457 00458 function vmm_ral::access_e vmm_ral_reg::get_rights(string domain); 00459 int i; 00460 00461 // No right restrictions if not shared 00462 if (this.domains.size() == 1) begin 00463 return vmm_ral::RW; 00464 end 00465 00466 i = this.get_domain_index(domain); 00467 if (i < 0) return vmm_ral::RW; 00468 00469 get_rights = this.rights[i]; 00470 endfunction: get_rights 00471 00472 00473 function vmm_ral_block vmm_ral_reg::get_block(); 00474 get_block = this.parent; 00475 endfunction: get_block 00476 00477 00478 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_reg::get_offset_in_block(string domain); 00479 foreach (this.domains[i]) begin 00480 if (this.domains[i] == domain) begin 00481 if (this.offset_in_block[i] === 'x) begin 00482 `vmm_warning(this.log, $psprintf("Register \"%s\" is unmapped in domain \"%s\".", this.get_name(), domain)); 00483 return '0; 00484 end 00485 00486 return this.offset_in_block[i]; 00487 end 00488 end 00489 `vmm_warning(this.log, $psprintf("Unable to find offset within domain \"%s\" in register \"%s\".", 00490 domain, this.get_name())); 00491 get_offset_in_block = '1; 00492 endfunction: get_offset_in_block 00493 00494 00495 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_reg::get_address_in_system(string domain); 00496 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[]; 00497 00498 int i = this.get_domain_index(domain); 00499 if (i < 0) return 0; 00500 00501 if (this.ral_access == null) begin 00502 `vmm_fatal(this.parent.log, 00503 "RAL model is not associated with an access transactor"); 00504 return 0; 00505 end 00506 00507 if (this.offset_in_block[i] === 'x) begin 00508 `vmm_error(this.log, $psprintf("Register \"%s\" is unmapped in domain \"%s\".", this.get_name(), this.domains[i])); 00509 return '1; 00510 end 00511 00512 this.ral_access.Xget_physical_addressesX(this.offset_in_block[i], 00513 0, this.get_n_bytes(), 00514 this.parent, this.domains[i], 00515 addr); 00516 00517 get_address_in_system = addr[addr.size()-1]; 00518 00519 // Make sure to return the lower address as Xget_physical_addressesX() 00520 // returns the address in little-endian sequence. 00521 if (addr[0] < get_address_in_system) get_address_in_system = addr[0]; 00522 endfunction: get_address_in_system 00523 00524 00525 function int unsigned vmm_ral_reg::get_n_bytes(); 00526 get_n_bytes = ((this.n_bits-1) / 8) + 1; 00527 endfunction: get_n_bytes 00528 00529 00530 function void vmm_ral_reg::display(string prefix, 00531 string domain); 00532 $write("%s\n", this.psdisplay(prefix, domain)); 00533 endfunction: display 00534 00535 00536 function string vmm_ral_reg::psdisplay(string prefix, 00537 string domain); 00538 $sformat(psdisplay, "%sRegister %s -- %0d bytes @", prefix, 00539 this.get_fullname(), this.get_n_bytes()); 00540 foreach (this.domains[i]) begin 00541 if (this.domains[i] == domain) begin 00542 if (this.offset_in_block[i] === 'x) begin 00543 psdisplay = {psdisplay, "none"}; 00544 end 00545 else begin 00546 $sformat(psdisplay, "%s'h%h", psdisplay, 00547 this.get_address_in_system(domain)); 00548 end 00549 break; 00550 end 00551 end 00552 foreach(this.fields[i]) begin 00553 $sformat(psdisplay, "%s\n%s", psdisplay, 00554 this.fields[i].psdisplay({prefix, " "})); 00555 end 00556 endfunction: psdisplay 00557 00558 00559 function void vmm_ral_reg::get_fields(ref vmm_ral_field fields[]); 00560 fields = new [this.fields.size()]; 00561 foreach(this.fields[i]) begin 00562 fields[i] = this.fields[i]; 00563 end 00564 endfunction: get_fields 00565 00566 00567 function vmm_ral_field vmm_ral_reg::get_field_by_name(string name); 00568 foreach (this.fields[i]) begin 00569 if (this.fields[i].get_name() == name) begin 00570 return this.fields[i]; 00571 end 00572 end 00573 `vmm_warning(this.log, $psprintf("Unable to locate field \"%s\" in register \"%s\".", 00574 name, this.get_name())); 00575 get_field_by_name = null; 00576 endfunction: get_field_by_name 00577 00578 00579 function void vmm_ral_reg::get_constraints(ref string names[]); 00580 names = new [this.constr.size()] (this.constr); 00581 endfunction: get_constraints 00582 00583 00584 function bit vmm_ral_reg::can_cover(int models); 00585 return ((this.has_cover & models) != vmm_ral::NO_COVERAGE); 00586 endfunction: can_cover 00587 00588 00589 function int vmm_ral_reg::set_cover(int is_on); 00590 set_cover = this.cover_on; 00591 00592 if (~this.has_cover && is_on) begin 00593 `vmm_warning(this.log, $psprintf("Cannot turn cover ON if not constructed with corresponding coverage model in register \"%s\"", this.get_name())); 00594 return 0; 00595 end 00596 00597 this.cover_on = is_on; 00598 endfunction: set_cover 00599 00600 00601 function bit vmm_ral_reg::is_cover_on(int is_on); 00602 return ((this.cover_on & is_on) == is_on); 00603 endfunction: is_cover_on 00604 00605 00606 function void vmm_ral_reg::XforceX(bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00607 vmm_ral::path_e path, 00608 string domain); 00609 // Fields are stored in LSB or MSB order 00610 foreach (this.fields[i]) begin 00611 this.fields[i].XforceX(value >> this.fields[i].get_lsb_pos_in_register(), 00612 path, domain); 00613 end 00614 endfunction: XforceX 00615 00616 00617 function void vmm_ral_reg::XwroteX(bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00618 vmm_ral::path_e path, 00619 string domain); 00620 int j, w; 00621 00622 // Fields are stored in LSB or MSB order 00623 foreach (this.fields[i]) begin 00624 j = this.fields[i].get_lsb_pos_in_register(); 00625 w = this.fields[i].get_n_bits(); 00626 this.fields[i].XwroteX((value >> j) & ((1 << w) - 1), path, domain); 00627 end 00628 endfunction: XwroteX 00629 00630 00631 function void vmm_ral_reg::set(bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00632 // Split the value into the individual fields 00633 int j, w; 00634 00635 // Fields are stored in LSB or MSB order 00636 foreach (this.fields[i]) begin 00637 j = this.fields[i].get_lsb_pos_in_register(); 00638 w = this.fields[i].get_n_bits(); 00639 this.fields[i].set((value >> j) & ((1 << w) - 1)); 00640 end 00641 endfunction: set 00642 00643 00644 function bit vmm_ral_reg::predict(bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00645 if (this.Xis_busyX) begin 00646 `vmm_warning(this.log, $psprintf("Trying to predict value of register \"%s\" while it is being accessed", 00647 this.get_fullname())); 00648 return 0; 00649 end 00650 00651 predict = 1; 00652 00653 // Fields are stored in LSB or MSB order 00654 foreach (this.fields[i]) begin 00655 predict &= this.fields[i].predict(value >> this.fields[i].get_lsb_pos_in_register()); 00656 end 00657 endfunction: predict 00658 00659 00660 function bit[`VMM_RAL_DATA_WIDTH-1:0] vmm_ral_reg::get(); 00661 // Concatenate the value of the individual fields 00662 // to form the register value 00663 int j, w; 00664 00665 get = 0; 00666 00667 // Fields are stored in LSB or MSB order 00668 foreach (this.fields[i]) begin 00669 j = this.fields[i].get_lsb_pos_in_register(); 00670 get |= this.fields[i].get() << j; 00671 end 00672 endfunction: get 00673 00674 00675 function void vmm_ral_reg::reset(vmm_ral::reset_e kind); 00676 foreach (this.fields[i]) begin 00677 this.fields[i].reset(kind); 00678 end 00679 // Put back a key in the semaphore if it is checked out 00680 // in case a thread was killed during an operation 00681 this.atomic.try_get(1); 00682 this.atomic.put(1); 00683 endfunction: reset 00684 00685 00686 function bit vmm_ral_reg::needs_update(); 00687 needs_update = 0; 00688 foreach (this.fields[i]) begin 00689 if (this.fields[i].needs_update()) begin 00690 return 1; 00691 end 00692 end 00693 endfunction: needs_update 00694 00695 00696 task vmm_ral_reg::update(output vmm_rw::status_e status, 00697 input vmm_ral::path_e path, 00698 input string domain); 00699 bit [`VMM_RAL_DATA_WIDTH-1:0] upd; 00700 int j; 00701 00702 status = vmm_rw::IS_OK; 00703 if (!this.needs_update()) return; 00704 00705 this.XatomicX(1); 00706 00707 // Concatenate the write-to-update values from each field 00708 // Fields are stored in LSB or MSB order 00709 upd = 0; 00710 foreach (this.fields[i]) begin 00711 j = this.fields[i].get_lsb_pos_in_register(); 00712 upd |= this.fields[i].XupdX() << j; 00713 end 00714 00715 this.XwriteX(status, upd, path, domain, -1, -1, -1); 00716 00717 this.XatomicX(0); 00718 endtask: update 00719 00720 00721 task vmm_ral_reg::write(output vmm_rw::status_e status, 00722 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00723 input vmm_ral::path_e path, 00724 input string domain, 00725 input int data_id, 00726 input int scenario_id, 00727 input int stream_id); 00728 this.XatomicX(1); 00729 this.XwriteX(status, value, path, domain, data_id, scenario_id, stream_id); 00730 this.XatomicX(0); 00731 endtask: write 00732 00733 00734 task vmm_ral_reg::XwriteX(output vmm_rw::status_e status, 00735 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00736 input vmm_ral::path_e path, 00737 input string domain, 00738 input int data_id, 00739 input int scenario_id, 00740 input int stream_id); 00741 status = vmm_rw::ERROR; 00742 00743 if (this.ral_access == null) begin 00744 `vmm_error(this.log, $psprintf("Register \"%s\" not associated with RAL access object", this.get_name())); 00745 return; 00746 end 00747 00748 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00749 00750 begin 00751 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00752 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00753 int lsb; 00754 00755 foreach (fields[i]) begin 00756 vmm_ral_field f = fields[i]; 00757 00758 lsb = f.get_lsb_pos_in_register(); 00759 00760 msk = ((1<<f.get_n_bits())-1) << lsb; 00761 tmp = (value & msk) >> lsb; 00762 00763 foreach (f.XcbsX[j]) begin 00764 vmm_ral_field_callbacks cb; 00765 if (!$cast(cb, f.XcbsX[j])) continue; 00766 cb.pre_write(f, tmp, path, domain); 00767 end 00768 00769 value = (value & ~msk) | (tmp << lsb); 00770 end 00771 end 00772 `vmm_callback(vmm_ral_reg_callbacks, 00773 pre_write(this, value, path, domain)); 00774 00775 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00776 00777 if (path == vmm_ral::BACKDOOR && 00778 this.backdoor == null) begin 00779 `vmm_warning(this.log, $psprintf("No backdoor access available for register \"%s\". Using frontdoor instead.", this.get_name())); 00780 path = vmm_ral::BFM; 00781 end 00782 00783 case (path) 00784 00785 vmm_ral::BFM: begin 00786 int di = this.get_domain_index(domain); 00787 if (di < 0) return; 00788 00789 this.Xis_busyX = 1; 00790 00791 if (this.frontdoor[di] != null) begin 00792 this.frontdoor[di].write(status, value, 00793 data_id, scenario_id, stream_id); 00794 end 00795 else begin 00796 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[]; 00797 int w, j; 00798 int n_bits; 00799 00800 if (this.offset_in_block[di] === 'x) begin 00801 `vmm_error(this.log, $psprintf("Register \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor", 00802 this.get_name(), 00803 this.domains[di])); 00804 return; 00805 end 00806 00807 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di], 00808 0, this.get_n_bytes(), 00809 this.parent, 00810 this.domains[di], 00811 addr); 00812 j = 0; 00813 n_bits = this.get_n_bytes() * 8; 00814 foreach (addr[i]) begin 00815 bit [`VMM_RAL_DATA_WIDTH-1:0] data; 00816 data = value >> (j*8); 00817 this.ral_access.write(status, addr[i], data, 00818 (n_bits > w*8) ? w*8 : n_bits, 00819 this.parent.get_external_domain(this.domains[di]), 00820 data_id, scenario_id, stream_id); 00821 if (status != vmm_rw::IS_OK) return; 00822 j += w; 00823 n_bits -= w * 8; 00824 end 00825 end 00826 00827 if (this.cover_on) begin 00828 this.sample(value, 0, di); 00829 this.parent.XsampleX(this.offset_in_block[di], di); 00830 end 00831 00832 this.Xis_busyX = 0; 00833 00834 this.XwroteX(value, path, domain); 00835 end 00836 00837 vmm_ral::BACKDOOR: begin 00838 bit [`VMM_RAL_DATA_WIDTH-1:0] reg_val; 00839 bit [`VMM_RAL_DATA_WIDTH-1:0] final_val; 00840 00841 // Mimick the final value after a physical read 00842 this.backdoor.read(status, reg_val, 00843 data_id, scenario_id, stream_id); 00844 if (status != vmm_rw::IS_OK) return; 00845 00846 begin 00847 int j, w; 00848 00849 // Fields are stored in LSB or MSB order 00850 final_val = '0; 00851 foreach (this.fields[i]) begin 00852 bit [`VMM_RAL_DATA_WIDTH-1:0] field_val; 00853 j = this.fields[i].get_lsb_pos_in_register(); 00854 w = this.fields[i].get_n_bits(); 00855 field_val = this.fields[i].XpredictX((reg_val >> j) & ((1 << w) - 1), 00856 (value >> j) & ((1 << w) - 1), 00857 domain); 00858 final_val |= field_val << j; 00859 end 00860 end 00861 this.backdoor.write(status, final_val, data_id, scenario_id, stream_id); 00862 this.XwroteX(final_val, path, "-"); 00863 end 00864 endcase 00865 00866 begin 00867 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00868 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00869 int lsb; 00870 00871 value = this.get(); 00872 00873 foreach (fields[i]) begin 00874 vmm_ral_field f = fields[i]; 00875 00876 lsb = f.get_lsb_pos_in_register(); 00877 00878 msk = ((1<<f.get_n_bits())-1) << lsb; 00879 tmp = (value & msk) >> lsb; 00880 00881 foreach (f.XcbsX[j]) begin 00882 vmm_ral_field_callbacks cb; 00883 if (!$cast(cb, f.XcbsX[j])) continue; 00884 cb.post_write(f, tmp, path, domain, status); 00885 end 00886 end 00887 end 00888 00889 `vmm_trace(this.log, $psprintf("Wrote register \"%s\" via %s with: 'h%h", 00890 this.get_fullname(), 00891 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 00892 value)); 00893 00894 `vmm_callback(vmm_ral_reg_callbacks, 00895 post_write(this, value, path, domain, status)); 00896 endtask: XwriteX 00897 00898 00899 task vmm_ral_reg::read(output vmm_rw::status_e status, 00900 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00901 input vmm_ral::path_e path, 00902 input string domain, 00903 input int data_id, 00904 input int scenario_id, 00905 input int stream_id); 00906 this.XatomicX(1); 00907 this.XreadX(status, value, path, domain, data_id, scenario_id, stream_id); 00908 this.XatomicX(0); 00909 endtask: read 00910 00911 00912 task vmm_ral_reg::XreadX(output vmm_rw::status_e status, 00913 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00914 input vmm_ral::path_e path, 00915 input string domain, 00916 input int data_id, 00917 input int scenario_id, 00918 input int stream_id); 00919 status = vmm_rw::ERROR; 00920 00921 if (this.ral_access == null) begin 00922 `vmm_error(this.log, $psprintf("Register \"%s\" not associated with RAL access object", this.get_name())); 00923 return; 00924 end 00925 00926 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00927 00928 foreach (fields[i]) begin 00929 vmm_ral_field f = fields[i]; 00930 00931 foreach (f.XcbsX[j]) begin 00932 vmm_ral_field_callbacks cb; 00933 if (!$cast(cb, f.XcbsX[j])) continue; 00934 cb.pre_read(f, path, domain); 00935 end 00936 end 00937 `vmm_callback(vmm_ral_reg_callbacks, 00938 pre_read(this, path, domain)); 00939 00940 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00941 00942 if (path == vmm_ral::BACKDOOR && 00943 this.backdoor == null) begin 00944 `vmm_warning(this.log, $psprintf("No backdoor access available for register \"%s\". Using frontdoor instead.", this.get_name())); 00945 path = vmm_ral::BFM; 00946 end 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 this.Xis_busyX = 1; 00955 00956 if (this.frontdoor[di] != null) begin 00957 this.frontdoor[di].read(status, value, 00958 data_id, scenario_id, stream_id); 00959 end 00960 else begin 00961 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[]; 00962 int w, j; 00963 int n_bits; 00964 00965 if (this.offset_in_block[di] === 'x) begin 00966 `vmm_error(this.log, $psprintf("Register \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor", 00967 this.get_name(), 00968 this.domains[di])); 00969 return; 00970 end 00971 00972 w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di], 00973 0, this.get_n_bytes(), 00974 this.parent, 00975 this.domains[di], 00976 addr); 00977 j = 0; 00978 n_bits = this.get_n_bytes() * 8; 00979 value = 0; 00980 foreach (addr[i]) begin 00981 bit [`VMM_RAL_DATA_WIDTH-1:0] data; 00982 this.ral_access.read(status, addr[i], data, 00983 (n_bits > w*8) ? w*8 : n_bits, 00984 this.parent.get_external_domain(this.domains[di]), 00985 data_id, scenario_id, stream_id); 00986 if (status != vmm_rw::IS_OK) return; 00987 value |= (data & ((1 << (w*8)) - 1)) << (j*8); 00988 j += w; 00989 n_bits -= w * 8; 00990 end 00991 end 00992 00993 if (this.cover_on) begin 00994 this.sample(value, 1, di); 00995 this.parent.XsampleX(this.offset_in_block[di], di); 00996 end 00997 00998 this.Xis_busyX = 0; 00999 01000 this.XforceX(value, path, domain); 01001 end 01002 01003 vmm_ral::BACKDOOR: begin 01004 bit [`VMM_RAL_DATA_WIDTH-1:0] final_val; 01005 01006 this.backdoor.read(status, value, data_id, scenario_id, stream_id); 01007 final_val = value; 01008 01009 // Need to clear RC fields and mask WO fields 01010 if (status == vmm_rw::IS_OK) begin 01011 bit [`VMM_RAL_DATA_WIDTH-1:0] wo_mask = 0; 01012 01013 foreach (this.fields[i]) begin 01014 vmm_ral::access_e acc = this.fields[i].get_access("BaCkDoOr"); 01015 if (acc == vmm_ral::RC) begin 01016 final_val &= ~(((1<<this.fields[i].get_n_bits())-1) << this.fields[i].get_lsb_pos_in_register()); 01017 end 01018 else if (acc == vmm_ral::WO) begin 01019 wo_mask |= ((1<<this.fields[i].get_n_bits())-1) << this.fields[i].get_lsb_pos_in_register(); 01020 end 01021 end 01022 01023 if (final_val != value) begin 01024 this.backdoor.write(status, final_val, 01025 data_id, scenario_id, stream_id); 01026 end 01027 01028 value &= ~wo_mask; 01029 this.XforceX(final_val, path, "-"); 01030 end 01031 end 01032 endcase 01033 01034 01035 begin 01036 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 01037 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 01038 int lsb; 01039 01040 foreach (fields[i]) begin 01041 vmm_ral_field f = fields[i]; 01042 01043 lsb = f.get_lsb_pos_in_register(); 01044 01045 msk = ((1<<f.get_n_bits())-1) << lsb; 01046 tmp = (value & msk) >> lsb; 01047 01048 foreach (f.XcbsX[j]) begin 01049 vmm_ral_field_callbacks cb; 01050 if (!$cast(cb, f.XcbsX[j])) continue; 01051 cb.post_read(f, tmp, path, domain, status); 01052 end 01053 01054 value = (value & ~msk) | (tmp << lsb); 01055 end 01056 end 01057 01058 `vmm_trace(this.log, $psprintf("Read register \"%s\" via %s: 'h%h", 01059 this.get_fullname(), 01060 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 01061 value)); 01062 01063 `vmm_callback(vmm_ral_reg_callbacks, 01064 post_read(this, value, path, domain, status)); 01065 endtask: XreadX 01066 01067 01068 task vmm_ral_reg::poke(output vmm_rw::status_e status, 01069 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 01070 input int data_id, 01071 input int scenario_id, 01072 input int stream_id); 01073 this.XatomicX(1); 01074 01075 if (this.backdoor == null) begin 01076 `vmm_error(this.log, $psprintf("No backdoor access available to poke register \"%s\"", this.get_name())); 01077 status = vmm_rw::ERROR; 01078 return; 01079 end 01080 01081 this.backdoor.write(status, value, data_id, scenario_id, stream_id); 01082 01083 `vmm_trace(this.log, $psprintf("Poked register \"%s\" with: 'h%h", 01084 this.get_fullname(), value)); 01085 01086 this.XforceX(value, vmm_ral::BACKDOOR, "-"); 01087 this.XatomicX(0); 01088 endtask: poke 01089 01090 01091 task vmm_ral_reg::peek(output vmm_rw::status_e status, 01092 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 01093 input int data_id, 01094 input int scenario_id, 01095 input int stream_id); 01096 this.XatomicX(1); 01097 if (this.backdoor == null) begin 01098 `vmm_error(this.log, $psprintf("No backdoor access available peek register \"%s\"", this.get_name())); 01099 status = vmm_rw::ERROR; 01100 return; 01101 end 01102 this.backdoor.read(status, value, data_id, scenario_id, stream_id); 01103 01104 `vmm_trace(this.log, $psprintf("Peeked register \"%s\": 'h%h", 01105 this.get_fullname(), value)); 01106 01107 this.XforceX(value, vmm_ral::BACKDOOR, "-"); 01108 01109 this.XatomicX(0); 01110 endtask: peek 01111 01112 01113 task vmm_ral_reg::mirror(output vmm_rw::status_e status, 01114 input vmm_ral::check_e check, 01115 input vmm_ral::path_e path, 01116 input string domain); 01117 bit [`VMM_RAL_DATA_WIDTH-1:0] v; 01118 bit [`VMM_RAL_DATA_WIDTH-1:0] exp; 01119 01120 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 01121 01122 this.XatomicX(1); 01123 01124 if (path == vmm_ral::BACKDOOR && this.backdoor != null) begin 01125 domain = "BaCkDoOr"; 01126 end 01127 01128 // Remember what we think the value is before it gets updated 01129 if (check == vmm_ral::VERB) begin 01130 exp = this.get(); 01131 // Any WO field will readback as 0's 01132 foreach(this.fields[i]) begin 01133 if (this.fields[i].get_access(domain) == vmm_ral::WO) begin 01134 exp &= ~(((1 << this.fields[i].get_n_bits())-1) 01135 << this.fields[i].get_lsb_pos_in_register()); 01136 end 01137 end 01138 end 01139 01140 this.XreadX(status, v, path, domain, -1, -1, -1); 01141 01142 if (status != vmm_rw::IS_OK) begin 01143 this.XatomicX(0); 01144 return; 01145 end 01146 01147 if (check == vmm_ral::VERB) begin 01148 // Check that our idea of the register value matches 01149 // what we just read from the DUT, minus the don't care fields 01150 bit [`VMM_RAL_DATA_WIDTH-1:0] dc = 0; 01151 01152 foreach(this.fields[i]) begin 01153 vmm_ral::access_e acc = this.fields[i].get_access(domain); 01154 if (acc == vmm_ral::DC) begin 01155 dc |= ((1 << this.fields[i].get_n_bits())-1) 01156 << this.fields[i].get_lsb_pos_in_register(); 01157 end 01158 else if (acc == vmm_ral::WO) begin 01159 // WO fields will always read-back as 0 01160 exp &= ~(((1 << this.fields[i].get_n_bits())-1) 01161 << this.fields[i].get_lsb_pos_in_register()); 01162 end 01163 end 01164 01165 if ((v|dc) !== (exp|dc)) begin 01166 `vmm_error(this.log, $psprintf("Register \"%s\" value read from DUT (0x%h) does not match mirrored value (0x%h)", 01167 this.get_name(), v, (exp ^ ('x & dc)))); 01168 end 01169 end 01170 01171 this.XatomicX(0); 01172 endtask: mirror 01173 01174 01175 function void vmm_ral_reg::set_frontdoor(vmm_ral_reg_frontdoor ftdr, 01176 string domain); 01177 foreach(this.domains[i]) begin 01178 if (this.domains[i] == domain) begin 01179 this.frontdoor[i] = ftdr; 01180 return; 01181 end 01182 end 01183 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in register %s", domain, this.get_fullname())); 01184 endfunction: set_frontdoor 01185 01186 01187 function vmm_ral_reg_frontdoor vmm_ral_reg::get_frontdoor(string domain); 01188 foreach(this.domains[i]) begin 01189 if (this.domains[i] == domain) begin 01190 return this.frontdoor[i]; 01191 end 01192 end 01193 `vmm_error(this.log, $psprintf("Domain \"%s\" not found in register %s", domain, this.get_fullname())); 01194 endfunction: get_frontdoor 01195 01196 01197 function void vmm_ral_reg::set_backdoor(vmm_ral_reg_backdoor bkdr); 01198 this.backdoor = bkdr; 01199 endfunction: set_backdoor 01200 01201 01202 function vmm_ral_reg_backdoor vmm_ral_reg::get_backdoor(); 01203 get_backdoor = this.backdoor; 01204 endfunction: get_backdoor 01205 01206 01207 function void vmm_ral_reg::prepend_callback(vmm_ral_reg_callbacks cb); 01208 foreach (this.callbacks[i]) begin 01209 if (this.callbacks[i] == cb) begin 01210 `vmm_warning(this.log, $psprintf("Callback has already been registered with register \"%s\"", this.get_name())); 01211 return; 01212 end 01213 end 01214 01215 // Prepend new callback 01216 this.callbacks.push_front(cb); 01217 endfunction: prepend_callback 01218 01219 01220 function void vmm_ral_reg::append_callback(vmm_ral_reg_callbacks cb); 01221 foreach (this.callbacks[i]) begin 01222 if (this.callbacks[i] == cb) begin 01223 `vmm_warning(this.log, $psprintf("Callback has already been registered with register \"%s\"", this.get_name())); 01224 return; 01225 end 01226 end 01227 01228 // Append new callback 01229 this.callbacks.push_back(cb); 01230 endfunction: append_callback 01231 01232 01233 function void vmm_ral_reg::unregister_callback(vmm_ral_reg_callbacks cb); 01234 foreach (this.callbacks[i]) begin 01235 if (this.callbacks[i] == cb) begin 01236 int j = i; 01237 // Unregister it 01238 this.callbacks.delete(j); 01239 return; 01240 end 01241 end 01242 01243 `vmm_warning(this.log, $psprintf("Callback was not registered with register \"%s\"", this.get_name())); 01244 endfunction: unregister_callback 01245 01246 01247 function int vmm_ral_reg::get_domain_index(string domain); 01248 // If the domain is "" and there is only one domain, 01249 // assume it is the one domain available to avoid 01250 // having to always have to specify domains 01251 if (domain == "" && this.domains.size() == 1) return 0; 01252 01253 foreach (this.domains[i]) begin 01254 if (this.domains[i] == domain) return i; 01255 end 01256 `vmm_warning(this.log, $psprintf("Unknown domain name \"%s\" in register \"%s\".", domain, this.get_name())); 01257 return -1; 01258 endfunction: get_domain_index 01259 01260 01261 task vmm_ral_reg_frontdoor::write(output vmm_rw::status_e status, 01262 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 01263 input int data_id, 01264 input int scenario_id, 01265 input int stream_id); 01266 `vmm_fatal(this.log, "vmm_ral_reg_frontdoor::write() method has not been overloaded"); 01267 endtask: write 01268 01269 01270 task vmm_ral_reg_frontdoor::read(output vmm_rw::status_e status, 01271 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 01272 input int data_id, 01273 input int scenario_id, 01274 input int stream_id); 01275 `vmm_fatal(this.log, "vmm_ral_reg_frontdoor::read() method has not been overloaded"); 01276 endtask: read 01277 01278 01279 function void vmm_ral_reg::sample(bit [`VMM_RAL_DATA_WIDTH-1:0] data, 01280 bit is_read, 01281 int domain); 01282 // Nothing to do in this base class 01283 endfunction 01284 01285 01286 function int unsigned vmm_ral_reg::get_reg_ID(); 01287 get_reg_ID = this.__vmm_reg_id; 01288 endfunction 01289 01290 function vmm_ral_reg vmm_ral_reg::get_reg_by_ID(int unsigned id); 01291 if (__vmm_all_regs.exists(id)) get_reg_by_ID = __vmm_all_regs[id]; 01292 else get_reg_by_ID = null; 01293 endfunction