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