VMM - RAL/vmm_ral_vreg.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,
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