VMM - RAL/vmm_ral_block.sv

RAL/vmm_ral_block.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 class vmm_ral_block extends vmm_ral_block_or_sys;
00024 
00025    local vmm_ral_reg  regs[$];
00026    local vmm_ral_vreg vregs[$];
00027    local vmm_ral_mem  mems[$];
00028    static local vmm_ral_block __vmm_all_blocks[*];  // Keeps track of all Blocks in the RAL Model
00029    local int unsigned __vmm_block_id = 0;
00030 
00031    extern function new(vmm_ral_sys                   parent,
00032                        string                        name,
00033                        string                        typename,
00034                        int unsigned                  n_bytes,
00035                        vmm_ral::endianness_e         endian,
00036                        bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00037                        string                        domain   = "",
00038                        bit                           cover_on = 1);
00039 
00040    /*local*/ extern virtual function void Xlock_modelX();
00041    /*local*/ extern function void register_reg(vmm_ral_reg register);
00042    /*local*/ extern function void register_vreg(vmm_ral_vreg register);
00043    /*local*/ extern function void register_mem(vmm_ral_mem memory);
00044    /*local*/ extern virtual function void Xregister_ral_accessX(vmm_ral_access access);
00045 
00046    extern virtual function string psdisplay(string prefix = "",
00047                                             string domain = "");
00048 
00049    extern virtual function void get_fields(ref vmm_ral_field fields[],
00050                                            input string      domain = ""); 
00051    extern virtual function void get_virtual_fields(ref vmm_ral_vfield fields[],
00052                                                    input string      domain = ""); 
00053    extern virtual function vmm_ral_field get_field_by_name(string name);
00054    extern virtual function vmm_ral_vfield get_virtual_field_by_name(string name);
00055 
00056    extern virtual function void get_registers(ref vmm_ral_reg regs[],
00057                                               input string    domain = "");
00058    extern virtual function void get_virtual_registers(ref vmm_ral_vreg vregs[],
00059                                                       input string    domain = "");
00060    extern virtual function vmm_ral_reg get_reg_by_name(string name);
00061    extern virtual function vmm_ral_vreg get_vreg_by_name(string name);
00062    extern virtual function vmm_ral_reg get_reg_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00063                                                          string                        domain = "");
00064 
00065    extern virtual function void get_memories(ref vmm_ral_mem mems[],
00066                                              input string    domain = "");
00067    extern virtual function vmm_ral_mem get_mem_by_name(string name);
00068    extern virtual function vmm_ral_mem get_mem_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00069                                                          string                        domain = "");
00070 
00071    extern virtual function void get_constraints(ref string names[]);
00072 
00073    extern virtual function bit set_cover(bit is_on);
00074 
00075    extern virtual function void reset(string           domain = "",
00076                                       vmm_ral::reset_e kind   = vmm_ral::HARD);
00077    extern virtual function bit needs_update();
00078 
00079    extern virtual task update(output vmm_rw::status_e status,
00080                               input  vmm_ral::path_e  path = vmm_ral::DEFAULT);
00081    extern virtual task mirror(output vmm_rw::status_e status,
00082                               input  vmm_ral::check_e check = vmm_ral::	QUIET,
00083                               input  vmm_ral::path_e  path  = vmm_ral::DEFAULT);
00084    
00085    extern virtual task readmemh(string filename);
00086    extern virtual task writememh(string filename);
00087 
00088    extern virtual /*local*/ function void XsampleX(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr,
00089                                                    int                           domain);
00090    extern protected virtual function void sample(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr,
00091                                                  int                           domain);
00092 
00093    extern function int unsigned get_block_ID(); 
00094 
00095    extern /*static*/ function vmm_ral_block get_block_by_ID(int unsigned id); 
00096 endclass: vmm_ral_block
00097    
00098 
00099 function vmm_ral_block::new(vmm_ral_sys                   parent,
00100                             string                        name,
00101                             string                        typename,
00102                             int unsigned                  n_bytes,
00103                             vmm_ral::endianness_e         endian,
00104                             bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr,
00105                             string                        domain,
00106                             bit                           cover_on);
00107    super.new(parent, "RAL Block", name, typename,
00108              n_bytes, endian, base_addr, domain,
00109              cover_on);
00110 
00111    // Initialize Block ID
00112    this.__vmm_block_id = ++this.__vmm_block_or_sys_id_factory;
00113    __vmm_all_blocks[this.__vmm_block_id] = this;
00114 endfunction: new
00115 
00116 
00117 function void vmm_ral_block::Xlock_modelX();
00118    if (this.Xis_lockedX()) return;
00119 
00120    super.Xlock_modelX();
00121    foreach (this.regs[i]) begin
00122       this.regs[i].Xlock_modelX();
00123    end
00124    foreach (this.mems[i]) begin
00125       this.mems[i].Xlock_modelX();
00126    end
00127 endfunction: Xlock_modelX
00128 
00129 
00130 function void vmm_ral_block::register_reg(vmm_ral_reg register);
00131    if (this.Xis_lockedX()) begin
00132       `vmm_error(this.log, "Cannot add register to locked block model");
00133       return;
00134    end
00135 
00136    // Check if this register has already been registered with this block
00137    foreach (this.regs[i]) begin
00138       if (this.regs[i] == register) begin
00139          `vmm_error(this.log, $psprintf("Register \"%s\" has already been registered with block \"%s\".\n",
00140                                        register.get_name(), this.get_name()));
00141          return;
00142       end
00143    end
00144    this.regs.push_back(register);
00145 endfunction: register_reg
00146 
00147 function void vmm_ral_block::register_vreg(vmm_ral_vreg register);
00148    if (this.Xis_lockedX()) begin
00149       `vmm_error(this.log, "Cannot add virtual register to locked block model");
00150       return;
00151    end
00152 
00153    // Check if this register has already been registered with this block
00154    foreach (this.vregs[i]) begin
00155       if (this.vregs[i] == register) begin
00156          `vmm_error(this.log, $psprintf("Virtual register \"%s\" has already been registered with block \"%s\".\n",
00157                                        register.get_name(), this.get_name()));
00158          return;
00159       end
00160    end
00161    this.vregs.push_back(register);
00162 endfunction: register_vreg
00163 
00164 function void vmm_ral_block::register_mem(vmm_ral_mem memory);
00165    if (this.Xis_lockedX()) begin
00166       `vmm_error(this.log, "Cannot add memory to locked block model");
00167       return;
00168    end
00169 
00170    // Check if this memory has already been registered with this block
00171    foreach (this.mems[i]) begin
00172       if (this.mems[i] == memory) begin
00173          `vmm_error(this.log, $psprintf("Memory \"%s\" has already been registered with block \"%s\".\n",
00174                                        memory.get_name(), this.get_name()));
00175          return;
00176       end
00177    end
00178    this.mems.push_back(memory);
00179 endfunction: register_mem
00180 
00181 
00182 function void vmm_ral_block::Xregister_ral_accessX(vmm_ral_access access);
00183    // There can only be one RAL Access on a RAL model
00184    if (this.ral_access != null && this.ral_access != access) begin
00185       `vmm_fatal(this.log, $psprintf("Block %s is already used by another RAL access instance", this.get_fullname()));
00186    end
00187    this.ral_access = access;
00188 
00189    // Register all sub-elements
00190    begin
00191       vmm_ral_reg  regs[];
00192       vmm_ral_mem  mems[];
00193 
00194       this.get_registers(regs);
00195       foreach (regs[i]) begin
00196          regs[i].Xregister_ral_accessX(access);
00197       end
00198 
00199       this.get_memories(mems);
00200       foreach (mems[i]) begin
00201          mems[i].Xregister_ral_accessX(access);
00202       end
00203    end
00204 endfunction: Xregister_ral_accessX
00205 
00206 
00207 function string vmm_ral_block::psdisplay(string prefix,
00208                                          string domain);
00209    string       domains[];
00210    vmm_ral_reg  regs[];
00211    vmm_ral_vreg vregs[];
00212    vmm_ral_mem  mems[];
00213    bit          single_domain;
00214    vmm_ral::endianness_e endian;
00215 
00216    single_domain = 1;
00217    if (domain == "") begin
00218       this.get_domains(domains);
00219       if (domains.size() > 1) single_domain = 0;
00220    end
00221    if (single_domain) begin
00222       $sformat(psdisplay, "%sBlock %s", prefix, this.get_fullname());
00223       if (domain != "") $sformat(psdisplay, "%s.%s", psdisplay, domain);
00224       endian = this.get_endian(domain);
00225       $sformat(psdisplay, "%s -- %0d bytes (%s)", psdisplay,
00226                this.get_n_bytes(domain), endian.name());
00227       this.get_registers(regs, domain);
00228       foreach (regs[j]) begin
00229          $sformat(psdisplay, "%s\n%s", psdisplay,
00230                   regs[j].psdisplay({prefix, "   "}, domain));
00231       end
00232       this.get_virtual_registers(vregs, domain);
00233       foreach (vregs[j]) begin
00234          $sformat(psdisplay, "%s\n%s", psdisplay,
00235                   vregs[j].psdisplay({prefix, "   "}, domain));
00236       end
00237       this.get_memories(mems, domain);
00238       foreach (mems[j]) begin
00239          $sformat(psdisplay, "%s\n%s", psdisplay,
00240                   mems[j].psdisplay({prefix, "   "}, domain));
00241       end
00242    end
00243    else begin
00244       $sformat(psdisplay, "%sBlock %s", prefix, this.get_fullname());
00245       foreach (domains[i]) begin
00246          endian = this.get_endian(domains[i]);
00247          $sformat(psdisplay, "%s\n%s   Domain \"%s\" -- %0d bytes (%s)",
00248                   psdisplay, prefix, domains[i],
00249                   this.get_n_bytes(domains[i]), endian.name());
00250          this.get_registers(regs, domains[i]);
00251          foreach (regs[j]) begin
00252             $sformat(psdisplay, "%s\n%s", psdisplay,
00253                      regs[j].psdisplay({prefix, "      "},
00254                                        domains[i]));
00255          end
00256          this.get_virtual_registers(vregs, domains[i]);
00257          foreach (vregs[j]) begin
00258             $sformat(psdisplay, "%s\n%s", psdisplay,
00259                      vregs[j].psdisplay({prefix, "      "},
00260                                        domains[i]));
00261          end
00262          this.get_memories(mems, domains[i]);
00263          foreach (mems[j]) begin
00264             $sformat(psdisplay, "%s\n%s", psdisplay,
00265                      mems[j].psdisplay({prefix, "      "}, domains[i]));
00266          end
00267       end
00268    end
00269 endfunction: psdisplay
00270 
00271 
00272 function void vmm_ral_block::get_fields(ref vmm_ral_field fields[],
00273                                         input string      domain);
00274    int n;
00275    vmm_ral_reg r[];
00276    vmm_ral_field f[];
00277 
00278    fields = new [0];
00279    this.get_registers(r, domain);
00280    foreach (r[i]) begin
00281       r[i].get_fields(f);
00282       n = fields.size();
00283       fields = new [n + f.size()] (fields);
00284 
00285       foreach (f[j]) begin
00286          fields[n++] = f[j];
00287       end
00288    end
00289 endfunction: get_fields
00290 
00291 function void vmm_ral_block::get_virtual_fields(ref vmm_ral_vfield fields[],
00292                                                 input string      domain);
00293    int n;
00294    vmm_ral_vreg r[];
00295    vmm_ral_vfield f[];
00296 
00297    fields = new [0];
00298    this.get_virtual_registers(r, domain);
00299    foreach (r[i]) begin
00300       r[i].get_fields(f);
00301       n = fields.size();
00302       fields = new [n + f.size()] (fields);
00303 
00304       foreach (f[j]) begin
00305          fields[n++] = f[j];
00306       end
00307    end
00308 endfunction: get_virtual_fields
00309 
00310 function vmm_ral_field vmm_ral_block::get_field_by_name(string name);
00311    // Search the registers to find the first field of the specified name
00312    foreach (this.regs[i]) begin
00313       vmm_ral_field fields[];
00314       this.regs[i].get_fields(fields);
00315       foreach (fields[j]) begin
00316          if (fields[j].get_name() == name) begin
00317             return fields[j];
00318          end
00319       end
00320    end
00321    `vmm_warning(this.log, $psprintf("Unable to locate field \"%s\" in block \"%s\".",
00322                                     name, this.get_fullname()));
00323    get_field_by_name = null;
00324 endfunction: get_field_by_name
00325 
00326 function vmm_ral_vfield vmm_ral_block::get_virtual_field_by_name(string name);
00327    // Search the registers to find the first field of the specified name
00328    foreach (this.vregs[i]) begin
00329       vmm_ral_vfield fields[];
00330       this.vregs[i].get_fields(fields);
00331       foreach (fields[j]) begin
00332          if (fields[j].get_name() == name) begin
00333             return fields[j];
00334          end
00335       end
00336    end
00337    `vmm_warning(this.log, $psprintf("Unable to locate virtual field \"%s\" in block \"%s\".",
00338                                     name, this.get_fullname()));
00339    get_virtual_field_by_name = null;
00340 endfunction: get_virtual_field_by_name
00341 
00342 
00343 function void vmm_ral_block::get_registers(ref vmm_ral_reg regs[],
00344                                            input string    domain);
00345    if (domain == "") begin
00346       regs = new [this.regs.size()];
00347       foreach(this.regs[i]) begin
00348          regs[i] = this.regs[i];
00349       end
00350    end
00351    else begin
00352       int n = 0;
00353       regs = new [this.regs.size()];
00354       foreach(this.regs[i]) begin
00355          // Is the register in the specified domain?
00356          string domains[];
00357          this.regs[i].get_domains(domains);
00358          foreach(domains[j]) begin
00359             if (domains[j] == domain) begin
00360                regs[n++] = this.regs[i];
00361                break;
00362             end
00363          end
00364       end
00365       regs = new [n] (regs);
00366    end
00367 endfunction: get_registers
00368 
00369 function void vmm_ral_block::get_virtual_registers(ref vmm_ral_vreg vregs[],
00370                                                    input string    domain);
00371    if (domain == "") begin
00372       vregs = new [this.vregs.size()];
00373       foreach(this.vregs[i]) begin
00374          vregs[i] = this.vregs[i];
00375       end
00376    end
00377    else begin
00378       int n = 0;
00379       vregs = new [this.vregs.size()];
00380       foreach(this.vregs[i]) begin
00381          // Is the register in the specified domain?
00382          string domains[];
00383          this.vregs[i].get_domains(domains);
00384          foreach(domains[j]) begin
00385             if (domains[j] == domain) begin
00386                vregs[n++] = this.vregs[i];
00387                break;
00388             end
00389          end
00390       end
00391       vregs = new [n] (vregs);
00392    end
00393 endfunction: get_virtual_registers
00394 
00395 function vmm_ral_reg vmm_ral_block::get_reg_by_name(string name);
00396    foreach (this.regs[i]) begin
00397       if (this.regs[i].get_name() == name) begin
00398          return this.regs[i];
00399       end
00400    end
00401    `vmm_warning(this.log, $psprintf("Unable to locate register \"%s\" in block \"%s\".",
00402                                     name, this.get_fullname()));
00403    get_reg_by_name = null;
00404 endfunction: get_reg_by_name
00405 
00406 function vmm_ral_vreg vmm_ral_block::get_vreg_by_name(string name);
00407    foreach (this.vregs[i]) begin
00408       if (this.vregs[i].get_name() == name) begin
00409          return this.vregs[i];
00410       end
00411    end
00412    `vmm_warning(this.log, $psprintf("Unable to locate virtual register \"%s\" in block \"%s\".",
00413                                     name, this.get_fullname()));
00414    get_vreg_by_name = null;
00415 endfunction: get_vreg_by_name
00416 
00417 function vmm_ral_reg vmm_ral_block::get_reg_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00418                                                       string                        domain);
00419    foreach (this.regs[i]) begin
00420       if (this.regs[i].get_offset_in_block(domain) == offset) begin
00421          return this.regs[i];
00422       end
00423    end
00424    `vmm_warning(this.log, $psprintf("Unable to locate register at offset 0x%h %0sin block \"%s\".",
00425                                     offset, ((domain == "") ? "" : $psprintf("in domain \"%s\" ",
00426                                                                              domain)),
00427                                     this.get_fullname()));
00428    get_reg_by_offset = null;
00429 endfunction: get_reg_by_offset
00430 
00431 
00432 function void vmm_ral_block::get_memories(ref vmm_ral_mem mems[],
00433                                           input string    domain);
00434    if (domain == "") begin
00435       mems = new [this.mems.size()];
00436       foreach(this.mems[i]) begin
00437          mems[i] = this.mems[i];
00438       end
00439    end
00440    else begin
00441       int n = 0;
00442       mems = new [this.mems.size()];
00443       foreach(this.mems[i]) begin
00444          // Is the memory in the specified domain?
00445          string domains[];
00446          this.mems[i].get_domains(domains);
00447          foreach(domains[j]) begin
00448             if (domains[j] == domain) begin
00449                mems[n++] = this.mems[i];
00450                break;
00451             end
00452          end
00453       end
00454       mems = new [n] (mems);
00455    end
00456 endfunction: get_memories
00457 
00458 
00459 function vmm_ral_mem vmm_ral_block::get_mem_by_name(string name);
00460    foreach (this.mems[i]) begin
00461       if (this.mems[i].get_name() == name) begin
00462          return this.mems[i];
00463       end
00464    end
00465    `vmm_warning(this.log, $psprintf("Unable to locate memory \"%s\" in block \"%s\".",
00466                                     name, this.get_fullname()));
00467    get_mem_by_name = null;
00468 endfunction: get_mem_by_name
00469 
00470 
00471 function vmm_ral_mem vmm_ral_block::get_mem_by_offset(bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00472                                                       string                        domain);
00473    //get_mem_by_offset = this.mems.first() with index: (this.mems[index].offset_in_block == offset);
00474 endfunction: get_mem_by_offset
00475 
00476 
00477 function void vmm_ral_block::get_constraints(ref string names[]);
00478 endfunction: get_constraints
00479 
00480 
00481 function bit vmm_ral_block::set_cover(bit is_on);
00482    set_cover = super.set_cover(is_on);
00483 
00484    if (is_on && !super.is_cover_on()) return set_cover;
00485 
00486    foreach (this.regs[i]) begin
00487       this.regs[i].set_cover(is_on);
00488    end
00489    foreach (this.mems[i]) begin
00490       this.mems[i].set_cover(is_on);
00491    end
00492 endfunction: set_cover
00493 
00494 
00495 function void vmm_ral_block::reset(string           domain,
00496                                    vmm_ral::reset_e kind);
00497    vmm_ral_reg regs[];
00498    vmm_ral_mem mems[];
00499 
00500    this.get_registers(regs, domain);
00501    foreach (regs[i]) begin
00502       regs[i].reset(kind);
00503    end
00504 
00505    this.get_memories(mems, domain);
00506    foreach (mems[i]) begin
00507       vmm_ral_vreg vregs[];
00508       mems[i].get_virtual_registers(vregs);
00509       foreach (vregs[j]) begin
00510          vregs[j].reset(kind);
00511       end
00512    end
00513 endfunction: reset
00514 
00515 
00516 function bit vmm_ral_block::needs_update();
00517    needs_update = 0;
00518    foreach (this.regs[i]) begin
00519       if (this.regs[i].needs_update()) begin
00520          return 1;
00521       end
00522    end
00523 endfunction: needs_update
00524 
00525 
00526 task vmm_ral_block::update(output vmm_rw::status_e status,
00527                            input  vmm_ral::path_e  path);
00528    string domains[];
00529    bit    updated;
00530 
00531    status = vmm_rw::IS_OK;
00532    foreach (this.regs[i]) begin
00533       if (!this.regs[i].needs_update()) continue;
00534 
00535       if (path == vmm_ral::BACKDOOR) begin
00536          this.regs[i].update(status, path);
00537          if (status != vmm_rw::IS_OK) return;
00538          continue;
00539       end
00540 
00541       // Find the first writeable domain to
00542       // perform the update through
00543       this.regs[i].get_domains(domains);
00544       updated = 0;
00545       foreach (domains[j]) begin
00546          if (this.regs[i].get_rights(domains[j]) != vmm_ral::RO) begin
00547             this.regs[i].update(status, path, domains[j]);
00548             if (status == vmm_rw::IS_OK) begin
00549                updated = 1;
00550                break;
00551             end
00552          end
00553       end
00554       if (!updated) begin
00555          `vmm_error(this.log, $psprintf("Register \"%s\" could not be updated",
00556                                         regs[i].get_fullname()));
00557          if (status == vmm_rw::IS_OK) status = vmm_rw::ERROR;
00558          return;
00559       end
00560    end
00561 endtask: update
00562 
00563 
00564 task vmm_ral_block::mirror(output vmm_rw::status_e status,
00565                            input  vmm_ral::check_e check,
00566                            input  vmm_ral::path_e  path);
00567    string domains[];
00568    bit mirrored;
00569 
00570    status = vmm_rw::IS_OK;
00571    foreach (this.regs[i]) begin
00572 
00573       if (path == vmm_ral::BACKDOOR) begin
00574          this.regs[i].mirror(status, check, path);
00575          if (status != vmm_rw::IS_OK) return;
00576          continue;
00577       end
00578 
00579       // Find the first readable domain to
00580       // perform the update through
00581       this.regs[i].get_domains(domains);
00582       mirrored = 0;
00583       foreach (domains[j]) begin
00584          if (this.regs[i].get_rights(domains[j]) != vmm_ral::WO) begin
00585             this.regs[i].mirror(status, check, path, domains[0]);
00586             if (status == vmm_rw::IS_OK) begin
00587                mirrored = 1;
00588                break;
00589             end
00590          end
00591       end
00592       if (!mirrored) begin
00593          `vmm_error(this.log, $psprintf("Register \"%s\" could not be mirrored",
00594                                         regs[i].get_fullname()));
00595          if (status == vmm_rw::IS_OK) status = vmm_rw::ERROR;
00596          return;
00597       end
00598    end
00599 endtask: mirror
00600 
00601 
00602 task vmm_ral_block::readmemh(string filename);
00603 endtask: readmemh
00604 
00605 
00606 task vmm_ral_block::writememh(string filename);
00607 endtask: writememh
00608 
00609 
00610 function void vmm_ral_block::XsampleX(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr,
00611                                       int                           domain);
00612    this.sample(addr, domain);
00613 endfunction
00614 
00615 
00616 function void vmm_ral_block::sample(bit [`VMM_RAL_ADDR_WIDTH-1:0] addr,
00617                                     int                           domain);
00618    // Nothing to do in this base class
00619 endfunction
00620 
00621 
00622 function int unsigned vmm_ral_block::get_block_ID(); 
00623    get_block_ID =  this.__vmm_block_id;
00624 endfunction
00625 
00626 function vmm_ral_block vmm_ral_block::get_block_by_ID(int unsigned id); 
00627    if (__vmm_all_blocks.exists(id)) get_block_by_ID = __vmm_all_blocks[id];
00628    else get_block_by_ID = null;
00629 endfunction