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