00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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[*];
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[$];
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 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 extern function void Xlock_modelX();
00112 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 extern function void register_field(vmm_ral_field field);
00123 extern function void Xregister_ral_accessX(vmm_ral_access access);
00124 extern function void Xadd_constraintsX(string name);
00125 extern task XatomicX(bit on);
00126 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 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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
00633 int j, w;
00634
00635
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
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
00662
00663 int j, w;
00664
00665 get = 0;
00666
00667
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
00680
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
00708
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
01129 if (check == vmm_ral::VERB) begin
01130 exp = this.get();
01131
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
01149
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
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