VMM OpenSource - sv/RAL/vmm_mam.sv

sv/RAL/vmm_mam.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 `ifndef VMM_MAM__SV
00024 `define VMM_MAM__SV
00025 
00026 
00027 typedef class vmm_mam_cfg;
00028 typedef class vmm_mam;
00029 
00030 typedef class vmm_ral_mem;
00031 typedef class vmm_ral_mem_burst;
00032 
00033 
00034 class vmm_mam_region;
00035    /*local*/ bit [63:0] Xstart_offsetX;  // Can't be local since function
00036    /*local*/ bit [63:0] Xend_offsetX;    // calls not supported in constraints
00037 
00038    local int unsigned len;
00039    local int unsigned n_bytes;
00040    local vmm_mam      parent;
00041 
00042    /*local*/ vmm_ral_vreg XvregX;
00043 
00044    extern /*local*/ function new(bit [63:0]   start_offset,
00045                                  bit [63:0]   end_offset,
00046                                  int unsigned len,
00047                                  int unsigned n_bytes,
00048                                  vmm_mam      parent);
00049 
00050    extern function bit [63:0] get_start_offset();
00051    extern function bit [63:0] get_end_offset();
00052 
00053    extern function int unsigned get_len();
00054    extern function int unsigned get_n_bytes();
00055 
00056    extern function string psdisplay(string prefix = "");
00057 
00058    extern function void release_region();
00059 
00060    extern function vmm_ral_mem get_memory();
00061    extern function vmm_ral_vreg get_virtual_registers();
00062 
00063    extern task write(output vmm_rw::status_e              status,
00064                      input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00065                      input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00066                      input  vmm_ral::path_e               path   = vmm_ral::DEFAULT,
00067                      input  string                        domain = "",
00068                      input  int                           data_id = -1,
00069                      input  int                           scenario_id = -1,
00070                      input  int                           stream_id = -1);
00071 
00072    extern task read(output vmm_rw::status_e              status,
00073                     input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00074                     output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00075                     input  vmm_ral::path_e               path   = vmm_ral::DEFAULT,
00076                     input  string                        domain = "",
00077                     input  int                           data_id = -1,
00078                     input  int                           scenario_id = -1,
00079                     input  int                           stream_id = -1);
00080 
00081    extern task burst_write(output vmm_rw::status_e              status,
00082                            input  vmm_ral_mem_burst             burst,
00083                            input  bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00084                            input  vmm_ral::path_e               path   = vmm_ral::DEFAULT,
00085                            input  string                        domain = "",
00086                            input  int                           data_id = -1,
00087                            input  int                           scenario_id = -1,
00088                            input  int                           stream_id = -1);
00089 
00090    extern task burst_read(output vmm_rw::status_e              status,
00091                           input  vmm_ral_mem_burst             burst,
00092                           output bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00093                           input  vmm_ral::path_e               path   = vmm_ral::DEFAULT,
00094                           input  string                        domain = "",
00095                           input  int                           data_id = -1,
00096                           input  int                           scenario_id = -1,
00097                           input  int                           stream_id = -1);
00098 
00099    extern task poke(output vmm_rw::status_e              status,
00100                     input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00101                     input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00102                     input  int                           data_id = -1,
00103                     input  int                           scenario_id = -1,
00104                     input  int                           stream_id = -1);
00105 
00106    extern task peek(output vmm_rw::status_e              status,
00107                     input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00108                     output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00109                     input  int                           data_id = -1,
00110                     input  int                           scenario_id = -1,
00111                     input  int                           stream_id = -1);
00112 endclass
00113 
00114 
00115 class vmm_mam_allocator;
00116    int unsigned len;
00117 
00118    rand bit [63:0] start_offset;
00119 
00120    bit [63:0] min_offset;
00121    bit [63:0] max_offset;
00122 
00123    vmm_mam_region in_use[$];
00124 
00125    constraint vmam_mam_allocator_valid {
00126       start_offset >= min_offset;
00127       start_offset <= max_offset - len + 1;
00128    }
00129 
00130    constraint vmam_mam_allocator_no_overlap {
00131       foreach (in_use[i]) {
00132          !(start_offset <= in_use[i].Xend_offsetX &&
00133            start_offset + len - 1 >= in_use[i].Xstart_offsetX);
00134       }
00135    }
00136 
00137 endclass
00138 
00139 
00140 class vmm_mam;
00141 
00142    typedef enum {GREEDY, THRIFTY} alloc_mode_e;
00143    typedef enum {BROAD, NEARBY}   locality_e;
00144 
00145    vmm_log log;
00146 
00147    local vmm_mam_cfg cfg;
00148 
00149    vmm_mam_allocator default_alloc;
00150    local vmm_ral_mem memory;
00151 
00152    local vmm_mam_region in_use[$];
00153    local int for_each_idx = -1;
00154 
00155    extern function new(string      name,
00156                        vmm_mam_cfg cfg,
00157                        vmm_ral_mem mem=null);
00158 
00159    extern function vmm_mam_cfg reconfigure(vmm_mam_cfg cfg = null);
00160 
00161    extern function vmm_mam_region reserve_region(bit [63:0]   start_offset,
00162                                                  int unsigned n_bytes);
00163    extern function vmm_mam_region request_region(int unsigned n_bytes,
00164                                                  vmm_mam_allocator alloc = null);
00165    extern function void release_region(vmm_mam_region region);
00166    extern function void release_all_regions();
00167 
00168 
00169    extern function string psdisplay(string prefix = "");
00170    extern function vmm_mam_region for_each(bit reset = 0);
00171    extern function vmm_ral_mem get_memory();
00172 
00173 endclass: vmm_mam
00174 
00175 
00176 class vmm_mam_cfg;
00177    rand int unsigned n_bytes;
00178 
00179    rand bit [63:0] start_offset;
00180    rand bit [63:0] end_offset;
00181 
00182    rand vmm_mam::alloc_mode_e mode;
00183    rand vmm_mam::locality_e   locality;
00184 
00185    constraint vmm_mam_cfg_valid {
00186       end_offset > start_offset;
00187       n_bytes < 64;
00188    }
00189 endclass
00190 
00191 
00192 
00193 //------------------------------------------------------------------
00194 //
00195 //  Implementation
00196 //
00197 
00198 function vmm_mam_region::new(bit [63:0] start_offset,
00199                              bit [63:0] end_offset,
00200                              int unsigned len,
00201                              int unsigned n_bytes,
00202                              vmm_mam      parent);
00203    this.Xstart_offsetX = start_offset;
00204    this.Xend_offsetX   = end_offset;
00205    this.len            = len;
00206    this.n_bytes        = n_bytes;
00207    this.parent         = parent;
00208    this.XvregX         = null;
00209 endfunction: new
00210 
00211 
00212 function bit [63:0] vmm_mam_region::get_start_offset();
00213    return this.Xstart_offsetX;
00214 endfunction: get_start_offset
00215 
00216 
00217 function bit [63:0] vmm_mam_region::get_end_offset();
00218    return this.Xend_offsetX;
00219 endfunction: get_end_offset
00220 
00221 
00222 function int unsigned vmm_mam_region::get_len();
00223    return this.len;
00224 endfunction: get_len
00225 
00226 
00227 function int unsigned vmm_mam_region::get_n_bytes();
00228    return this.n_bytes;
00229 endfunction: get_n_bytes
00230 
00231 
00232 function string vmm_mam_region::psdisplay(string prefix = "");
00233    $sformat(psdisplay, "%s['h%h:'h%h]", prefix,
00234             this.Xstart_offsetX, this.Xend_offsetX);
00235 endfunction: psdisplay
00236 
00237 
00238 function void vmm_mam_region::release_region();
00239    this.parent.release_region(this);
00240 endfunction
00241 
00242 
00243 function vmm_ral_mem vmm_mam_region::get_memory();
00244    return this.parent.get_memory();
00245 endfunction: get_memory
00246 
00247 
00248 function vmm_ral_vreg vmm_mam_region::get_virtual_registers();
00249    return this.XvregX;
00250 endfunction: get_virtual_registers
00251 
00252 
00253 function vmm_mam::new(string      name,
00254                       vmm_mam_cfg cfg,
00255                       vmm_ral_mem mem = null);
00256    this.log           = new("Memory Allocation Manager", name);
00257    this.cfg           = cfg;
00258    this.memory        = mem;
00259    this.default_alloc = new;
00260 endfunction: new
00261 
00262 
00263 function vmm_mam_cfg vmm_mam::reconfigure(vmm_mam_cfg cfg = null);
00264    if (cfg == null) return this.cfg;
00265 
00266    // Cannot reconfigure n_bytes
00267    if (cfg.n_bytes !== this.cfg.n_bytes) begin
00268       `vmm_error(this.log,
00269                  $psprintf("Cannot reconfigure Memory Allocation Manager with a different number of bytes (%0d !== %0d)",
00270                            cfg.n_bytes, this.cfg.n_bytes));
00271       return this.cfg;
00272    end
00273 
00274    // All currently allocated regions must fall within the new space
00275    foreach (this.in_use[i]) begin
00276       if (this.in_use[i].get_start_offset() < cfg.start_offset ||
00277           this.in_use[i].get_end_offset() > cfg.end_offset) begin
00278          `vmm_error(this.log,
00279                     $psprintf("Cannot reconfigure Memory Allocation Manager with a currently allocated region outside of the managed address range ([%0d:%0d] outside of [%0d:%0d])",
00280                               this.in_use[i].get_start_offset(),
00281                               this.in_use[i].get_end_offset(),
00282                               cfg.start_offset, cfg.end_offset));
00283          return this.cfg;
00284       end
00285    end
00286 
00287    reconfigure = this.cfg;
00288    this.cfg = cfg;
00289 endfunction: reconfigure
00290 
00291 
00292 function vmm_mam_region vmm_mam::reserve_region(bit [63:0]   start_offset,
00293                                                 int unsigned n_bytes);
00294    bit [63:0] end_offset;
00295 
00296    if (n_bytes == 0) begin
00297       `vmm_error(this.log, "Cannot reserve 0 bytes");
00298       return null;
00299    end
00300 
00301    if (start_offset < this.cfg.start_offset) begin
00302       `vmm_error(this.log, $psprintf("Cannot reserve before start of memory space: 'h%h < 'h%h",
00303                                      start_offset, this.cfg.start_offset));
00304       return null;
00305    end
00306 
00307    end_offset = start_offset + ((n_bytes-1) / this.cfg.n_bytes);
00308    n_bytes = (end_offset - start_offset + 1) * this.cfg.n_bytes;
00309 
00310    if (end_offset > this.cfg.end_offset) begin
00311       `vmm_error(this.log, $psprintf("Cannot reserve past end of memory space: 'h%h > 'h%h",
00312                                      end_offset, this.cfg.end_offset));
00313       return null;
00314    end
00315 
00316    `vmm_trace(this.log, $psprintf("Attempting to reserve ['h%h:'h%h]...",
00317                                   start_offset, end_offset));
00318 
00319    foreach (this.in_use[i]) begin
00320       if (start_offset <= this.in_use[i].get_end_offset() &&
00321           end_offset >= this.in_use[i].get_start_offset()) begin
00322          // Overlap!
00323          `vmm_error(this.log, $psprintf("Cannot reserve ['h%h:'h%h] because it overlaps with %s",
00324                                         start_offset, end_offset,
00325                                         this.in_use[i].psdisplay()));
00326          return null;
00327       end
00328 
00329       // Regions are stored in increasing start offset
00330       if (start_offset > this.in_use[i].get_start_offset()) begin
00331          reserve_region = new(start_offset, end_offset,
00332                               end_offset - start_offset + 1, n_bytes, this);
00333          this.in_use.insert(i, reserve_region);
00334          return reserve_region;
00335       end
00336    end
00337 
00338    reserve_region = new(start_offset, end_offset,
00339                         end_offset - start_offset + 1, n_bytes, this);
00340    this.in_use.push_back(reserve_region);
00341 endfunction: reserve_region
00342 
00343 
00344 function vmm_mam_region vmm_mam::request_region(int unsigned n_bytes,
00345                                                 vmm_mam_allocator alloc = null);
00346    if (alloc == null) alloc = this.default_alloc;
00347 
00348    alloc.len        = (n_bytes-1) / this.cfg.n_bytes + 1;
00349    alloc.min_offset = this.cfg.start_offset;
00350    alloc.max_offset = this.cfg.end_offset;
00351    alloc.in_use     = this.in_use;
00352 
00353    if (!alloc.randomize()) begin
00354       `vmm_error(this.log, "Unable to randomize allocator");
00355       return null;
00356    end
00357 
00358    return reserve_region(alloc.start_offset, n_bytes);
00359 endfunction: request_region
00360 
00361 
00362 function void vmm_mam::release_region(vmm_mam_region region);
00363 
00364    if (region == null) return;
00365 
00366    foreach (this.in_use[i]) begin
00367       if (this.in_use[i] == region) begin
00368          this.in_use.delete(i);
00369          return;
00370       end
00371    end
00372    `vmm_error(this.log, region.psdisplay("Attempting to release unallocated region "));
00373 endfunction: release_region
00374 
00375 
00376 function void vmm_mam::release_all_regions();
00377 `ifdef VCS2006_06
00378    // Work-around for NYI feature in VCS2006.06
00379    // but IEEE 1800-2009 compliant
00380    this.in_use.delete();
00381 `else
00382    // Works in VCS2008.03 or later
00383    // IEEE 1800-2005 compliant
00384    this.in_use = '{};
00385 `endif
00386 endfunction: release_all_regions
00387 
00388 
00389 function string vmm_mam::psdisplay(string prefix = "");
00390    $sformat(psdisplay, "%sAllocated memory regions:\n", prefix);
00391    foreach (this.in_use[i]) begin
00392       $sformat(psdisplay, "%s%s   %s\n", psdisplay, prefix,
00393                this.in_use[i].psdisplay());
00394    end
00395 endfunction: psdisplay
00396 
00397 
00398 function vmm_mam_region vmm_mam::for_each(bit reset = 0);
00399    if (reset) this.for_each_idx = -1;
00400 
00401    this.for_each_idx++;
00402 
00403    if (this.for_each_idx >= this.in_use.size()) begin
00404       return null;
00405    end
00406 
00407    return this.in_use[this.for_each_idx];
00408 endfunction: for_each
00409 
00410 
00411 function vmm_ral_mem vmm_mam::get_memory();
00412    return this.memory;
00413 endfunction: get_memory
00414 
00415 
00416 task vmm_mam_region::write(output vmm_rw::status_e              status,
00417                            input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00418                            input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00419                            input  vmm_ral::path_e               path = vmm_ral::DEFAULT,
00420                            input  string                        domain = "",
00421                            input  int                           data_id = -1,
00422                            input  int                           scenario_id = -1,
00423                            input  int                           stream_id = -1);
00424 
00425    vmm_ral_mem mem = this.parent.get_memory();
00426 
00427    if (mem == null) begin
00428       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::write() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00429       status = vmm_rw::ERROR;
00430       return;
00431    end
00432 
00433    if (offset > this.len) begin
00434       `vmm_error(this.parent.log,
00435                  $psprintf("Attempting to write to an offset outside of the allocated region (%0d > %0d)",
00436                            offset, this.len));
00437       status = vmm_rw::ERROR;
00438       return;
00439    end
00440 
00441    mem.write(status, offset + this.get_start_offset(), value,
00442             path, domain,
00443             data_id, scenario_id, stream_id);
00444 endtask: write
00445 
00446 
00447 task vmm_mam_region::read(output vmm_rw::status_e              status,
00448                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00449                           output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00450                           input  vmm_ral::path_e               path = vmm_ral::DEFAULT,
00451                           input  string                        domain = "",
00452                           input  int                           data_id = -1,
00453                           input  int                           scenario_id = -1,
00454                           input  int                           stream_id = -1);
00455    vmm_ral_mem mem = this.parent.get_memory();
00456 
00457    if (mem == null) begin
00458       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::read() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00459       status = vmm_rw::ERROR;
00460       return;
00461    end
00462 
00463    if (offset > this.len) begin
00464       `vmm_error(this.parent.log,
00465                  $psprintf("Attempting to read from an offset outside of the allocated region (%0d > %0d)",
00466                            offset, this.len));
00467       status = vmm_rw::ERROR;
00468       return;
00469    end
00470 
00471    mem.read(status, offset + this.get_start_offset(), value,
00472             path, domain,
00473             data_id, scenario_id, stream_id);
00474 endtask: read
00475 
00476 
00477 task vmm_mam_region::burst_write(output vmm_rw::status_e              status,
00478                                  input  vmm_ral_mem_burst             burst,
00479                                  input  bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00480                                  input  vmm_ral::path_e               path = vmm_ral::DEFAULT,
00481                                  input  string                        domain = "",
00482                                  input  int                           data_id = -1,
00483                                  input  int                           scenario_id = -1,
00484                                  input  int                           stream_id =-1);
00485    vmm_ral_mem mem = this.parent.get_memory();
00486 
00487    if (mem == null) begin
00488       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::burst_write() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00489       status = vmm_rw::ERROR;
00490       return;
00491    end
00492 
00493    if (burst.start_offset > this.len ||
00494        burst.max_offset   > this.len) begin
00495       `vmm_error(this.parent.log,
00496                  $psprintf("Attempting to burst-write to an offset outside of the allocated region ([%0d:%0d] > %0d)",
00497                            burst.start_offset, burst.max_offset, this.len));
00498       status = vmm_rw::ERROR;
00499       return;
00500    end
00501 
00502    begin
00503       vmm_ral_mem_burst b = new burst;
00504       b.start_offset += this.get_start_offset();
00505       b.max_offset   += this.get_start_offset();
00506 
00507       mem.burst_write(status, b, value,
00508                       path, domain,
00509                       data_id, scenario_id, stream_id);
00510    end
00511 endtask: burst_write
00512 
00513 
00514 task vmm_mam_region::burst_read(output vmm_rw::status_e              status,
00515                                 input  vmm_ral_mem_burst             burst,
00516                                 output bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00517                                 input  vmm_ral::path_e               path = vmm_ral::DEFAULT,
00518                                 input  string                        domain = "",
00519                                 input  int                           data_id = -1,
00520                                 input  int                           scenario_id = -1,
00521                                 input  int                           stream_id = -1);
00522    vmm_ral_mem mem = this.parent.get_memory();
00523 
00524    if (mem == null) begin
00525       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::burst_read() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00526       status = vmm_rw::ERROR;
00527       return;
00528    end
00529 
00530    if (burst.start_offset > this.len ||
00531        burst.max_offset   > this.len) begin
00532       `vmm_error(this.parent.log,
00533                  $psprintf("Attempting to burst-read from an offset outside of the allocated region ([%0d:%0d] > %0d)",
00534                            burst.start_offset, burst.max_offset, this.len));
00535       status = vmm_rw::ERROR;
00536       return;
00537    end
00538 
00539    begin
00540       vmm_ral_mem_burst b = new burst;
00541       b.start_offset += this.get_start_offset();
00542       b.max_offset   += this.get_start_offset();
00543 
00544       mem.burst_read(status, b, value,
00545                      path, domain,
00546                      data_id, scenario_id, stream_id);
00547    end
00548 endtask: burst_read
00549 
00550 
00551 task vmm_mam_region::poke(output vmm_rw::status_e              status,
00552                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00553                           input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00554                           input  int                           data_id = -1,
00555                           input  int                           scenario_id = -1,
00556                           input  int                           stream_id = -1);
00557    vmm_ral_mem mem = this.parent.get_memory();
00558 
00559    if (mem == null) begin
00560       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::poke() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00561       status = vmm_rw::ERROR;
00562       return;
00563    end
00564 
00565    if (offset > this.len) begin
00566       `vmm_error(this.parent.log,
00567                  $psprintf("Attempting to poke to an offset outside of the allocated region (%0d > %0d)",
00568                            offset, this.len));
00569       status = vmm_rw::ERROR;
00570       return;
00571    end
00572 
00573    mem.poke(status, offset + this.get_start_offset(), value,
00574             data_id, scenario_id, stream_id);
00575 endtask: poke
00576 
00577 
00578 task vmm_mam_region::peek(output vmm_rw::status_e              status,
00579                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00580                           output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00581                           input  int                           data_id = -1,
00582                           input  int                           scenario_id = -1,
00583                           input  int                           stream_id = -1);
00584    vmm_ral_mem mem = this.parent.get_memory();
00585 
00586    if (mem == null) begin
00587       `vmm_error(this.parent.log, "Cannot use vmm_mam_region::peek() on a region that was allocated by a Memory Allocation Manager that was not associated with a vmm_ral_mem instance");
00588       status = vmm_rw::ERROR;
00589       return;
00590    end
00591 
00592    if (offset > this.len) begin
00593       `vmm_error(this.parent.log,
00594                  $psprintf("Attempting to peek from an offset outside of the allocated region (%0d > %0d)",
00595                            offset, this.len));
00596       status = vmm_rw::ERROR;
00597       return;
00598    end
00599 
00600    mem.peek(status, offset + this.get_start_offset(), value,
00601             data_id, scenario_id, stream_id);
00602 endtask: peek
00603 
00604 
00605 `endif  // VMM_MAM__SV