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 = vmm_ral::DEFAULT,
00197 input string domain = "",
00198 input int data_id = -1,
00199 input int scenario_id = -1,
00200 input int stream_id = -1);
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 = vmm_ral::DEFAULT,
00322 input string domain = "",
00323 input int data_id = -1,
00324 input int scenario_id = -1,
00325 input int stream_id = -1);
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 = -1,
00407 input int scenario_id = -1,
00408 input int stream_id = -1);
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 = -1,
00507 input int scenario_id = -1,
00508 input int stream_id = -1);
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