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, 00173 vmm_ral_mem mem, 00174 longint unsigned size, 00175 int unsigned incr); 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 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 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); 00283 // Put back a key in the semaphore if it is checked out 00284 // in case a thread was killed during an operation 00285 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, 00316 bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00317 int unsigned incr); 00318 if (mem == null) begin 00319 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" using a NULL vmm_ral_mem reference", this.get_fullname())); 00320 return 0; 00321 end 00322 00323 if (this.is_static) begin 00324 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically implemented", this.get_fullname())); 00325 return 0; 00326 end 00327 00328 if (mem.get_block() != this.parent) begin 00329 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" on memory \"%s\" in a different block", 00330 this.get_fullname(), 00331 mem.get_fullname())); 00332 return 0; 00333 end 00334 00335 begin 00336 int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; 00337 if (incr == 0) incr = min_incr; 00338 if (min_incr > incr) begin 00339 `vmm_error(this.log, $psprintf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", 00340 this.get_fullname(), incr, 00341 min_incr, mem.get_fullname())); 00342 return 0; 00343 end 00344 end 00345 00346 // Is the memory big enough for ya? 00347 if (offset + (n * incr) > mem.get_size()) begin 00348 `vmm_error(this.log, $psprintf("Virtual register \"%s[%0d]\" is too big for memory %s@'h%0h", this.get_fullname(), n, mem.get_fullname(), offset)); 00349 return 0; 00350 end 00351 00352 if (this.mem != null) begin 00353 `vmm_trace(this.log, $psprintf("Virtual register \"%s\" is being moved re-implemented from %s@'h%0h to %s@'h%0h", 00354 this.get_fullname(), 00355 this.mem.get_fullname(), 00356 this.offset, 00357 mem.get_fullname(), offset)); 00358 this.release_region(); 00359 end 00360 00361 this.mem = mem; 00362 this.size = n; 00363 this.offset = offset; 00364 this.incr = incr; 00365 this.mem.XvregsX.push_back(this); 00366 00367 return 1; 00368 endfunction: implement 00369 00370 00371 function vmm_mam_region vmm_ral_vreg::allocate(longint unsigned n, 00372 vmm_mam mam); 00373 00374 vmm_ral_mem mem; 00375 00376 if (mam == null) begin 00377 `vmm_error(this.log, $psprintf("Attempting to implement virtual register \"%s\" using a NULL vmm_mam reference", this.get_fullname())); 00378 return null; 00379 end 00380 00381 if (this.is_static) begin 00382 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically allocated", this.get_fullname())); 00383 return null; 00384 end 00385 00386 mem = mam.get_memory(); 00387 if (mem.get_block() != this.parent) begin 00388 `vmm_error(this.log, $psprintf("Attempting to allocate virtual register \"%s\" on memory \"%s\" in a different block", 00389 this.get_fullname(), 00390 mem.get_fullname())); 00391 return null; 00392 end 00393 00394 begin 00395 int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; 00396 if (incr == 0) incr = min_incr; 00397 if (min_incr < incr) begin 00398 `vmm_error(this.log, $psprintf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", 00399 this.get_fullname(), incr, 00400 min_incr, mem.get_fullname())); 00401 return null; 00402 end 00403 end 00404 00405 // Need memory at least of size num_vregs*sizeof(vreg) in bytes. 00406 allocate = mam.request_region(n*incr*mem.get_n_bytes()); 00407 if (allocate == null) begin 00408 `vmm_error(this.log, $psprintf("Could not allocate a memory region for virtual register \"%s\"", this.get_fullname())); 00409 return null; 00410 end 00411 00412 if (this.mem != null) begin 00413 `vmm_trace(this.log, $psprintf("Virtual register \"%s\" is being moved re-allocated from %s@'h%0h to %s@'h%0h", 00414 this.get_fullname(), 00415 this.mem.get_fullname(), 00416 this.offset, 00417 mem.get_fullname(), 00418 allocate.get_start_offset())); 00419 00420 this.release_region(); 00421 end 00422 00423 this.region = allocate; 00424 00425 this.mem = mam.get_memory(); 00426 this.offset = allocate.get_start_offset(); 00427 this.size = n; 00428 this.incr = incr; 00429 00430 this.mem.XvregsX.push_back(this); 00431 endfunction: allocate 00432 00433 00434 function vmm_mam_region vmm_ral_vreg::get_region(); 00435 return this.region; 00436 endfunction: get_region 00437 00438 00439 function void vmm_ral_vreg::release_region(); 00440 if (this.is_static) begin 00441 `vmm_error(this.log, $psprintf("Virtual register \"%s\" is static and cannot be dynamically released", this.get_fullname())); 00442 return; 00443 end 00444 00445 if (this.mem != null) begin 00446 foreach (this.mem.XvregsX[i]) begin 00447 if (this.mem.XvregsX[i] == this) begin 00448 this.mem.XvregsX.delete(i); 00449 break; 00450 end 00451 end 00452 end 00453 if (this.region != null) begin 00454 this.region.release_region(); 00455 end 00456 00457 this.region = null; 00458 this.mem = null; 00459 this.size = 0; 00460 this.offset = 0; 00461 00462 this.reset(); 00463 endfunction: release_region 00464 00465 00466 function vmm_ral_mem vmm_ral_vreg::get_memory(); 00467 return this.mem; 00468 endfunction: get_memory 00469 00470 00471 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_vreg::get_offset_in_memory(longint unsigned idx); 00472 if (this.mem == null) begin 00473 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_offset_in_memory() on unimplemented virtual register \"%s\"", 00474 this.get_fullname())); 00475 return 0; 00476 end 00477 00478 return this.offset + idx * this.incr; 00479 endfunction 00480 00481 00482 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_vreg::get_address_in_system(longint unsigned idx, 00483 string domain); 00484 if (this.mem == null) begin 00485 `vmm_error(this.log, $psprintf("Cannot get address of of unimplemented virtual register \"%s\".", this.get_fullname())); 00486 return 0; 00487 end 00488 00489 return this.mem.get_address_in_system(this.get_offset_in_memory(idx), 00490 domain); 00491 endfunction: get_address_in_system 00492 00493 00494 function int unsigned vmm_ral_vreg::get_size(); 00495 if (this.size == 0) begin 00496 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_size() on unimplemented virtual register \"%s\"", 00497 this.get_fullname())); 00498 return 0; 00499 end 00500 00501 return this.size; 00502 endfunction: get_size 00503 00504 00505 function int unsigned vmm_ral_vreg::get_n_bytes(); 00506 return ((this.n_bits-1) / 8) + 1; 00507 endfunction: get_n_bytes 00508 00509 00510 function int unsigned vmm_ral_vreg::get_n_memlocs(); 00511 if (this.mem == null) begin 00512 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_n_memlocs() on unimplemented virtual register \"%s\"", 00513 this.get_fullname())); 00514 return 0; 00515 end 00516 00517 return (this.get_n_bytes()-1) / this.mem.get_n_bytes() + 1; 00518 endfunction: get_n_memlocs 00519 00520 00521 function int unsigned vmm_ral_vreg::get_incr(); 00522 if (this.incr == 0) begin 00523 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_incr() on unimplemented virtual register \"%s\"", 00524 this.get_fullname())); 00525 return 0; 00526 end 00527 00528 return this.incr; 00529 endfunction: get_incr 00530 00531 00532 function int vmm_ral_vreg::get_n_domains(); 00533 if (this.mem == null) begin 00534 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_n_domains() on unimplemented virtual register \"%s\"", 00535 this.get_fullname())); 00536 return 0; 00537 end 00538 00539 get_n_domains = this.mem.get_n_domains(); 00540 endfunction: get_n_domains 00541 00542 00543 function void vmm_ral_vreg::get_domains(ref string domains[]); 00544 if (this.mem == null) begin 00545 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_domains() on unimplemented virtual register \"%s\"", 00546 this.get_fullname())); 00547 return; 00548 end 00549 00550 this.mem.get_domains(domains); 00551 endfunction: get_domains 00552 00553 00554 function vmm_ral::access_e vmm_ral_vreg::get_access(string domain); 00555 if (this.mem == null) begin 00556 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_rights() on unimplemented virtual register \"%s\"", 00557 this.get_fullname())); 00558 return vmm_ral::RW; 00559 end 00560 00561 get_access = this.mem.get_access(domain); 00562 endfunction: get_access 00563 00564 00565 function vmm_ral::access_e vmm_ral_vreg::get_rights(string domain); 00566 if (this.mem == null) begin 00567 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vreg::get_rights() on unimplemented virtual register \"%s\"", 00568 this.get_fullname())); 00569 return vmm_ral::RW; 00570 end 00571 00572 get_rights = this.mem.get_rights(domain); 00573 endfunction: get_rights 00574 00575 00576 function void vmm_ral_vreg::display(string prefix, 00577 string domain); 00578 $write("%s\n", this.psdisplay(prefix, domain)); 00579 endfunction: display 00580 00581 00582 function string vmm_ral_vreg::psdisplay(string prefix, 00583 string domain); 00584 $sformat(psdisplay, "%sVirtual register %s -- ", prefix, 00585 this.get_fullname()); 00586 if (this.size == 0) $sformat(psdisplay, "%sunimplemented", psdisplay); 00587 else begin 00588 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr0; 00589 00590 addr0 = this.get_address_in_system(0, domain); 00591 00592 $sformat(psdisplay, "%s[%0d] in %0s['h%0h+'h%0h] @'h%h+'h%h", psdisplay, 00593 this.size, this.mem.get_fullname(), this.offset, this.incr, 00594 addr0, this.get_address_in_system(1, domain) - addr0); 00595 end 00596 foreach(this.fields[i]) begin 00597 $sformat(psdisplay, "%s\n%s", psdisplay, 00598 this.fields[i].psdisplay({prefix, " "})); 00599 end 00600 endfunction: psdisplay 00601 00602 00603 function void vmm_ral_vreg::get_fields(ref vmm_ral_vfield fields[]); 00604 fields = new [this.fields.size()]; 00605 foreach(this.fields[i]) begin 00606 fields[i] = this.fields[i]; 00607 end 00608 endfunction: get_fields 00609 00610 00611 function vmm_ral_vfield vmm_ral_vreg::get_field_by_name(string name); 00612 foreach (this.fields[i]) begin 00613 if (this.fields[i].get_name() == name) begin 00614 return this.fields[i]; 00615 end 00616 end 00617 `vmm_warning(this.log, $psprintf("Unable to locate field \"%s\" in virtual register \"%s\".", 00618 name, this.get_fullname())); 00619 get_field_by_name = null; 00620 endfunction: get_field_by_name 00621 00622 00623 task vmm_ral_vreg::write(input longint unsigned idx, 00624 output vmm_rw::status_e status, 00625 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00626 input vmm_ral::path_e path, 00627 input string domain, 00628 input int data_id, 00629 input int scenario_id, 00630 input int stream_id); 00631 00632 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr; 00633 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00634 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00635 int lsb; 00636 00637 if (this.mem == null) begin 00638 `vmm_error(this.log, $psprintf("Cannot write to unimplemented virtual register \"%s\".", this.get_fullname())); 00639 status = vmm_rw::ERROR; 00640 return; 00641 end 00642 00643 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00644 00645 foreach (fields[i]) begin 00646 vmm_ral_vfield f = fields[i]; 00647 00648 lsb = f.get_lsb_pos_in_register(); 00649 msk = ((1<<f.get_n_bits())-1) << lsb; 00650 tmp = (value & msk) >> lsb; 00651 foreach (f.XcbsX[j]) begin 00652 vmm_ral_vfield_callbacks cb; 00653 if (!$cast(cb, f.XcbsX[j])) continue; 00654 cb.pre_write(f, idx, tmp, path, domain); 00655 end 00656 value = (value & ~msk) | (tmp << lsb); 00657 end 00658 `vmm_callback(vmm_ral_vreg_callbacks, 00659 pre_write(this, idx, value, path, domain)); 00660 00661 addr = this.offset + (idx * this.incr); 00662 00663 lsb = 0; 00664 status = vmm_rw::IS_OK; 00665 for (int i = 0; i < this.get_n_memlocs(); i++) begin 00666 vmm_rw::status_e s; 00667 00668 msk = ((1<<(this.mem.get_n_bytes()*8))-1) << lsb; 00669 tmp = (value & msk) >> lsb; 00670 this.mem.write(s, addr + i, tmp, 00671 path, domain , 00672 data_id, scenario_id, stream_id); 00673 if (s != vmm_rw::IS_OK) status = s; 00674 lsb += this.mem.get_n_bytes() * 8; 00675 end 00676 00677 foreach (fields[i]) begin 00678 vmm_ral_vfield f = fields[i]; 00679 00680 lsb = f.get_lsb_pos_in_register(); 00681 msk = ((1<<f.get_n_bits())-1) << lsb; 00682 tmp = (value & msk) >> lsb; 00683 foreach (f.XcbsX[j]) begin 00684 vmm_ral_vfield_callbacks cb; 00685 if (!$cast(cb, f.XcbsX[j])) continue; 00686 cb.post_write(f, idx, tmp, path, domain, status); 00687 end 00688 value = (value & ~msk) | (tmp << lsb); 00689 end 00690 `vmm_callback(vmm_ral_vreg_callbacks, 00691 post_write(this, idx, value, path, domain, status)); 00692 00693 `vmm_trace(this.log, $psprintf("Wrote virtual register \"%s\"[%0d] via %s with: 'h%h", 00694 this.get_fullname(), idx, 00695 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 00696 value)); 00697 00698 endtask: write 00699 00700 00701 task vmm_ral_vreg::read(input longint unsigned idx, 00702 output vmm_rw::status_e status, 00703 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00704 input vmm_ral::path_e path, 00705 input string domain, 00706 input int data_id, 00707 input int scenario_id, 00708 input int stream_id); 00709 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr; 00710 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00711 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00712 int lsb; 00713 00714 if (this.mem == null) begin 00715 `vmm_error(this.log, $psprintf("Cannot read from unimplemented virtual register \"%s\".", this.get_fullname())); 00716 status = vmm_rw::ERROR; 00717 return; 00718 end 00719 00720 if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access(); 00721 00722 foreach (fields[i]) begin 00723 vmm_ral_vfield f = fields[i]; 00724 foreach (f.XcbsX[j]) begin 00725 vmm_ral_vfield_callbacks cb; 00726 if (!$cast(cb, f.XcbsX[j])) continue; 00727 cb.pre_read(f, idx, path, domain); 00728 end 00729 end 00730 `vmm_callback(vmm_ral_vreg_callbacks, 00731 pre_read(this, idx, path, domain)); 00732 00733 addr = this.offset + (idx * this.incr); 00734 00735 lsb = 0; 00736 value = 0; 00737 status = vmm_rw::IS_OK; 00738 for (int i = 0; i < this.get_n_memlocs(); i++) begin 00739 vmm_rw::status_e s; 00740 00741 this.mem.read(s, addr + i, tmp, 00742 path, domain , 00743 data_id, scenario_id, stream_id); 00744 if (s != vmm_rw::IS_OK) status = s; 00745 00746 value |= tmp << lsb; 00747 lsb += this.mem.get_n_bytes() * 8; 00748 end 00749 00750 foreach (fields[i]) begin 00751 vmm_ral_vfield f = fields[i]; 00752 00753 lsb = f.get_lsb_pos_in_register(); 00754 00755 msk = ((1<<f.get_n_bits())-1) << lsb; 00756 tmp = (value & msk) >> lsb; 00757 00758 foreach (f.XcbsX[j]) begin 00759 vmm_ral_vfield_callbacks cb; 00760 if (!$cast(cb, f.XcbsX[j])) continue; 00761 cb.post_read(f, idx, tmp, path, domain, status); 00762 end 00763 00764 value = (value & ~msk) | (tmp << lsb); 00765 end 00766 `vmm_callback(vmm_ral_vreg_callbacks, 00767 post_read(this, idx, value, path, domain, status)); 00768 00769 `vmm_trace(this.log, $psprintf("Read virtual register \"%s\"[%0d] via %s: 'h%h", 00770 this.get_fullname(), idx, 00771 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 00772 value)); 00773 endtask: read 00774 00775 00776 task vmm_ral_vreg::poke(input longint unsigned idx, 00777 output vmm_rw::status_e status, 00778 input bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00779 input int data_id, 00780 input int scenario_id, 00781 input int stream_id); 00782 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr; 00783 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00784 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00785 int lsb; 00786 00787 if (this.mem == null) begin 00788 `vmm_error(this.log, $psprintf("Cannot poke in unimplemented virtual register \"%s\".", this.get_fullname())); 00789 status = vmm_rw::ERROR; 00790 return; 00791 end 00792 00793 addr = this.offset + (idx * this.incr); 00794 00795 lsb = 0; 00796 status = vmm_rw::IS_OK; 00797 for (int i = 0; i < this.get_n_memlocs(); i++) begin 00798 vmm_rw::status_e s; 00799 00800 msk = ((1<<(this.mem.get_n_bytes() * 8))-1) << lsb; 00801 tmp = (value & msk) >> lsb; 00802 00803 this.mem.poke(status, addr + i, tmp, 00804 data_id, scenario_id, stream_id); 00805 if (s != vmm_rw::IS_OK) status = s; 00806 00807 lsb += this.mem.get_n_bytes() * 8; 00808 end 00809 00810 `vmm_trace(this.log, $psprintf("Poked virtual register \"%s\"[%0d] with: 'h%h", 00811 this.get_fullname(), idx, value)); 00812 00813 endtask: poke 00814 00815 00816 task vmm_ral_vreg::peek(input longint unsigned idx, 00817 output vmm_rw::status_e status, 00818 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00819 input int data_id, 00820 input int scenario_id, 00821 input int stream_id); 00822 bit [`VMM_RAL_ADDR_WIDTH-1:0] addr; 00823 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00824 bit [`VMM_RAL_DATA_WIDTH-1:0] msk; 00825 int lsb; 00826 00827 if (this.mem == null) begin 00828 `vmm_error(this.log, $psprintf("Cannot peek in from unimplemented virtual register \"%s\".", this.get_fullname())); 00829 status = vmm_rw::ERROR; 00830 return; 00831 end 00832 00833 addr = this.offset + (idx * this.incr); 00834 00835 lsb = 0; 00836 value = 0; 00837 status = vmm_rw::IS_OK; 00838 for (int i = 0; i < this.get_n_memlocs(); i++) begin 00839 vmm_rw::status_e s; 00840 00841 this.mem.peek(status, addr + i, tmp, 00842 data_id, scenario_id, stream_id); 00843 if (s != vmm_rw::IS_OK) status = s; 00844 00845 value |= tmp << lsb; 00846 lsb += this.mem.get_n_bytes() * 8; 00847 end 00848 00849 `vmm_trace(this.log, $psprintf("Peeked virtual register \"%s\"[%0d]: 'h%h", 00850 this.get_fullname(), idx, value)); 00851 00852 endtask: peek 00853 00854 00855 function void vmm_ral_vreg::prepend_callback(vmm_ral_vreg_callbacks cb); 00856 foreach (this.callbacks[i]) begin 00857 if (this.callbacks[i] == cb) begin 00858 `vmm_warning(this.log, $psprintf("Callback has already been registered with virtual register \"%s\"", this.get_fullname())); 00859 return; 00860 end 00861 end 00862 00863 // Prepend new callback 00864 this.callbacks.push_front(cb); 00865 endfunction: prepend_callback 00866 00867 00868 function void vmm_ral_vreg::append_callback(vmm_ral_vreg_callbacks cb); 00869 foreach (this.callbacks[i]) begin 00870 if (this.callbacks[i] == cb) begin 00871 `vmm_warning(this.log, $psprintf("Callback has already been registered with virtual register \"%s\"", this.get_fullname())); 00872 return; 00873 end 00874 end 00875 00876 // Append new callback 00877 this.callbacks.push_back(cb); 00878 endfunction: append_callback 00879 00880 00881 function void vmm_ral_vreg::unregister_callback(vmm_ral_vreg_callbacks cb); 00882 foreach (this.callbacks[i]) begin 00883 if (this.callbacks[i] == cb) begin 00884 int j = i; 00885 // Unregister it 00886 this.callbacks.delete(j); 00887 return; 00888 end 00889 end 00890 00891 `vmm_warning(this.log, $psprintf("Callback was not registered with virtual register \"%s\"", this.get_fullname())); 00892 endfunction: unregister_callback