VMM - RAL/vmm_ral_mem.sv

RAL/vmm_ral_mem.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 function vmm_ral_mem::new(vmm_ral_block                 parent,
00024                           string                        name,
00025                           vmm_ral::access_e             access,
00026                           longint unsigned              size,
00027                           int unsigned                  n_bits,
00028                           bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00029                           string                        domain,
00030                           bit                           cover_on,
00031                           bit [1:0]                     rights,
00032                           bit                           unmapped);
00033 
00034    this.name = name;
00035    this.locked = 0;
00036 
00037    if (n_bits == 0) begin
00038       `vmm_error(this.log, $psprintf("Memory \"%s\" cannot have 0 bits", this.get_fullname()));
00039       n_bits = 1;
00040    end
00041    if (n_bits > `VMM_RAL_DATA_WIDTH) begin
00042       `vmm_error(this.log, $psprintf("Memory \"%s\" cannot have more than %0d bits (%0d)", this.get_fullname(), `VMM_RAL_DATA_WIDTH, n_bits));
00043       n_bits = `VMM_RAL_DATA_WIDTH;
00044    end
00045    if (access != vmm_ral::RW && access != vmm_ral::RO) begin
00046       `vmm_error(this.log, $psprintf("Memory %s can only be RW or RO",
00047                                      this.get_fullname()));
00048       access = vmm_ral::RW;
00049    end
00050 
00051    this.parent   = parent;
00052    this.size     = size;
00053    this.access   = access;
00054    this.n_bits   = n_bits;
00055    this.backdoor  = null;
00056 
00057    this.parent.register_mem(this);
00058    this.add_domain(base_addr, domain, rights, unmapped);
00059 
00060    this.cover_on = cover_on;
00061    this.no_cover = !cover_on;
00062 
00063    begin
00064       vmm_mam_cfg cfg = new;
00065 
00066       cfg.n_bytes      = ((n_bits-1) / 8) + 1;
00067       cfg.start_offset = 0;
00068       cfg.end_offset   = size-1;
00069 
00070       cfg.mode     = vmm_mam::GREEDY;
00071       cfg.locality = vmm_mam::BROAD;
00072 
00073       this.mam = new(this.get_fullname(), cfg, this);
00074    end
00075 
00076    // Initialize Memory ID
00077    this.__vmm_mem_id = ++this.__vmm_mem_id_factory;
00078    __vmm_all_mems[this.__vmm_mem_id] = this;
00079 endfunction: new
00080 
00081 
00082 function void vmm_ral_mem::Xlock_modelX();
00083    this.locked = 1;
00084 endfunction: Xlock_modelX
00085 
00086 
00087 function void vmm_ral_mem::add_domain(bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00088                                       string                        domain,
00089                                       bit [1:0]                     rights,
00090                                       bit                           unmapped);
00091    vmm_ral::access_e acc;
00092 
00093    // Verify that this is a valid domain in the block
00094    string domains[];
00095 
00096    if (this.locked) begin
00097       `vmm_error(this.log, $psprintf("Cannot add domain to locked memory %s", this.get_fullname()));
00098       return;
00099    end
00100 
00101    case (rights)
00102      2'b11: acc = vmm_ral::RW;
00103      2'b10: acc = vmm_ral::RO;
00104      2'b01: acc = vmm_ral::WO;
00105      default:
00106        `vmm_error(this.log,
00107                   $psprintf("Memory %s has no access rights in domain \"%s\"",
00108                             this.get_fullname(), domain));
00109    endcase
00110 
00111    this.parent.get_domains(domains);
00112    foreach(domains[i]) begin
00113       if (domains[i] == domain) begin
00114          automatic int n = this.offset_in_block.size();
00115    
00116          this.offset_in_block = new [n + 1] (this.offset_in_block);
00117          this.offset_in_block[n] = (unmapped) ? 'X : base_addr;
00118     
00119          this.domains = new [n + 1] (this.domains);
00120          this.domains[n] = domain;
00121 
00122          this.rights = new [n + 1] (this.rights);
00123          this.rights[n] = acc;
00124 
00125          this.frontdoor = new [n + 1] (this.frontdoor);
00126          this.frontdoor[n] = null;
00127          return;
00128       end
00129    end
00130    `vmm_error(this.log, $psprintf("Domain \"%s\" not found in parent block %s of memory %s",
00131                                   domain, this.parent.get_name(), this.get_fullname()));
00132 endfunction: add_domain
00133 
00134 
00135 function void vmm_ral_mem::Xregister_ral_accessX(vmm_ral_access access);
00136    // There can only be one RAL Access on a RAL model
00137    if (this.ral_access != null && this.ral_access != access) begin
00138       `vmm_fatal(this.log, $psprintf("Memory %s is already used by another RAL access instance", this.get_fullname()));
00139    end
00140    this.ral_access = access;
00141 endfunction: Xregister_ral_accessX
00142 
00143 
00144 function string vmm_ral_mem::get_name();
00145    get_name = this.name;
00146 endfunction: get_name
00147 
00148 
00149 function string vmm_ral_mem::get_fullname();
00150    vmm_ral_block blk;
00151 
00152    get_fullname = this.get_name();
00153 
00154    // Do not include top-level name in full name
00155    blk = this.get_block();
00156    if (blk == null) return get_fullname;
00157    if (blk.get_parent() == null) return get_fullname;
00158 
00159    get_fullname = {this.parent.get_fullname(), ".", get_fullname};
00160 endfunction: get_fullname
00161 
00162 
00163 function int vmm_ral_mem::get_n_domains();
00164    get_n_domains = this.domains.size();
00165 endfunction: get_n_domains
00166 
00167 
00168 function void vmm_ral_mem::get_domains(ref string domains[]);
00169    domains = new [this.domains.size()] (this.domains);
00170 endfunction: get_domains
00171 
00172 
00173 function vmm_ral::access_e vmm_ral_mem::get_access(string domain);
00174    get_access = this.access;
00175    if (this.get_n_domains() == 1) return get_access;
00176 
00177    // Is the memory restricted in this domain?
00178    case (this.get_rights(domain))
00179      vmm_ral::RW:
00180        // No restrictions
00181        return get_access;
00182 
00183      vmm_ral::RO:
00184        case (get_access)
00185          vmm_ral::RW,
00186          vmm_ral::RO: get_access = vmm_ral::RO;
00187 
00188          vmm_ral::WO: begin
00189             `vmm_error(this.log,
00190                        $psprintf("WO memory %s restricted to RO in domain \"%s\"",
00191                                  this.get_fullname(), domain));
00192          end
00193 
00194          default:
00195            `vmm_error(this.log,
00196                       $psprintf("Invalid memory %s access mode \"%s\"",
00197                                 this.get_fullname(), get_access.name()));
00198        endcase
00199 
00200      vmm_ral::WO:
00201        case (get_access)
00202          vmm_ral::RW,
00203          vmm_ral::WO: get_access = vmm_ral::WO;
00204 
00205          vmm_ral::RO: begin
00206             `vmm_error(this.log,
00207                        $psprintf("RO memory %s restricted to WO in domain \"%s\"",
00208                                  this.get_fullname(), get_access.name(), domain));
00209          end
00210 
00211          default:
00212            `vmm_error(this.log,
00213                       $psprintf("Invalid memory %s access mode \"%s\"",
00214                                 this.get_fullname(), get_access.name()));
00215        endcase
00216 
00217      default:
00218        `vmm_error(this.log,
00219                   $psprintf("Shared memory \"%s\" is not shared in domain \"%s\"",
00220                             this.get_fullname(), domain));
00221    endcase
00222 endfunction: get_access
00223 
00224 
00225 function vmm_ral::access_e vmm_ral_mem::get_rights(string domain);
00226    int i;
00227 
00228    // No right restrictions if not shared
00229    if (this.domains.size() == 1) begin
00230       return vmm_ral::RW;
00231    end
00232 
00233    i = this.get_domain_index(domain);
00234    if (i < 0) return vmm_ral::RW;
00235 
00236    get_rights = this.rights[i];
00237 endfunction: get_rights
00238 
00239 
00240 function void vmm_ral_mem::get_virtual_fields(ref vmm_ral_vfield fields[]);
00241   vmm_ral_vfield vfields[];
00242 
00243   fields = new[0];
00244   foreach (this.XvregsX[i]) begin
00245     int n = fields.size();
00246     this.XvregsX[i].get_fields(vfields);
00247     fields = new[n + vfields.size()] (fields);
00248     foreach(vfields[j]) begin
00249       fields[n+j] = vfields[j];
00250     end
00251   end
00252 endfunction: get_virtual_fields
00253 
00254 
00255 // Return first occurrence of vfield matching name
00256 function vmm_ral_vfield vmm_ral_mem::get_virtual_field_by_name(string name);
00257   vmm_ral_vfield vfields[];
00258 
00259   this.get_virtual_fields(vfields);
00260   foreach (vfields[i]) begin
00261     if (vfields[i].get_name() == name) return vfields[i];
00262   end
00263   `vmm_warning(this.log,
00264                $psprintf("Unable to find virtual field \"%s\" in memory %s.",
00265                          name, this.get_fullname()));
00266    return null;
00267 endfunction: get_virtual_field_by_name
00268 
00269 
00270 function void vmm_ral_mem::get_virtual_registers(ref vmm_ral_vreg regs[]);
00271   regs = new[this.XvregsX.size()];
00272   foreach (this.XvregsX[i]) begin
00273      regs[i] = this.XvregsX[i];
00274   end
00275 endfunction: get_virtual_registers
00276 
00277 
00278 function vmm_ral_vreg vmm_ral_mem::get_vreg_by_name(string name);
00279   foreach (this.XvregsX[i]) begin
00280     if (this.XvregsX[i].get_name() == name) return this.XvregsX[i];
00281   end
00282   `vmm_warning(this.log,
00283                $psprintf("Unable to find virtual register \"%s\" in memory %s.",
00284                          name, this.get_fullname()));
00285 
00286 endfunction: get_vreg_by_name
00287 
00288 
00289 function vmm_ral_vreg vmm_ral_mem::get_vreg_by_offset(bit [63:0] offset,
00290                                                       string domain);
00291    `vmm_error(this.log, "vmm_ral_mem::get_vreg_by_offset() not yet implemented");
00292    return null;
00293 endfunction: get_vreg_by_offset
00294 
00295 
00296 function vmm_ral_block vmm_ral_mem::get_block();
00297    get_block = this.parent;
00298 endfunction: get_block
00299 
00300 
00301 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_mem::get_offset_in_block(bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00302                                                                         string                        domain);
00303    foreach (this.domains[i]) begin
00304       if (this.domains[i] == domain) begin
00305          if (this.offset_in_block[i] === 'x) begin
00306             `vmm_warning(this.log, $psprintf("Memory \"%s\" is unmapped in domain \"%s\".", this.get_name(), domain));
00307             return '0;
00308          end
00309          
00310          return this.offset_in_block[i];
00311       end
00312    end
00313    `vmm_warning(this.log, $psprintf("Unable to find offset within domain \"%s\" in memory %s.",
00314                                     domain, this.get_fullname()));
00315    get_offset_in_block = '1;
00316 endfunction: get_offset_in_block
00317 
00318 
00319 function bit [`VMM_RAL_ADDR_WIDTH-1:0] vmm_ral_mem::get_address_in_system(bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00320                                                        string                                           domain);
00321    bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00322          
00323    int i = this.get_domain_index(domain);
00324    if (i < 0) return 0;
00325          
00326    if (this.ral_access == null) begin
00327       `vmm_fatal(this.parent.log,
00328                  "RAL model is not associated with an access transactor");
00329       return 0;
00330    end
00331          
00332    if (this.offset_in_block[i] === 'x) begin
00333       `vmm_error(this.log, $psprintf("Memory \"%s\" is unmapped in domain \"%s\".", this.get_name(), this.domains[i]));
00334       return '1;
00335    end
00336          
00337    this.ral_access.Xget_physical_addressesX(this.offset_in_block[i],
00338                                             mem_addr, this.get_n_bytes(),
00339                                             this.parent,
00340                                             this.domains[i],
00341                                             addr);
00342 
00343    get_address_in_system = addr[0];
00344 endfunction: get_address_in_system
00345 
00346 
00347 function longint unsigned vmm_ral_mem::get_size();
00348    get_size = this.size;
00349 endfunction: get_size
00350 
00351 
00352 function int unsigned vmm_ral_mem::get_n_bits();
00353    get_n_bits = this.n_bits;
00354 endfunction: get_n_bits
00355 
00356 
00357 function int unsigned vmm_ral_mem::get_n_bytes();
00358    get_n_bytes = (this.n_bits - 1) / 8 + 1;
00359 endfunction: get_n_bytes
00360 
00361 
00362 function void vmm_ral_mem::display(string prefix,
00363                                    string domain);
00364    $write("%s\n", this.psdisplay(prefix, domain));
00365 endfunction: display
00366 
00367 
00368 function string vmm_ral_mem::psdisplay(string prefix,
00369                                        string domain);
00370    $sformat(psdisplay, "%sMemory %s -- %0dx%0d bits @", prefix,
00371             this.get_fullname(), this.get_size(), this.get_n_bits());
00372    foreach (this.domains[i]) begin
00373       if (this.domains[i] == domain) begin
00374          if (this.offset_in_block[i] === 'x) begin
00375             psdisplay = {psdisplay, "none"};
00376          end
00377          else begin
00378             $sformat(psdisplay, "%s'h%h", psdisplay,
00379                      this.get_address_in_system(0, domain));
00380          end
00381          break;
00382       end
00383    end
00384 endfunction: psdisplay
00385 
00386 
00387 function bit vmm_ral_mem::set_cover(bit is_on);
00388    set_cover = this.cover_on;
00389 
00390    if (this.no_cover && is_on) begin
00391       `vmm_warning(this.log, $psprintf("Cannot turn cover ON if constructed with coverage disabled in memory %s", this.get_fullname()));
00392       return 0;
00393    end
00394 
00395    this.cover_on = is_on;
00396 endfunction: set_cover
00397 
00398 
00399 function bit vmm_ral_mem::is_cover_on();
00400    is_cover_on = this.cover_on;
00401 endfunction: is_cover_on
00402 
00403 
00404 task vmm_ral_mem::init(output bit                           is_ok,
00405                        input  init_e                        pattern,
00406                        input  bit [`VMM_RAL_DATA_WIDTH-1:0] data);
00407    int incr;
00408    is_ok = 0;
00409 
00410    if (this.backdoor == null) begin
00411       `vmm_error(this.log, $psprintf("No backdoor available to initialize memory %s", this.get_fullname()));
00412       return;
00413    end
00414 
00415    case (pattern)
00416    UNKNOWNS:
00417      begin
00418         data = 'x;
00419         incr = 0;
00420      end
00421 
00422    ZEROES:
00423      begin
00424         data = '0;
00425         incr = 0;
00426      end
00427 
00428    ONES:
00429      begin
00430         data = '1;
00431         incr = 0;
00432      end
00433 
00434    VALUE:
00435      begin
00436         incr = 0;
00437      end
00438 
00439    INCR:
00440      begin
00441         incr = 1;
00442      end
00443 
00444    DECR:
00445      begin
00446         incr = -1;
00447      end
00448    endcase
00449 
00450    // ToDo...
00451 endtask:init
00452 
00453 
00454 task vmm_ral_mem::write(output vmm_rw::status_e              status,
00455                         input  bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00456                         input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00457                         input  vmm_ral::path_e               path,
00458                         input  string                        domain,
00459                         input  int                           data_id,
00460                         input  int                           scenario_id,
00461                         input  int                           stream_id);
00462    status = vmm_rw::ERROR;
00463    
00464    if (this.ral_access == null) begin
00465       `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00466       return;
00467    end
00468    
00469    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00470 
00471    `vmm_callback(vmm_ral_mem_callbacks,
00472                  pre_write(this, mem_addr, value, path, domain));
00473 
00474    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00475 
00476    if (path == vmm_ral::BACKDOOR &&
00477        this.backdoor == null) begin
00478       `vmm_warning(this.log, $psprintf("No backdoor access available for memory \"%s\". Using frontdoor instead.", this.get_name()));
00479       path = vmm_ral::BFM;
00480    end
00481 
00482    case (path)
00483       
00484       vmm_ral::BFM: begin
00485          int di = this.get_domain_index(domain);
00486          if (di < 0) return;
00487 
00488          if (this.frontdoor[di] != null) begin
00489             this.frontdoor[di].write(status, mem_addr, value,
00490                                      data_id, scenario_id, stream_id);
00491          end
00492          else begin
00493             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00494             int w, j;
00495             int n_bits;
00496          
00497             if (this.offset_in_block[di] === 'x) begin
00498                `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00499                                               this.get_name(),
00500                                               this.domains[di]));
00501                return;
00502             end
00503          
00504             w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00505                                                          mem_addr,
00506                                                          this.get_n_bytes(),
00507                                                          this.parent,
00508                                                          this.domains[di],
00509                                                          addr);
00510             j = 0;
00511             n_bits = this.get_n_bits;
00512             foreach (addr[i]) begin
00513                bit [`VMM_RAL_DATA_WIDTH-1:0] data;
00514                data = value >> (j*8);
00515                this.ral_access.write(status, addr[i], data,
00516                                      (n_bits > w*8) ? w*8 : n_bits,
00517                                      this.parent.get_external_domain(this.domains[di]),
00518                                      data_id, scenario_id, stream_id);
00519                if (status != vmm_rw::IS_OK) break;
00520                j += w;
00521                n_bits -= w * 8;
00522             end
00523          end
00524 
00525          if (this.cover_on) this.parent.XsampleX(this.offset_in_block[di], di);
00526       end
00527       
00528       vmm_ral::BACKDOOR: begin
00529          // Mimick front door access: Do not write read-only memories
00530          if (this.get_access(domain) == vmm_ral::RW) begin
00531             this.poke(status, mem_addr, value,
00532                       data_id, scenario_id, stream_id);
00533          end else status = vmm_rw::IS_OK;
00534       end
00535    endcase
00536 
00537    `vmm_callback(vmm_ral_mem_callbacks,
00538                  post_write(this, mem_addr, value, path, domain, status));
00539 
00540    `vmm_trace(this.log, $psprintf("Wrote memory \"%s\"[%0d] via %s: with 'h%h",
00541                                   this.get_fullname(), mem_addr,
00542                                   (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00543                                   value));
00544 endtask: write
00545 
00546 
00547 task vmm_ral_mem::read(output vmm_rw::status_e              status,
00548                        input  bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00549                        output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00550                        input  vmm_ral::path_e               path,
00551                        input  string                        domain,
00552                        input  int                           data_id,
00553                        input  int                           scenario_id,
00554                        input  int                           stream_id);
00555    status = vmm_rw::ERROR;
00556    
00557    if (this.ral_access == null) begin
00558       `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00559       return;
00560    end
00561    
00562    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00563 
00564    `vmm_callback(vmm_ral_mem_callbacks,
00565                  pre_read(this, mem_addr, path, domain));
00566 
00567    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00568 
00569    if (path == vmm_ral::BACKDOOR &&
00570        this.backdoor == null) begin
00571       `vmm_warning(this.log, $psprintf("No backdoor access available for memory \"%s\". Using frontdoor instead.", this.get_name()));
00572       path = vmm_ral::BFM;
00573    end
00574 
00575    case (path)
00576       
00577       vmm_ral::BFM: begin
00578          int di = this.get_domain_index(domain);
00579          if (di < 0) return;
00580          
00581          if (this.frontdoor[di] != null) begin
00582             this.frontdoor[di].read(status, mem_addr, value,
00583                                    data_id, scenario_id, stream_id);
00584          end
00585          else begin
00586             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00587             int w, j;
00588             int n_bits;
00589          
00590             if (this.offset_in_block[di] === 'x) begin
00591                `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00592                                               this.get_name(),
00593                                               this.domains[di]));
00594                return;
00595             end
00596          
00597             w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00598                                                          mem_addr,
00599                                                          this.get_n_bytes(),
00600                                                          this.parent,
00601                                                          this.domains[di],
00602                                                          addr);
00603             j = 0;
00604             n_bits = this.get_n_bits();
00605             value = 0;
00606             foreach (addr[i]) begin
00607                bit [`VMM_RAL_DATA_WIDTH-1:0] data;
00608                this.ral_access.read(status, addr[i], data,
00609                                     (n_bits > w*8) ? w*8 : n_bits,
00610                                     this.parent.get_external_domain(this.domains[di]),
00611                                     data_id, scenario_id, stream_id);
00612                if (status != vmm_rw::IS_OK) break;
00613                value |= (data & ((1 << (w*8)) - 1)) << (j*8);
00614                j += w;
00615                n_bits -= w * 8;
00616             end
00617          end
00618 
00619          if (this.cover_on) this.parent.XsampleX(this.offset_in_block[di], di);
00620       end
00621       
00622       vmm_ral::BACKDOOR: begin
00623          this.peek(status, mem_addr, value,
00624                    data_id, scenario_id, stream_id);
00625       end
00626    endcase
00627 
00628    `vmm_callback(vmm_ral_mem_callbacks,
00629                  post_read(this, mem_addr, value, path, domain, status));
00630 
00631    `vmm_trace(this.log, $psprintf("Read memory \"%s\"[%0d] via %s: 'h%h",
00632                                   this.get_fullname(), mem_addr,
00633                                   (path == vmm_ral::BFM) ? "frontdoor" : "backdoor",
00634                                   value));
00635 endtask: read
00636 
00637 
00638 function bit vmm_ral_mem::validate_burst(vmm_ral_mem_burst burst);
00639    if (burst.start_offset >= this.get_size()) begin
00640       `vmm_error(this.log, $psprintf("Starting burst offset 'h%0h is greater than number of memory locations ('h%0h)",
00641                                      burst.start_offset, this.get_size()));
00642       return 0;
00643    end
00644 
00645    if (burst.max_offset >= this.get_size()) begin
00646       `vmm_error(this.log, $psprintf("Maximum burst offset 'h%0h is greater than number of memory locations ('h%0h)",
00647                                      burst.max_offset, this.get_size()));
00648       return 0;
00649    end
00650 
00651    if (burst.n_beats == 0) begin
00652       `vmm_error(this.log, "Zero-length burst");
00653       return 0;
00654    end
00655 
00656    if (burst.start_offset > burst.max_offset) begin
00657       `vmm_error(this.log, $psprintf("Starting burst offset ('h%0h) greater than maximum burst offset ('h%0h)",
00658                                      burst.start_offset, burst.max_offset));
00659       return 0;
00660    end
00661 
00662    if (burst.n_beats > 1 &&
00663        burst.start_offset + burst.incr_offset >= burst.max_offset) begin
00664       `vmm_error(this.log, $psprintf("First burst offset increment 'h%0h+%0h is greater than maximum burst offset ('h%0h)",
00665                                      burst.start_offset, burst.incr_offset,
00666                                      burst.max_offset));
00667       return 0;
00668    end
00669 
00670    return 1;
00671 endfunction: validate_burst
00672 
00673 
00674 task vmm_ral_mem::burst_write(output vmm_rw::status_e              status,
00675                               input  vmm_ral_mem_burst             burst,
00676                               input  bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00677                               input  vmm_ral::path_e               path,
00678                               input  string                        domain,
00679                               input  int                           data_id,
00680                               input  int                           scenario_id,
00681                               input  int                           stream_id);
00682    status = vmm_rw::ERROR;
00683 
00684    if (this.ral_access == null) begin
00685       `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00686       return;
00687    end
00688    
00689    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00690 
00691    `vmm_callback(vmm_ral_mem_callbacks,
00692                  pre_burst(this, vmm_rw::WRITE, burst, value, path, domain));
00693 
00694    if (!this.validate_burst(burst)) return;
00695 
00696    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00697 
00698    case (path)
00699       
00700       vmm_ral::BFM: begin
00701          int di = this.get_domain_index(domain);
00702          if (di < 0) return;
00703 
00704          if (this.frontdoor[di] != null) begin
00705             this.frontdoor[di].burst_write(status, burst, value,
00706                                            data_id, scenario_id, stream_id);
00707          end
00708          else begin
00709             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00710             int w;
00711             int n_bits;
00712          
00713             if (this.offset_in_block[di] === 'x) begin
00714                `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00715                                               this.get_name(),
00716                                               this.domains[di]));
00717                return;
00718             end
00719          
00720             w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00721                                                          burst.start_offset,
00722                                                          this.get_n_bytes(),
00723                                                          this.parent,
00724                                                          this.domains[di],
00725                                                          addr);
00726             n_bits = this.get_n_bits;
00727             // Cannot burst memory through a narrower datapath
00728             if (n_bits > w*8) begin
00729                `vmm_error(this.log, $psprintf("Cannot burst-write a %0d-bit memory through a narrower data path (%0d bytes)",
00730                                               n_bits, w));
00731                return;
00732             end
00733             // Translate offsets into addresses
00734             begin
00735                bit [`VMM_RAL_ADDR_WIDTH-1:0] start, incr, max;
00736 
00737                start = addr[0];
00738 
00739                w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00740                                                             burst.start_offset + burst.incr_offset,
00741                                                             this.get_n_bytes(),
00742                                                             this.parent,
00743                                                             this.domains[di],
00744                                                             addr);
00745                incr = addr[0] - start;
00746 
00747                w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00748                                                             burst.max_offset,
00749                                                             this.get_n_bytes(),
00750                                                             this.parent,
00751                                                             this.domains[di],
00752                                                             addr);
00753 
00754                max = addr[addr.size()-1];
00755 
00756                this.ral_access.burst_write(status, start, incr, max, value,
00757                                            burst.user_data, n_bits,
00758                                            this.parent.get_external_domain(this.domains[di]),
00759                                            data_id, scenario_id, stream_id);
00760             end
00761          end
00762 
00763          if (this.cover_on) begin
00764             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00765             for (addr = burst.start_offset;
00766                  addr <= burst.max_offset;
00767                  addr += burst.incr_offset) begin
00768                this.parent.XsampleX(this.offset_in_block[di] + addr, di);
00769             end
00770          end
00771       end
00772       
00773       vmm_ral::BACKDOOR: begin
00774          // Mimick front door access: Do not write read-only memories
00775          if (this.get_access(domain) == vmm_ral::RW) begin
00776             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00777             addr = burst.start_offset;
00778             foreach (value[i]) begin
00779                this.poke(status, addr, value[i],
00780                          data_id, scenario_id, stream_id);
00781                if (status != vmm_rw::IS_OK) return;
00782                addr += burst.incr_offset;
00783                if (addr > burst.max_offset) begin
00784                   addr -= (burst.max_offset - burst.start_offset - 1);
00785                end
00786             end
00787          end
00788          else status = vmm_rw::IS_OK;
00789       end
00790    endcase
00791 
00792    `vmm_callback(vmm_ral_mem_callbacks,
00793                  post_burst(this, vmm_rw::WRITE, burst, value,
00794                             path, domain, status));
00795 endtask: burst_write
00796 
00797 
00798 task vmm_ral_mem::burst_read(output vmm_rw::status_e              status,
00799                              input  vmm_ral_mem_burst             burst,
00800                              output bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00801                              input  vmm_ral::path_e               path,
00802                              input  string                        domain,
00803                              input  int                           data_id,
00804                              input  int                           scenario_id,
00805                              input  int                           stream_id);
00806    status = vmm_rw::ERROR;
00807 
00808    if (this.ral_access == null) begin
00809       `vmm_error(this.log, $psprintf("Memory %s not associated with RAL access object", this.get_fullname()));
00810       return;
00811    end
00812    
00813    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00814 
00815    begin
00816       bit [`VMM_RAL_DATA_WIDTH-1:0] junk[];
00817 
00818       `vmm_callback(vmm_ral_mem_callbacks,
00819                     pre_burst(this, vmm_rw::READ, burst, junk, path, domain));
00820    end
00821 
00822    if (!this.validate_burst(burst)) return;
00823 
00824    if (path == vmm_ral::DEFAULT) path = this.parent.get_default_access();
00825 
00826    case (path)
00827       
00828       vmm_ral::BFM: begin
00829          int di = this.get_domain_index(domain);
00830          if (di < 0) return;
00831          
00832          if (this.frontdoor[di] != null) begin
00833             this.frontdoor[di].burst_read(status, burst, value,
00834                                           data_id, scenario_id, stream_id);
00835          end
00836          else begin
00837             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[];
00838             int n_bits, w;
00839          
00840             if (this.offset_in_block[di] === 'x) begin
00841                `vmm_error(this.log, $psprintf("Memory \"%s\" unmapped in domain \"%s\" does not have a user-defined frontdoor",
00842                                               this.get_name(),
00843                                               this.domains[di]));
00844                return;
00845             end
00846          
00847             w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00848                                                          burst.start_offset,
00849                                                          this.get_n_bytes(),
00850                                                          this.parent,
00851                                                          this.domains[di],
00852                                                          addr);
00853             n_bits = this.get_n_bits();
00854             // Cannot burst memory through a narrower datapath
00855             if (n_bits > w*8) begin
00856                `vmm_error(this.log, $psprintf("Cannot burst-write a %0d-bit memory through a narrower data path (%0d bytes)",
00857                                               n_bits, w));
00858                return;
00859             end
00860             // Translate the offset-based burst into address-based burst
00861             begin
00862                bit [`VMM_RAL_ADDR_WIDTH-1:0] start, incr, max;
00863 
00864                start = addr[0];
00865 
00866                w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00867                                                             burst.start_offset + burst.incr_offset,
00868                                                             this.get_n_bytes(),
00869                                                             this.parent,
00870                                                             this.domains[di],
00871                                                             addr);
00872                incr = addr[0] - start;
00873 
00874                w = this.ral_access.Xget_physical_addressesX(this.offset_in_block[di],
00875                                                             burst.max_offset,
00876                                                             this.get_n_bytes(),
00877                                                             this.parent,
00878                                                             this.domains[di],
00879                                                             addr);
00880 
00881                max = addr[addr.size()-1];
00882 
00883                this.ral_access.burst_read(status, start, incr, max,
00884                                           burst.n_beats, value,
00885                                           burst.user_data, n_bits,
00886                                           this.parent.get_external_domain(this.domains[di]),
00887                                           data_id, scenario_id, stream_id);
00888             end
00889          end
00890 
00891          if (this.cover_on) begin
00892             bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00893             for (addr = burst.start_offset;
00894                  addr <= burst.max_offset;
00895                  addr += burst.incr_offset) begin
00896                this.parent.XsampleX(this.offset_in_block[di] + addr, di);
00897             end
00898          end
00899       end
00900       
00901       vmm_ral::BACKDOOR: begin
00902          bit [`VMM_RAL_ADDR_WIDTH-1:0] addr;
00903          value = new [burst.n_beats];
00904          addr = burst.start_offset;
00905          foreach (value[i]) begin
00906             this.peek(status, addr, value[i],
00907                       data_id, scenario_id, stream_id);
00908             if (status != vmm_rw::IS_OK) return;
00909             addr += burst.incr_offset;
00910             if (addr > burst.max_offset) begin
00911                addr -= (burst.max_offset - burst.start_offset - 1);
00912             end
00913          end
00914       end
00915    endcase
00916 
00917    `vmm_callback(vmm_ral_mem_callbacks,
00918                  post_burst(this, vmm_rw::READ, burst, value,
00919                             path, domain, status));
00920 endtask: burst_read
00921 
00922 
00923 task vmm_ral_mem::poke(output vmm_rw::status_e              status,
00924                        input  bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00925                        input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00926                        input  int                           data_id,
00927                        input  int                           scenario_id,
00928                        input  int                           stream_id);
00929    if (this.backdoor == null) begin
00930       `vmm_error(this.log, $psprintf("No backdoor access available in memory %s", this.get_fullname()));
00931       status = vmm_rw::ERROR;
00932       return;
00933    end
00934    this.backdoor.write(status, mem_addr, value, data_id, scenario_id, stream_id);
00935 
00936    `vmm_trace(this.log, $psprintf("Poked memory \"%s\"[%0d] with: 'h%h",
00937                                   this.get_fullname(), mem_addr, value));
00938 endtask: poke
00939 
00940 
00941 task vmm_ral_mem::peek(output vmm_rw::status_e              status,
00942                        input  bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_addr,
00943                        output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00944                        input  int                           data_id,
00945                        input  int                           scenario_id,
00946                        input  int                           stream_id);
00947    if (this.backdoor == null) begin
00948       `vmm_error(this.log, $psprintf("No backdoor access available in memory %s", this.get_fullname()));
00949       status = vmm_rw::ERROR;
00950       return;
00951    end
00952    this.backdoor.read(status, mem_addr, value, data_id, scenario_id, stream_id);
00953 
00954    `vmm_trace(this.log, $psprintf("Peeked memory \"%s\"[%0d]: 'h%h",
00955                                   this.get_fullname(), mem_addr, value));
00956 endtask: peek
00957 
00958 
00959 task vmm_ral_mem::readmemh(string filename);
00960 endtask: readmemh
00961 
00962 
00963 task vmm_ral_mem::writememh(string filename);
00964 endtask: writememh
00965 
00966 
00967 function void vmm_ral_mem::set_frontdoor(vmm_ral_mem_frontdoor ftdr,
00968                                          string                domain);
00969    foreach(this.domains[i]) begin
00970       if (this.domains[i] == domain) begin
00971          this.frontdoor[i] = ftdr;
00972          return;
00973       end
00974    end
00975    `vmm_error(this.log, $psprintf("Domain \"%s\" not found in memory %s", domain, this.get_fullname()));
00976 endfunction: set_frontdoor
00977 
00978 
00979 function vmm_ral_mem_frontdoor vmm_ral_mem::get_frontdoor(string domain);
00980    foreach(this.domains[i]) begin
00981       if (this.domains[i] == domain) begin
00982          return this.frontdoor[i];
00983       end
00984    end
00985    `vmm_error(this.log, $psprintf("Domain \"%s\" not found in memory %s", domain, this.get_fullname()));
00986 endfunction: get_frontdoor
00987 
00988 
00989 function void vmm_ral_mem::set_backdoor(vmm_ral_mem_backdoor bkdr);
00990    this.backdoor = bkdr;
00991 endfunction: set_backdoor
00992 
00993 
00994 function vmm_ral_mem_backdoor vmm_ral_mem::get_backdoor();
00995    get_backdoor = this.backdoor;
00996 endfunction: get_backdoor
00997 
00998 
00999 function void vmm_ral_mem::prepend_callback(vmm_ral_mem_callbacks cb);
01000    foreach (this.callbacks[i]) begin
01001       if (this.callbacks[i] == cb) begin
01002          `vmm_warning(this.log, $psprintf("Callback has already been registered with memory %s", this.get_fullname()));
01003          return;
01004       end
01005    end
01006    
01007    // Prepend new callback
01008    this.callbacks.push_front(cb);
01009 endfunction: prepend_callback
01010 
01011 
01012 function void vmm_ral_mem::append_callback(vmm_ral_mem_callbacks cb);
01013    foreach (this.callbacks[i]) begin
01014       if (this.callbacks[i] == cb) begin
01015          `vmm_warning(this.log, $psprintf("Callback has already been registered with memory %s", this.get_fullname()));
01016          return;
01017       end
01018    end
01019    
01020    // Append new callback
01021    this.callbacks.push_back(cb);
01022 endfunction: append_callback
01023 
01024 
01025 function void vmm_ral_mem::unregister_callback(vmm_ral_mem_callbacks cb);
01026    foreach (this.callbacks[i]) begin
01027       if (this.callbacks[i] == cb) begin
01028          int j = i;
01029          // Unregister it
01030          this.callbacks.delete(j);
01031          return;
01032       end
01033    end
01034 
01035 `vmm_warning(this.log, $psprintf("Callback was not registered with memory %s", this.get_fullname()));
01036 endfunction: unregister_callback
01037 
01038 
01039 function int vmm_ral_mem::get_domain_index(string domain);
01040    // If the domain is "" and there is only one domain,
01041    // assume it is the one domain available to avoid
01042    // having to always have to specify domains
01043    if (domain == "" && this.domains.size() == 1) return 0;
01044 
01045    foreach (this.domains[i]) begin
01046       if (this.domains[i] == domain) return i;
01047    end
01048    `vmm_warning(this.log, $psprintf("Unknown domain name \"%s\" in memory %s.", domain, this.get_fullname()));
01049    return -1;
01050 endfunction: get_domain_index
01051 
01052 
01053 task vmm_ral_mem_frontdoor::write(output vmm_rw::status_e              status,
01054                                   input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
01055                                   input  bit [`VMM_RAL_DATA_WIDTH-1:0] data,
01056                                   input  int                           data_id,
01057                                   input  int                           scenario_id,
01058                                   input  int                           stream_id);
01059    `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::write() method has not been overloaded");
01060 endtask: write
01061 
01062 
01063 task vmm_ral_mem_frontdoor::read(output vmm_rw::status_e              status,
01064                                  input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
01065                                  output bit [`VMM_RAL_DATA_WIDTH-1:0] data,
01066                                  input  int                           data_id,
01067                                  input  int                           scenario_id,
01068                                  input  int                           stream_id);
01069    `vmm_fatal(this.log, "vmm_ral_mem_frontdoor::read() method has not been overloaded");
01070 endtask: read
01071 
01072 
01073 function int unsigned vmm_ral_mem::get_mem_ID();
01074    get_mem_ID =  this.__vmm_mem_id;
01075 endfunction
01076 
01077 function vmm_ral_mem vmm_ral_mem::get_mem_by_ID(int unsigned id);
01078    if (__vmm_all_mems.exists(id)) get_mem_by_ID = __vmm_all_mems[id];
01079    else get_mem_by_ID = null;
01080 endfunction