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 typedef class vmm_mam_region;
00024 typedef class vmm_mam;
00025
00026
00027 class vmm_ral_vreg_callbacks extends vmm_ral_callbacks;
00028
00029 virtual task pre_write(vmm_ral_vreg rg,
00030 longint unsigned idx,
00031 ref bit [`VMM_RAL_DATA_WIDTH-1:0] wdat,
00032 ref vmm_ral::path_e path,
00033 ref string domain);
00034 endtask: pre_write
00035
00036 virtual task post_write(vmm_ral_vreg rg,
00037 longint unsigned idx,
00038 bit [`VMM_RAL_DATA_WIDTH-1:0] wdat,
00039 vmm_ral::path_e path,
00040 string domain,
00041 ref vmm_rw::status_e status);
00042 endtask: post_write
00043
00044 virtual task pre_read(vmm_ral_vreg rg,
00045 longint unsigned idx,
00046 ref vmm_ral::path_e path,
00047 ref string domain);
00048 endtask: pre_read
00049
00050 virtual task post_read(vmm_ral_vreg rg,
00051 longint unsigned idx,
00052 ref bit [`VMM_RAL_DATA_WIDTH-1:0] rdat,
00053 input vmm_ral::path_e path,
00054 input string domain,
00055 ref vmm_rw::status_e status);
00056 endtask: post_read
00057 endclass: vmm_ral_vreg_callbacks
00058
00059
00060 class vmm_ral_vreg;
00061 static vmm_log log = new("RAL", "virtual register");
00062
00063 local bit locked;
00064 local vmm_ral_block parent;
00065 local string name;
00066 local int unsigned n_bits;
00067 local int unsigned n_used_bits;
00068
00069 local vmm_ral_vfield fields[$]; // Fields in LSB to MSB order
00070
00071 local vmm_ral_vreg_callbacks callbacks[$];
00072
00073 local vmm_ral_mem mem; // Where is it implemented?
00074 local bit [`VMM_RAL_ADDR_WIDTH-1:0] offset; // Start of vreg[0]
00075 local int unsigned incr; // From start to start of next
00076 local longint unsigned size; //number of vregs
00077 local bit is_static;
00078
00079 local vmm_mam_region region; // Not NULL if implemented via MAM
00080
00081 local semaphore atomic; // Field RMW operations must be atomic
00082
00083 extern /*local*/ function new(vmm_ral_block parent,
00084 string name,
00085 int unsigned n_bits,
00086 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset = 0,
00087 vmm_ral_mem mem = null,
00088 longint unsigned size = 0,
00089 int unsigned incr = 0);
00090
00091 /*local*/ extern function void Xlock_modelX();
00092
00093 /*local*/ extern function void register_field(vmm_ral_vfield field);
00094 /*local*/ extern task XatomicX(bit on);
00095
00096 extern function void reset(vmm_ral::reset_e kind = vmm_ral::HARD);
00097
00098 extern virtual function string get_name();
00099 extern virtual function string get_fullname();
00100 extern virtual function vmm_ral_block get_block();
00101
00102 extern virtual function bit implement(longint unsigned n,
00103 vmm_ral_mem mem = null,
00104 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset = 0,
00105 int unsigned incr = 0);
00106 extern virtual function vmm_mam_region allocate(longint unsigned n,
00107 vmm_mam mam);
00108 extern virtual function vmm_mam_region get_region();
00109 extern virtual function void release_region();
00110
00111 extern virtual function vmm_ral_mem get_memory();
00112 extern virtual function int get_n_domains();
00113 extern virtual function void get_domains(ref string domains[]);
00114 extern virtual function vmm_ral::access_e get_access(string domain = "");
00115 extern virtual function vmm_ral::access_e get_rights(string domain = "");
00116 extern virtual function bit [`VMM_RAL_ADDR_WIDTH-1:0] get_offset_in_memory(longint unsigned idx);
00117
00118 extern virtual function bit [`VMM_RAL_ADDR_WIDTH-1:0] get_address_in_system(longint unsigned idx,
00119 string domain = "");
00120
00121 extern virtual function int unsigned get_size();
00122 extern virtual function int unsigned get_n_bytes();
00123 extern virtual function int unsigned get_n_memlocs();
00124 extern virtual function int unsigned get_incr();
00125
00126 extern virtual function void display(string prefix = "",
00127 string domain = "");
00128 extern virtual function string psdisplay(string prefix = "",
00129 string domain = "");
00130
00131 extern virtual function void get_fields(ref vmm_ral_vfield fields[]);
00132 extern virtual function vmm_ral_vfield get_field_by_name(string name);
00133
00134 extern virtual task write(input longint unsigned idx,
00135 output vmm_rw::status_e status,
00136 input bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00137 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00138 input string domain = "",
00139 input int data_id = -1,
00140 input int scenario_id = -1,
00141 input int stream_id = -1);
00142 extern virtual task read(input longint unsigned idx,
00143 output vmm_rw::status_e status,
00144 output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00145 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00146 input string domain = "",
00147 input int data_id = -1,
00148 input int scenario_id = -1,
00149 input int stream_id = -1);
00150 extern virtual task poke(input longint unsigned idx,
00151 output vmm_rw::status_e status,
00152 input bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00153 input int data_id = -1,
00154 input int scenario_id = -1,
00155 input int stream_id = -1);
00156 extern virtual task peek(input longint unsigned idx,
00157 output vmm_rw::status_e status,
00158 output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00159 input int data_id = -1,
00160 input int scenario_id = -1,
00161 input int stream_id = -1);
00162
00163 extern function void prepend_callback(vmm_ral_vreg_callbacks cb);
00164 extern function void append_callback(vmm_ral_vreg_callbacks cb);
00165 extern function void unregister_callback(vmm_ral_vreg_callbacks cb);
00166 endclass: vmm_ral_vreg
00167
00168
00169 function vmm_ral_vreg::new(vmm_ral_block parent,
00170 string name,
00171 int unsigned n_bits,
00172 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset = 0,
00173 vmm_ral_mem mem = null,
00174 longint unsigned size = 0,
00175 int unsigned incr = 0);
00176 this.locked = 0;
00177
00178 this.parent = parent;
00179 this.parent.register_vreg(this);
00180 this.name = name;
00181
00182 if (n_bits == 0) begin
00183 `vmm_error(this.log, $psprintf("Virtual register \"%s\" cannot have 0 bits", this.get_fullname()));
00184 n_bits = 1;
00185 end
00186 if (n_bits > `VMM_RAL_DATA_WIDTH) begin
00187 `vmm_error(this.log, $psprintf("Virtual register \"%s\" cannot have more than %0d bits (%0d)", this.get_fullname(), `VMM_RAL_DATA_WIDTH, n_bits));
00188 n_bits = `VMM_RAL_DATA_WIDTH;
00189 end
00190 this.n_bits = n_bits;
00191 this.n_used_bits = 0;
00192
00193 if (mem != null) begin
00194 void'(this.implement(size, mem, offset, incr));
00195 this.is_static = 1;
00196 end
00197 else begin
00198 this.mem = null;
00199 this.is_static = 0;
00200 end
00201
00202 this.atomic = new(1);
00203 endfunction: new
00204
00205
00206 function void vmm_ral_vreg::Xlock_modelX();
00207 if (this.locked) return;
00208
00209 this.locked = 1;
00210 endfunction: Xlock_modelX
00211
00212
00213 function void vmm_ral_vreg::register_field(vmm_ral_vfield field);
00214 int offset;
00215 int idx;
00216
00217 if (this.locked) begin
00218 `vmm_error(this.log, "Cannot add virtual field to locked virtual register model");
00219 return;
00220 end
00221
00222 if (field == null) `vmm_fatal(this.log, "Attempting to register NULL virtual field");
00223
00224 // Store fields in LSB to MSB order
00225 offset = field.get_lsb_pos_in_register();
00226
00227 idx = -1;
00228 foreach (this.fields[i]) begin
00229 if (offset < this.fields[i].get_lsb_pos_in_register()) begin
00230 int j = i;
00231 this.fields.insert(j, field);
00232 idx = i;
00233 break;
00234 end
00235 end
00236 if (idx < 0) begin
00237 this.fields.push_back(field);
00238 idx = this.fields.size()-1;
00239 end
00240
00241 this.n_used_bits += field.get_n_bits();
00242
00243 // Check if there are too many fields in the register
00244 if (this.n_used_bits > this.n_bits) begin
00245 `vmm_error(this.log, $psprintf("Virtual fields use more bits (%0d) than available in virtual register \"%s\" (%0d)",
00246 this.n_used_bits, this.get_fullname(), this.n_bits));
00247 end
00248
00249 // Check if there are overlapping fields
00250 if (idx > 0) begin
00251 if (this.fields[idx-1].get_lsb_pos_in_register() +
00252 this.fields[idx-1].get_n_bits() > offset) begin
00253 `vmm_error(this.log, $psprintf("Field %s overlaps field %s in virtual register \"%s\"",
00254 this.fields[idx-1].get_name(),
00255 field.get_name(),
00256 this.get_fullname()));
00257 end
00258 end
00259 if (idx < this.fields.size()-1) begin
00260 if (offset + field.get_n_bits() >
00261 this.fields[idx+1].get_lsb_pos_in_register()) begin
00262 `vmm_error(this.log, $psprintf("Field %s overlaps field %s in virtual register \"%s\"",
00263 field.get_name(),
00264 this.fields[idx+1].get_name(),
00265
00266 this.get_fullname()));
00267 end
00268 end
00269 endfunction: register_field
00270
00271
00272 task vmm_ral_vreg::XatomicX(bit on);
00273 if (on) this.atomic.get(1);
00274 else begin
00275 // Maybe a key was put back in by a spurious call to reset()
00276 void'(this.atomic.try_get(1));
00277 this.atomic.put(1);
00278 end
00279 endtask: XatomicX
00280
00281
00282 function void vmm_ral_vreg::reset(vmm_ral::reset_e kind = vmm_ral::HARD);
00283 // Put back a key in the semaphore if it is checked out
00284 // in case a thread was killed during an operation
00285 void'(this.atomic.try_get(1));
00286 this.atomic.put(1);
00287 endfunction: reset
00288
00289
00290 function string vmm_ral_vreg::get_name();
00291 return this.name;
00292 endfunction: get_name
00293
00294
00295 function string vmm_ral_vreg::get_fullname();
00296 vmm_ral_block blk;
00297
00298 get_fullname = this.get_name();
00299
00300 // Do not include top-level name in full name
00301 blk = this.get_block();
00302 if (blk == null) return get_fullname;
00303 if (blk.get_parent() == null) return get_fullname;
00304
00305 get_fullname = {this.parent.get_fullname(), ".", get_fullname};
00306 endfunction: get_fullname
00307
00308
00309 function vmm_ral_block vmm_ral_vreg::get_block();
00310 get_block = this.parent;
00311 endfunction: get_block
00312
00313
00314 function bit vmm_ral_vreg::implement(longint unsigned n,
00315 vmm_ral_mem mem = null,
00316 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset = 0,
00317 int unsigned incr = 0);
00318
00319 vmm_mam_region mam_region;
00320
00321 if(n < 1)
00322 begin
00323 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_fullname()));
00324 return 0;
00325 end
00326
00327 if (mem == null) begin
00328 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" using a NULL vmm_ral_mem reference", this.get_fullname()));
00329 return 0;
00330 end
00331
00332 if (this.is_static) begin
00333 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically implemented", this.get_fullname()));
00334 return 0;
00335 end
00336
00337 if (mem.get_block() != this.parent) begin
00338 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" on memory \"%s\" in a different block",
00339 this.get_fullname(),
00340 mem.get_fullname()));
00341 return 0;
00342 end
00343
00344 begin
00345 int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1;
00346 if (incr == 0) incr = min_incr;
00347 if (min_incr > incr) begin
00348 `vmm_error(this.log, $psprintf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".",
00349 this.get_fullname(), incr,
00350 min_incr, mem.get_fullname()));
00351 return 0;
00352 end
00353 end
00354
00355 // Is the memory big enough for ya?
00356 if (offset + (n * incr) > mem.get_size()) begin
00357 `vmm_error(this.log, $psprintf("Given Offset for Virtual register \"%s[%0d]\" is too big for memory %s@'h%0h", this.get_fullname(), n, mem.get_fullname(), offset));
00358 return 0;
00359 end
00360
00361 mam_region = mem.mam.reserve_region(offset,n*incr*mem.get_n_bytes());
00362
00363 if (mam_region == null) begin
00364 `vmm_error(this.log, $psprintf("Could not allocate a memory region for virtual register \"%s\"", this.get_fullname()));
00365 return 0;
00366 end
00367
00368 if (this.mem != null) begin
00369 `vmm_trace(this.log, $psprintf("Virtual register \"%s\" is being moved re-implemented from %s@'h%0h to %s@'h%0h",
00370 this.get_fullname(),
00371 this.mem.get_fullname(),
00372 this.offset,
00373 mem.get_fullname(), offset));
00374 this.release_region();
00375 end
00376
00377 this.region = mam_region;
00378 this.mem = mem;
00379 this.size = n;
00380 this.offset = offset;
00381 this.incr = incr;
00382 this.mem.XvregsX.push_back(this);
00383
00384 return 1;
00385 endfunction: implement
00386
00387
00388 function vmm_mam_region vmm_ral_vreg::allocate(longint unsigned n,
00389 vmm_mam mam);
00390
00391 vmm_ral_mem mem;
00392
00393 if(n < 1)
00394 begin
00395 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_fullname()));
00396 return null;
00397 end
00398
00399 if (mam == null) begin
00400 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" using a NULL vmm_mam reference", this.get_fullname()));
00401 return null;
00402 end
00403
00404 if (this.is_static) begin
00405 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically allocated", this.get_fullname()));
00406 return null;
00407 end
00408
00409 mem = mam.get_memory();
00410 if (mem.get_block() != this.parent) begin
00411 `vmm_error(this.log, $psprintf("Attempting to allocate virtual register \"%s\" on memory \"%s\" in a different block",
00412 this.get_fullname(),
00413 mem.get_fullname()));
00414 return null;
00415 end
00416
00417 begin
00418 int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1;
00419 if (incr == 0) incr = min_incr;
00420 if (min_incr < incr) begin
00421 `vmm_error(this.log, $psprintf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".",
00422 this.get_fullname(), incr,
00423 min_incr, mem.get_fullname()));
00424 return null;
00425 end
00426 end
00427
00428 // Need memory at least of size num_vregs*sizeof(vreg) in bytes.
00429 allocate = mam.request_region(n*incr*mem.get_n_bytes());
00430 if (allocate == null) begin
00431 `vmm_error(this.log, $psprintf("Could not allocate a memory region for virtual register \"%s\"", this.get_fullname()));
00432 return null;
00433 end
00434
00435 if (this.mem != null) begin
00436 `vmm_trace(this.log, $psprintf("Virtual register \"%s\" is being moved re-allocated from %s@'h%0h to %s@'h%0h",
00437 this.get_fullname(),
00438 this.mem.get_fullname(),
00439 this.offset,
00440 mem.get_fullname(),
00441 allocate.get_start_offset()));
00442
00443 this.release_region();
00444 end
00445
00446 this.region = allocate;
00447
00448 this.mem = mam.get_memory();
00449 this.offset = allocate.get_start_offset();
00450 this.size = n;
00451 this.incr = incr;
00452
00453 this.mem.XvregsX.push_back(this);
00454 endfunction: allocate
00455
00456
00457 function vmm_mam_region vmm_ral_vreg::get_region();
00458 return this.region;
00459 endfunction: get_region
00460
00461
00462 function void vmm_ral_vreg::release_region();
00463 if (this.is_static) begin
00464 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically released", this.get_fullname()));
00465 return;
00466 end
00467
00468 if (this.mem != null) begin
00469 foreach (this.mem.XvregsX[i]) begin
00470 if (this.mem.XvregsX[i] == this) begin
00471 this.mem.XvregsX.delete(i);
00472 break;
00473 end
00474 end
00475 end
00476 if (this.region != null) begin
00477 this.region.release_region();
00478 end
00479
00480 this.region = null;
00481 this.mem = null;
00482 this.size = 0;
00483 this.offset = 0;
00484
00485 this.reset();
00486 endfunction: release_region
00487
00488
00489 function vmm_ral_mem vmm_ral_vreg::get_memory();
00490 return this.mem;
00491 endfunction: get_memory
00492
00493
00494 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_vreg::get_offset_in_memory(longint unsigned idx);
00495 if (this.mem == null) begin
00496 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_offset_in_memory() on unimplemented virtual register \"%s\"",
00497 this.get_fullname()));
00498 return 0;
00499 end
00500
00501 return this.offset + idx * this.incr;
00502 endfunction
00503
00504
00505 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_vreg::get_address_in_system(longint unsigned idx,
00506 string domain = "");
00507 if (this.mem == null) begin
00508 `vmm_error(this.log, $psprintf("Cannot get address of of unimplemented virtual register \"%s\".", this.get_fullname()));
00509 return 0;
00510 end
00511
00512 return this.mem.get_address_in_system(this.get_offset_in_memory(idx),
00513 domain);
00514 endfunction: get_address_in_system
00515
00516
00517 function int unsigned vmm_ral_vreg::get_size();
00518 if (this.size == 0) begin
00519 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_size() on unimplemented virtual register \"%s\"",
00520 this.get_fullname()));
00521 return 0;
00522 end
00523
00524 return this.size;
00525 endfunction: get_size
00526
00527
00528 function int unsigned vmm_ral_vreg::get_n_bytes();
00529 return ((this.n_bits-1) / 8) + 1;
00530 endfunction: get_n_bytes
00531
00532
00533 function int unsigned vmm_ral_vreg::get_n_memlocs();
00534 if (this.mem == null) begin
00535 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_n_memlocs() on unimplemented virtual register \"%s\"",
00536 this.get_fullname()));
00537 return 0;
00538 end
00539
00540 return (this.get_n_bytes()-1) / this.mem.get_n_bytes() + 1;
00541 endfunction: get_n_memlocs
00542
00543
00544 function int unsigned vmm_ral_vreg::get_incr();
00545 if (this.incr == 0) begin
00546 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_incr() on unimplemented virtual register \"%s\"",
00547 this.get_fullname()));
00548 return 0;
00549 end
00550
00551 return this.incr;
00552 endfunction: get_incr
00553
00554
00555 function int vmm_ral_vreg::get_n_domains();
00556 if (this.mem == null) begin
00557 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_n_domains() on unimplemented virtual register \"%s\"",
00558 this.get_fullname()));
00559 return 0;
00560 end
00561
00562 get_n_domains = this.mem.get_n_domains();
00563 endfunction: get_n_domains
00564
00565
00566 function void vmm_ral_vreg::get_domains(ref string domains[]);
00567 if (this.mem == null) begin
00568 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_domains() on unimplemented virtual register \"%s\"",
00569 this.get_fullname()));
00570 return;
00571 end
00572
00573 this.mem.get_domains(domains);
00574 endfunction: get_domains
00575
00576
00577 function vmm_ral::access_e vmm_ral_vreg::get_access(string domain = "");
00578 if (this.mem == null) begin
00579 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_rights() on unimplemented virtual register \"%s\"",
00580 this.get_fullname()));
00581 return vmm_ral::RW;
00582 end
00583
00584 get_access = this.mem.get_access(domain);
00585 endfunction: get_access
00586
00587
00588 function vmm_ral::access_e vmm_ral_vreg::get_rights(string domain = "");
00589 if (this.mem == null) begin
00590 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_rights() on unimplemented virtual register \"%s\"",
00591 this.get_fullname()));
00592 return vmm_ral::RW;
00593 end
00594
00595 get_rights = this.mem.get_rights(domain);
00596 endfunction: get_rights
00597
00598
00599 function void vmm_ral_vreg::display(string prefix = "",
00600 string domain = "");
00601 $write("%s\n", this.psdisplay(prefix, domain));
00602 endfunction: display
00603
00604
00605 function string vmm_ral_vreg::psdisplay(string prefix = "",
00606 string domain = "");
00607 $sformat(psdisplay, "%sVirtual register %s -- ", prefix,
00608 this.get_fullname());
00609 if (this.size == 0) $sformat(psdisplay, "%sunimplemented", psdisplay);
00610 else begin
00611 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr0;
00612
00613 addr0 = this.get_address_in_system(0, domain);
00614
00615 $sformat(psdisplay, "%s[%0d] in %0s['h%0h+'h%0h] @'h%h+'h%h", psdisplay,
00616 this.size, this.mem.get_fullname(), this.offset, this.incr,
00617 addr0, this.get_address_in_system(1, domain) - addr0);
00618 end
00619 foreach(this.fields[i]) begin
00620 $sformat(psdisplay, "%s\n%s", psdisplay,
00621 this.fields[i].psdisplay({prefix, " "}));
00622 end
00623 endfunction: psdisplay
00624
00625
00626 function void vmm_ral_vreg::get_fields(ref vmm_ral_vfield fields[]);
00627 fields = new [this.fields.size()];
00628 foreach(this.fields[i]) begin
00629 fields[i] = this.fields[i];
00630 end
00631 endfunction: get_fields
00632
00633
00634 function vmm_ral_vfield vmm_ral_vreg::get_field_by_name(string name);
00635 foreach (this.fields[i]) begin
00636 if (this.fields[i].get_name() == name) begin
00637 return this.fields[i];
00638 end
00639 end
00640 `vmm_warning(this.log, $psprintf("Unable to locate field \"%s\" in virtual register \"%s\".",
00641 name, this.get_fullname()));
00642 get_field_by_name = null;
00643 endfunction: get_field_by_name
00644
00645
00646 task vmm_ral_vreg::write(input longint unsigned idx,
00647 output vmm_rw::status_e status,
00648 input bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00649 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00650 input string domain = "",
00651 input int data_id = -1,
00652 input int scenario_id = -1,
00653 input int stream_id = -1);
00654
00655 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00656 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00657 bit [`VMM_RAL_DATA_WIDTH-1:0] msk;
00658 int lsb;
00659
00660 if (this.mem == null) begin
00661 `vmm_error(this.log, $psprintf("Cannot write to unimplemented virtual register \"%s\".", this.get_fullname()));
00662 status = vmm_rw::ERROR;
00663 return;
00664 end
00665
00666 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00667
00668 foreach (fields[i]) begin
00669 vmm_ral_vfield f = fields[i];
00670
00671 lsb = f.get_lsb_pos_in_register();
00672 msk = ((1<<f.get_n_bits())-1) << lsb;
00673 tmp = (value & msk) >> lsb;
00674 foreach (f.XcbsX[j]) begin
00675 vmm_ral_vfield_callbacks cb;
00676 if (!$cast(cb, f.XcbsX[j])) continue;
00677 cb.pre_write(f, idx, tmp, path, domain);
00678 end
00679 value = (value & ~msk) | (tmp << lsb);
00680 end
00681 `vmm_callback(vmm_ral_vreg_callbacks,
00682 pre_write(this, idx, value, path, domain));
00683
00684 addr = this.offset + (idx * this.incr);
00685
00686 lsb = 0;
00687 status = vmm_rw::IS_OK;
00688 for (int i = 0; i < this.get_n_memlocs(); i++) begin
00689 vmm_rw::status_e s;
00690
00691 msk = ((1<<(this.mem.get_n_bytes()*8))-1) << lsb;
00692 tmp = (value & msk) >> lsb;
00693 this.mem.write(s, addr + i, tmp,
00694 path, domain ,
00695 data_id, scenario_id, stream_id);
00696 if (s != vmm_rw::IS_OK) status = s;
00697 lsb += this.mem.get_n_bytes() * 8;
00698 end
00699
00700 foreach (fields[i]) begin
00701 vmm_ral_vfield f = fields[i];
00702
00703 lsb = f.get_lsb_pos_in_register();
00704 msk = ((1<<f.get_n_bits())-1) << lsb;
00705 tmp = (value & msk) >> lsb;
00706 foreach (f.XcbsX[j]) begin
00707 vmm_ral_vfield_callbacks cb;
00708 if (!$cast(cb, f.XcbsX[j])) continue;
00709 cb.post_write(f, idx, tmp, path, domain, status);
00710 end
00711 value = (value & ~msk) | (tmp << lsb);
00712 end
00713 `vmm_callback(vmm_ral_vreg_callbacks,
00714 post_write(this, idx, value, path, domain, status));
00715
00716 `vmm_trace(this.log, $psprintf("Wrote virtual register \"%s\"[%0d] via %s with: 'h%h",
00717 this.get_fullname(), idx,
00718 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00719 value));
00720
00721 endtask: write
00722
00723
00724 task vmm_ral_vreg::read(input longint unsigned idx,
00725 output vmm_rw::status_e status,
00726 output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00727 input vmm_ral::path_e path = vmm_ral::DEFAULT,
00728 input string domain = "",
00729 input int data_id = -1,
00730 input int scenario_id = -1,
00731 input int stream_id = -1);
00732 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00733 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00734 bit [`VMM_RAL_DATA_WIDTH-1:0] msk;
00735 int lsb;
00736
00737 if (this.mem == null) begin
00738 `vmm_error(this.log, $psprintf("Cannot read from unimplemented virtual register \"%s\".", this.get_fullname()));
00739 status = vmm_rw::ERROR;
00740 return;
00741 end
00742
00743 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00744
00745 foreach (fields[i]) begin
00746 vmm_ral_vfield f = fields[i];
00747 foreach (f.XcbsX[j]) begin
00748 vmm_ral_vfield_callbacks cb;
00749 if (!$cast(cb, f.XcbsX[j])) continue;
00750 cb.pre_read(f, idx, path, domain);
00751 end
00752 end
00753 `vmm_callback(vmm_ral_vreg_callbacks,
00754 pre_read(this, idx, path, domain));
00755
00756 addr = this.offset + (idx * this.incr);
00757
00758 lsb = 0;
00759 value = 0;
00760 status = vmm_rw::IS_OK;
00761 for (int i = 0; i < this.get_n_memlocs(); i++) begin
00762 vmm_rw::status_e s;
00763
00764 this.mem.read(s, addr + i, tmp,
00765 path, domain ,
00766 data_id, scenario_id, stream_id);
00767 if (s != vmm_rw::IS_OK) status = s;
00768
00769 value |= tmp << lsb;
00770 lsb += this.mem.get_n_bytes() * 8;
00771 end
00772
00773 foreach (fields[i]) begin
00774 vmm_ral_vfield f = fields[i];
00775
00776 lsb = f.get_lsb_pos_in_register();
00777
00778 msk = ((1<<f.get_n_bits())-1) << lsb;
00779 tmp = (value & msk) >> lsb;
00780
00781 foreach (f.XcbsX[j]) begin
00782 vmm_ral_vfield_callbacks cb;
00783 if (!$cast(cb, f.XcbsX[j])) continue;
00784 cb.post_read(f, idx, tmp, path, domain, status);
00785 end
00786
00787 value = (value & ~msk) | (tmp << lsb);
00788 end
00789 `vmm_callback(vmm_ral_vreg_callbacks,
00790 post_read(this, idx, value, path, domain, status));
00791
00792 `vmm_trace(this.log, $psprintf("Read virtual register \"%s\"[%0d] via %s: 'h%h",
00793 this.get_fullname(), idx,
00794 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00795 value));
00796 endtask: read
00797
00798
00799 task vmm_ral_vreg::poke(input longint unsigned idx,
00800 output vmm_rw::status_e status,
00801 input bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00802 input int data_id = -1,
00803 input int scenario_id = -1,
00804 input int stream_id = -1);
00805 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00806 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00807 bit [`VMM_RAL_DATA_WIDTH-1:0] msk;
00808 int lsb;
00809
00810 if (this.mem == null) begin
00811 `vmm_error(this.log, $psprintf("Cannot poke in unimplemented virtual register \"%s\".", this.get_fullname()));
00812 status = vmm_rw::ERROR;
00813 return;
00814 end
00815
00816 addr = this.offset + (idx * this.incr);
00817
00818 lsb = 0;
00819 status = vmm_rw::IS_OK;
00820 for (int i = 0; i < this.get_n_memlocs(); i++) begin
00821 vmm_rw::status_e s;
00822
00823 msk = ((1<<(this.mem.get_n_bytes() * 8))-1) << lsb;
00824 tmp = (value & msk) >> lsb;
00825
00826 this.mem.poke(status, addr + i, tmp,
00827 data_id, scenario_id, stream_id);
00828 if (s != vmm_rw::IS_OK) status = s;
00829
00830 lsb += this.mem.get_n_bytes() * 8;
00831 end
00832
00833 `vmm_trace(this.log, $psprintf("Poked virtual register \"%s\"[%0d] with: 'h%h",
00834 this.get_fullname(), idx, value));
00835
00836 endtask: poke
00837
00838
00839 task vmm_ral_vreg::peek(input longint unsigned idx,
00840 output vmm_rw::status_e status,
00841 output bit[`VMM_RAL_DATA_WIDTH-1:0] value,
00842 input int data_id = -1,
00843 input int scenario_id = -1,
00844 input int stream_id = -1);
00845 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00846 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp;
00847 bit [`VMM_RAL_DATA_WIDTH-1:0] msk;
00848 int lsb;
00849
00850 if (this.mem == null) begin
00851 `vmm_error(this.log, $psprintf("Cannot peek in from unimplemented virtual register \"%s\".", this.get_fullname()));
00852 status = vmm_rw::ERROR;
00853 return;
00854 end
00855
00856 addr = this.offset + (idx * this.incr);
00857
00858 lsb = 0;
00859 value = 0;
00860 status = vmm_rw::IS_OK;
00861 for (int i = 0; i < this.get_n_memlocs(); i++) begin
00862 vmm_rw::status_e s;
00863
00864 this.mem.peek(status, addr + i, tmp,
00865 data_id, scenario_id, stream_id);
00866 if (s != vmm_rw::IS_OK) status = s;
00867
00868 value |= tmp << lsb;
00869 lsb += this.mem.get_n_bytes() * 8;
00870 end
00871
00872 `vmm_trace(this.log, $psprintf("Peeked virtual register \"%s\"[%0d]: 'h%h",
00873 this.get_fullname(), idx, value));
00874
00875 endtask: peek
00876
00877
00878 function void vmm_ral_vreg::prepend_callback(vmm_ral_vreg_callbacks cb);
00879 foreach (this.callbacks[i]) begin
00880 if (this.callbacks[i] == cb) begin
00881 `vmm_warning(this.log, $psprintf("Callback has already been registered with virtual register \"%s\"", this.get_fullname()));
00882 return;
00883 end
00884 end
00885
00886 // Prepend new callback
00887 this.callbacks.push_front(cb);
00888 endfunction: prepend_callback
00889
00890
00891 function void vmm_ral_vreg::append_callback(vmm_ral_vreg_callbacks cb);
00892 foreach (this.callbacks[i]) begin
00893 if (this.callbacks[i] == cb) begin
00894 `vmm_warning(this.log, $psprintf("Callback has already been registered with virtual register \"%s\"", this.get_fullname()));
00895 return;
00896 end
00897 end
00898
00899 // Append new callback
00900 this.callbacks.push_back(cb);
00901 endfunction: append_callback
00902
00903
00904 function void vmm_ral_vreg::unregister_callback(vmm_ral_vreg_callbacks cb);
00905 foreach (this.callbacks[i]) begin
00906 if (this.callbacks[i] == cb) begin
00907 int j = i;
00908 // Unregister it
00909 this.callbacks.delete(j);
00910 return;
00911 end
00912 end
00913
00914 `vmm_warning(this.log, $psprintf("Callback was not registered with virtual register \"%s\"", this.get_fullname()));
00915 endfunction: unregister_callback