VMM OpenSource - sv/RAL/vmm_ral_vreg.sv

sv/RAL/vmm_ral_vreg.sv expanded source

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