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_ral_vfield; 00024 class vmm_ral_vfield_callbacks extends vmm_ral_callbacks; 00025 00026 virtual task pre_write(vmm_ral_vfield field, 00027 longint unsigned idx, 00028 ref bit [`VMM_RAL_DATA_WIDTH-1:0] wdat, 00029 ref vmm_ral::path_e path, 00030 ref string domain); 00031 endtask: pre_write 00032 00033 virtual task post_write(vmm_ral_vfield field, 00034 longint unsigned idx, 00035 bit [`VMM_RAL_DATA_WIDTH-1:0] wdat, 00036 vmm_ral::path_e path, 00037 string domain, 00038 ref vmm_rw::status_e status); 00039 endtask: post_write 00040 00041 virtual task pre_read(vmm_ral_vfield field, 00042 longint unsigned idx, 00043 ref vmm_ral::path_e path, 00044 ref string domain); 00045 endtask: pre_read 00046 00047 virtual task post_read(vmm_ral_vfield field, 00048 longint unsigned idx, 00049 ref bit [`VMM_RAL_DATA_WIDTH-1:0] rdat, 00050 vmm_ral::path_e path, 00051 string domain, 00052 ref vmm_rw::status_e status); 00053 endtask: post_read 00054 endclass: vmm_ral_vfield_callbacks 00055 00056 00057 class vmm_ral_vfield; 00058 static vmm_log log = new("RAL", "virtual field"); 00059 00060 local string name; 00061 local vmm_ral_vreg parent; 00062 local int unsigned lsb; 00063 local int unsigned size; 00064 00065 vmm_ral_vfield_callbacks XcbsX[$]; 00066 00067 extern /*local*/ function new(vmm_ral_vreg parent, 00068 string name, 00069 int unsigned size, 00070 int unsigned lsb_pos); 00071 00072 extern virtual function string get_name(); 00073 extern virtual function string get_fullname(); 00074 extern virtual function vmm_ral_vreg get_register(); 00075 extern virtual function int unsigned get_lsb_pos_in_register(); 00076 extern virtual function int unsigned get_n_bits(); 00077 00078 extern virtual function vmm_ral::access_e get_access(string domain = ""); 00079 00080 extern virtual function void display(string prefix = ""); 00081 extern virtual function string psdisplay(string prefix = ""); 00082 00083 extern virtual task write(input longint unsigned idx, 00084 output vmm_rw::status_e status, 00085 input bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00086 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00087 input string domain = "", 00088 input int data_id = -1, 00089 input int scenario_id =- 1, 00090 input int stream_id = -1); 00091 extern virtual task read(input longint unsigned idx, 00092 output vmm_rw::status_e status, 00093 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00094 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00095 input string domain = "", 00096 input int data_id = -1, 00097 input int scenario_id = -1, 00098 input int stream_id = -1); 00099 00100 extern virtual task poke(input longint unsigned idx, 00101 output vmm_rw::status_e status, 00102 input bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00103 input int data_id = -1, 00104 input int scenario_id =- 1, 00105 input int stream_id = -1); 00106 extern virtual task peek(input longint unsigned idx, 00107 output vmm_rw::status_e status, 00108 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00109 input int data_id = -1, 00110 input int scenario_id = -1, 00111 input int stream_id = -1); 00112 00113 extern function void prepend_callback(vmm_ral_vfield_callbacks cb); 00114 extern function void append_callback(vmm_ral_vfield_callbacks cb); 00115 extern function void unregister_callback(vmm_ral_vfield_callbacks cb); 00116 endclass: vmm_ral_vfield 00117 00118 00119 function vmm_ral_vfield::new(vmm_ral_vreg parent, 00120 string name, 00121 int unsigned size, 00122 int unsigned lsb_pos); 00123 this.parent = parent; 00124 this.name = name; 00125 00126 if (size == 0) begin 00127 `vmm_error(this.log, $psprintf("Virtual field \"%s\" cannot have 0 bits", this.get_fullname())); 00128 size = 1; 00129 end 00130 if (size > `VMM_RAL_DATA_WIDTH) begin 00131 `vmm_error(this.log, $psprintf("Virtual field \"%s\" cannot have more than %0d bits", 00132 this.get_fullname(), 00133 `VMM_RAL_DATA_WIDTH)); 00134 size = `VMM_RAL_DATA_WIDTH; 00135 end 00136 00137 this.size = size; 00138 this.lsb = lsb_pos; 00139 00140 this.parent.register_field(this); 00141 endfunction: new 00142 00143 00144 function string vmm_ral_vfield::get_name(); 00145 get_name = this.name; 00146 endfunction: get_name 00147 00148 00149 function string vmm_ral_vfield::get_fullname(); 00150 get_fullname = {this.parent.get_fullname(), ".", this.name}; 00151 endfunction: get_fullname 00152 00153 00154 function vmm_ral_vreg vmm_ral_vfield::get_register(); 00155 get_register = this.parent; 00156 endfunction: get_register 00157 00158 00159 function int unsigned vmm_ral_vfield::get_lsb_pos_in_register(); 00160 get_lsb_pos_in_register = this.lsb; 00161 endfunction: get_lsb_pos_in_register 00162 00163 00164 function int unsigned vmm_ral_vfield::get_n_bits(); 00165 get_n_bits = this.size; 00166 endfunction: get_n_bits 00167 00168 00169 function vmm_ral::access_e vmm_ral_vfield::get_access(string domain); 00170 if (this.parent.get_memory() == null) begin 00171 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::get_rights() on unimplemented virtual field \"%s\"", 00172 this.get_fullname())); 00173 return vmm_ral::RW; 00174 end 00175 00176 get_access = this.parent.get_access(domain); 00177 endfunction: get_access 00178 00179 00180 function void vmm_ral_vfield::display(string prefix); 00181 $write("%s\n", this.psdisplay(prefix)); 00182 endfunction: display 00183 00184 00185 function string vmm_ral_vfield::psdisplay(string prefix); 00186 $sformat(psdisplay, {"%s%s[%0d-%0d]"}, prefix, 00187 this.get_name(), 00188 this.get_lsb_pos_in_register() + this.get_n_bits() - 1, 00189 this.get_lsb_pos_in_register()); 00190 endfunction: psdisplay 00191 00192 00193 task vmm_ral_vfield::write(input longint unsigned idx, 00194 output vmm_rw::status_e status, 00195 input bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00196 input vmm_ral::path_e path, 00197 input string domain, 00198 input int data_id, 00199 input int scenario_id, 00200 input int stream_id); 00201 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00202 bit [`VMM_RAL_DATA_WIDTH-1:0] segval; 00203 bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff; 00204 vmm_rw::status_e st; 00205 00206 int flsb, fmsb, rmwbits; 00207 int segsiz, segn; 00208 vmm_ral_mem mem; 00209 vmm_ral::path_e rm_path; 00210 00211 mem = this.parent.get_memory(); 00212 if (mem == null) begin 00213 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::write() on unimplemented virtual register \"%s\"", 00214 this.get_fullname())); 00215 status = vmm_rw::ERROR; 00216 return; 00217 end 00218 00219 if (path == vmm_ral::DEFAULT) begin 00220 vmm_ral_block blk = this.parent.get_block(); 00221 path = blk.get_default_access(); 00222 end 00223 00224 status = vmm_rw::IS_OK; 00225 00226 this.parent.XatomicX(1); 00227 00228 if (value >> this.size) begin 00229 `vmm_warning(log, $psprintf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_fullname(), this.get_n_bits())); 00230 value &= value & ((1<<this.size)-1); 00231 end 00232 tmp = 0; 00233 00234 foreach (this.XcbsX[j]) begin 00235 vmm_ral_vfield_callbacks cb; 00236 if (!$cast(cb, this.XcbsX[j])) continue; 00237 cb.pre_write(this, idx, value, path, domain); 00238 end 00239 00240 segsiz = mem.get_n_bytes() * 8; 00241 flsb = this.get_lsb_pos_in_register(); 00242 segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); 00243 00244 // Favor backdoor read to frontdoor read for the RMW operation 00245 rm_path = vmm_ral::DEFAULT; 00246 if (mem.get_backdoor() != null) rm_path = vmm_ral::BACKDOOR; 00247 00248 // Any bits on the LSB side we need to RMW? 00249 rmwbits = flsb % segsiz; 00250 00251 // Total number of memory segment in this field 00252 segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1; 00253 00254 if (rmwbits > 0) begin 00255 bit [`VMM_RAL_ADDR_WIDTH-1:0] segn; 00256 00257 mem.read(st, segoff, tmp, rm_path, domain, 00258 data_id, scenario_id, stream_id); 00259 if (st != vmm_rw::IS_OK) begin 00260 `vmm_error(this.log, 00261 $psprintf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", 00262 mem.get_fullname(), segoff, this.get_fullname())); 00263 status = vmm_rw::ERROR; 00264 this.parent.XatomicX(0); 00265 return; 00266 end 00267 00268 value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1)); 00269 end 00270 00271 // Any bits on the MSB side we need to RMW? 00272 fmsb = rmwbits + this.get_n_bits() - 1; 00273 rmwbits = (fmsb+1) % segsiz; 00274 if (rmwbits > 0) begin 00275 if (segn > 0) begin 00276 mem.read(st, segoff + segn - 1, tmp, rm_path, domain, 00277 data_id, scenario_id, stream_id); 00278 if (st != vmm_rw::IS_OK) begin 00279 `vmm_error(this.log, 00280 $psprintf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", 00281 mem.get_fullname(), segoff+segn-1, 00282 this.get_fullname())); 00283 status = vmm_rw::ERROR; 00284 this.parent.XatomicX(0); 00285 return; 00286 end 00287 end 00288 value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz); 00289 end 00290 00291 // Now write each of the segments 00292 tmp = value; 00293 repeat (segn) begin 00294 mem.write(st, segoff, tmp, path, domain, 00295 data_id, scenario_id, stream_id); 00296 if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR; 00297 00298 segoff++; 00299 tmp = tmp >> segsiz; 00300 end 00301 00302 foreach (this.XcbsX[j]) begin 00303 vmm_ral_vfield_callbacks cb; 00304 if (!$cast(cb, this.XcbsX[j])) continue; 00305 cb.post_write(this, idx, value, path, domain, status); 00306 end 00307 00308 this.parent.XatomicX(0); 00309 00310 `vmm_trace(this.log, $psprintf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h", 00311 this.get_fullname(), idx, 00312 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 00313 value)); 00314 00315 endtask: write 00316 00317 00318 task vmm_ral_vfield::read(input longint unsigned idx, 00319 output vmm_rw::status_e status, 00320 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00321 input vmm_ral::path_e path, 00322 input string domain, 00323 input int data_id, 00324 input int scenario_id, 00325 input int stream_id); 00326 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00327 bit [`VMM_RAL_DATA_WIDTH-1:0] segval; 00328 bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff; 00329 vmm_rw::status_e st; 00330 00331 int flsb, lsb; 00332 int segsiz, segn; 00333 vmm_ral_mem mem; 00334 00335 mem = this.parent.get_memory(); 00336 if (mem == null) begin 00337 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::read() on unimplemented virtual register \"%s\"", 00338 this.get_fullname())); 00339 status = vmm_rw::ERROR; 00340 return; 00341 end 00342 00343 if (path == vmm_ral::DEFAULT) begin 00344 vmm_ral_block blk = this.parent.get_block(); 00345 path = blk.get_default_access(); 00346 end 00347 00348 status = vmm_rw::IS_OK; 00349 00350 this.parent.XatomicX(1); 00351 00352 value = 0; 00353 00354 foreach (this.XcbsX[j]) begin 00355 vmm_ral_vfield_callbacks cb; 00356 if (!$cast(cb, this.XcbsX[j])) continue; 00357 cb.pre_read(this, idx, path, domain); 00358 end 00359 00360 segsiz = mem.get_n_bytes() * 8; 00361 flsb = this.get_lsb_pos_in_register(); 00362 segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); 00363 lsb = flsb % segsiz; 00364 00365 // Total number of memory segment in this field 00366 segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; 00367 00368 // Read each of the segments, MSB first 00369 segoff += segn - 1; 00370 repeat (segn) begin 00371 value = value << segsiz; 00372 00373 mem.read(st, segoff, tmp, path, domain, 00374 data_id, scenario_id, stream_id); 00375 if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR; 00376 00377 segoff--; 00378 value |= tmp; 00379 end 00380 00381 // Any bits on the LSB side we need to get rid of? 00382 value = value >> lsb; 00383 00384 // Any bits on the MSB side we need to get rid of? 00385 value &= (1<<this.get_n_bits()) - 1; 00386 00387 foreach (this.XcbsX[j]) begin 00388 vmm_ral_vfield_callbacks cb; 00389 if (!$cast(cb, this.XcbsX[j])) continue; 00390 cb.post_read(this, idx, value, path, domain, status); 00391 end 00392 00393 this.parent.XatomicX(0); 00394 00395 `vmm_trace(this.log, $psprintf("Read virtual field \"%s\"[%0d] via %s: 'h%h", 00396 this.get_fullname(), idx, 00397 (path == vmm_ral::BFM) ? "frontdoor" : "backdoor", 00398 value)); 00399 00400 endtask: read 00401 00402 00403 task vmm_ral_vfield::poke(input longint unsigned idx, 00404 output vmm_rw::status_e status, 00405 input bit [`VMM_RAL_DATA_WIDTH-1:0] value, 00406 input int data_id, 00407 input int scenario_id, 00408 input int stream_id); 00409 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00410 bit [`VMM_RAL_DATA_WIDTH-1:0] segval; 00411 bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff; 00412 vmm_rw::status_e st; 00413 00414 int flsb, fmsb, rmwbits; 00415 int segsiz, segn; 00416 vmm_ral_mem mem; 00417 vmm_ral::path_e rm_path; 00418 00419 mem = this.parent.get_memory(); 00420 if (mem == null) begin 00421 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::poke() on unimplemented virtual register \"%s\"", 00422 this.get_fullname())); 00423 status = vmm_rw::ERROR; 00424 return; 00425 end 00426 00427 status = vmm_rw::IS_OK; 00428 00429 this.parent.XatomicX(1); 00430 00431 if (value >> this.size) begin 00432 `vmm_warning(log, $psprintf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_fullname(), this.get_n_bits())); 00433 value &= value & ((1<<this.size)-1); 00434 end 00435 tmp = 0; 00436 00437 segsiz = mem.get_n_bytes() * 8; 00438 flsb = this.get_lsb_pos_in_register(); 00439 segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); 00440 00441 // Any bits on the LSB side we need to RMW? 00442 rmwbits = flsb % segsiz; 00443 00444 // Total number of memory segment in this field 00445 segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1; 00446 00447 if (rmwbits > 0) begin 00448 bit [`VMM_RAL_ADDR_WIDTH-1:0] segn; 00449 00450 mem.peek(st, segoff, tmp, 00451 data_id, scenario_id, stream_id); 00452 if (st != vmm_rw::IS_OK) begin 00453 `vmm_error(this.log, 00454 $psprintf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", 00455 mem.get_fullname(), segoff, this.get_fullname())); 00456 status = vmm_rw::ERROR; 00457 this.parent.XatomicX(0); 00458 return; 00459 end 00460 00461 value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1)); 00462 end 00463 00464 // Any bits on the MSB side we need to RMW? 00465 fmsb = rmwbits + this.get_n_bits() - 1; 00466 rmwbits = (fmsb+1) % segsiz; 00467 if (rmwbits > 0) begin 00468 if (segn > 0) begin 00469 mem.peek(st, segoff + segn - 1, tmp, 00470 data_id, scenario_id, stream_id); 00471 if (st != vmm_rw::IS_OK) begin 00472 `vmm_error(this.log, 00473 $psprintf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", 00474 mem.get_fullname(), segoff+segn-1, 00475 this.get_fullname())); 00476 status = vmm_rw::ERROR; 00477 this.parent.XatomicX(0); 00478 return; 00479 end 00480 end 00481 value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz); 00482 end 00483 00484 // Now write each of the segments 00485 tmp = value; 00486 repeat (segn) begin 00487 mem.poke(st, segoff, tmp, 00488 data_id, scenario_id, stream_id); 00489 if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR; 00490 00491 segoff++; 00492 tmp = tmp >> segsiz; 00493 end 00494 00495 this.parent.XatomicX(0); 00496 00497 `vmm_trace(this.log, $psprintf("Wrote virtual field \"%s\"[%0d] with: 'h%h", 00498 this.get_fullname(), idx, value)); 00499 00500 endtask: poke 00501 00502 00503 task vmm_ral_vfield::peek(input longint unsigned idx, 00504 output vmm_rw::status_e status, 00505 output bit[`VMM_RAL_DATA_WIDTH-1:0] value, 00506 input int data_id, 00507 input int scenario_id, 00508 input int stream_id); 00509 bit [`VMM_RAL_DATA_WIDTH-1:0] tmp; 00510 bit [`VMM_RAL_DATA_WIDTH-1:0] segval; 00511 bit [`VMM_RAL_ADDR_WIDTH-1:0] segoff; 00512 vmm_rw::status_e st; 00513 00514 int flsb, lsb; 00515 int segsiz, segn; 00516 vmm_ral_mem mem; 00517 00518 mem = this.parent.get_memory(); 00519 if (mem == null) begin 00520 `vmm_error(this.log, $psprintf("Cannot call vmm_ral_vfield::peek() on unimplemented virtual register \"%s\"", 00521 this.get_fullname())); 00522 status = vmm_rw::ERROR; 00523 return; 00524 end 00525 00526 status = vmm_rw::IS_OK; 00527 00528 this.parent.XatomicX(1); 00529 00530 value = 0; 00531 00532 segsiz = mem.get_n_bytes() * 8; 00533 flsb = this.get_lsb_pos_in_register(); 00534 segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); 00535 lsb = flsb % segsiz; 00536 00537 // Total number of memory segment in this field 00538 segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; 00539 00540 // Read each of the segments, MSB first 00541 segoff += segn - 1; 00542 repeat (segn) begin 00543 value = value << segsiz; 00544 00545 mem.peek(st, segoff, tmp, 00546 data_id, scenario_id, stream_id); 00547 if (st != vmm_rw::IS_OK) status = vmm_rw::ERROR; 00548 00549 segoff--; 00550 value |= tmp; 00551 end 00552 00553 // Any bits on the LSB side we need to get rid of? 00554 value = value >> lsb; 00555 00556 // Any bits on the MSB side we need to get rid of? 00557 value &= (1<<this.get_n_bits()) - 1; 00558 00559 this.parent.XatomicX(0); 00560 00561 `vmm_trace(this.log, $psprintf("Peeked virtual field \"%s\"[%0d]: 'h%h", 00562 this.get_fullname(), idx, value)); 00563 00564 endtask: peek 00565 00566 00567 function void vmm_ral_vfield::prepend_callback(vmm_ral_vfield_callbacks cb); 00568 foreach (this.XcbsX[i]) begin 00569 if (this.XcbsX[i] == cb) begin 00570 `vmm_warning(this.log, $psprintf("Callback has already been registered with field \"%s\"", this.get_fullname())); 00571 return; 00572 end 00573 end 00574 00575 // Prepend new callback 00576 this.XcbsX.push_front(cb); 00577 endfunction: prepend_callback 00578 00579 00580 function void vmm_ral_vfield::append_callback(vmm_ral_vfield_callbacks cb); 00581 foreach (this.XcbsX[i]) begin 00582 if (this.XcbsX[i] == cb) begin 00583 `vmm_warning(this.log, $psprintf("Callback has already been registered with field \"%s\"", this.get_fullname())); 00584 return; 00585 end 00586 end 00587 00588 // Append new callback 00589 this.XcbsX.push_back(cb); 00590 endfunction: append_callback 00591 00592 00593 function void vmm_ral_vfield::unregister_callback(vmm_ral_vfield_callbacks cb); 00594 foreach (this.XcbsX[i]) begin 00595 if (this.XcbsX[i] == cb) begin 00596 int j = i; 00597 // Unregister it 00598 this.XcbsX.delete(j); 00599 return; 00600 end 00601 end 00602 00603 `vmm_warning(this.log, $psprintf("Callback was not registered with field \"%s\"", this.get_fullname())); 00604 endfunction: unregister_callback