VMM OpenSource - sv/RAL/vmm_ral_mem.sv

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