VMM - RAL/vmm_mam.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);
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);
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);
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    // *NOT* IEEE compliant :-(
00380    this.in_use.delete();
00381 `else
00382    // Works in VCS2008.03
00383    this.in_use = '{};
00384 `endif
00385 endfunction: release_all_regions
00386 
00387 
00388 function string vmm_mam::psdisplay(string prefix);
00389    $sformat(psdisplay, "%sAllocated memory regions:\n", prefix);
00390    foreach (this.in_use[i]) begin
00391       $sformat(psdisplay, "%s%s   %s\n", psdisplay, prefix,
00392                this.in_use[i].psdisplay());
00393    end
00394 endfunction: psdisplay
00395 
00396 
00397 function vmm_mam_region vmm_mam::for_each(bit reset);
00398    if (reset) this.for_each_idx = -1;
00399 
00400    this.for_each_idx++;
00401 
00402    if (this.for_each_idx >= this.in_use.size()) begin
00403       return null;
00404    end
00405 
00406    return this.in_use[this.for_each_idx];
00407 endfunction: for_each
00408 
00409 
00410 function vmm_ral_mem vmm_mam::get_memory();
00411    return this.memory;
00412 endfunction: get_memory
00413 
00414 
00415 task vmm_mam_region::write(output vmm_rw::status_e              status,
00416                            input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00417                            input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00418                            input  vmm_ral::path_e               path,
00419                            input  string                        domain,
00420                            input  int                           data_id,
00421                            input  int                           scenario_id,
00422                            input  int                           stream_id);
00423 
00424    vmm_ral_mem mem = this.parent.get_memory();
00425 
00426    if (mem == null) begin
00427       `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");
00428       status = vmm_rw::ERROR;
00429       return;
00430    end
00431 
00432    if (offset > this.len) begin
00433       `vmm_error(this.parent.log,
00434                  $psprintf("Attempting to write to an offset outside of the allocated region (%0d > %0d)",
00435                            offset, this.len));
00436       status = vmm_rw::ERROR;
00437       return;
00438    end
00439 
00440    mem.write(status, offset + this.get_start_offset(), value,
00441             path, domain,
00442             data_id, scenario_id, stream_id);
00443 endtask: write
00444 
00445 
00446 task vmm_mam_region::read(output vmm_rw::status_e              status,
00447                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00448                           output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00449                           input  vmm_ral::path_e               path,
00450                           input  string                        domain,
00451                           input  int                           data_id,
00452                           input  int                           scenario_id,
00453                           input  int                           stream_id);
00454    vmm_ral_mem mem = this.parent.get_memory();
00455 
00456    if (mem == null) begin
00457       `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");
00458       status = vmm_rw::ERROR;
00459       return;
00460    end
00461 
00462    if (offset > this.len) begin
00463       `vmm_error(this.parent.log,
00464                  $psprintf("Attempting to read from an offset outside of the allocated region (%0d > %0d)",
00465                            offset, this.len));
00466       status = vmm_rw::ERROR;
00467       return;
00468    end
00469 
00470    mem.read(status, offset + this.get_start_offset(), value,
00471             path, domain,
00472             data_id, scenario_id, stream_id);
00473 endtask: read
00474 
00475 
00476 task vmm_mam_region::burst_write(output vmm_rw::status_e              status,
00477                                  input  vmm_ral_mem_burst             burst,
00478                                  input  bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00479                                  input  vmm_ral::path_e               path,
00480                                  input  string                        domain,
00481                                  input  int                           data_id,
00482                                  input  int                           scenario_id,
00483                                  input  int                           stream_id);
00484    vmm_ral_mem mem = this.parent.get_memory();
00485 
00486    if (mem == null) begin
00487       `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");
00488       status = vmm_rw::ERROR;
00489       return;
00490    end
00491 
00492    if (burst.start_offset > this.len ||
00493        burst.max_offset   > this.len) begin
00494       `vmm_error(this.parent.log,
00495                  $psprintf("Attempting to burst-write to an offset outside of the allocated region ([%0d:%0d] > %0d)",
00496                            burst.start_offset, burst.max_offset, this.len));
00497       status = vmm_rw::ERROR;
00498       return;
00499    end
00500 
00501    begin
00502       vmm_ral_mem_burst b = new burst;
00503       b.start_offset += this.get_start_offset();
00504       b.max_offset   += this.get_start_offset();
00505 
00506       mem.burst_write(status, b, value,
00507                       path, domain,
00508                       data_id, scenario_id, stream_id);
00509    end
00510 endtask: burst_write
00511 
00512 
00513 task vmm_mam_region::burst_read(output vmm_rw::status_e              status,
00514                                 input  vmm_ral_mem_burst             burst,
00515                                 output bit [`VMM_RAL_DATA_WIDTH-1:0] value[],
00516                                 input  vmm_ral::path_e               path,
00517                                 input  string                        domain,
00518                                 input  int                           data_id,
00519                                 input  int                           scenario_id,
00520                                 input  int                           stream_id);
00521    vmm_ral_mem mem = this.parent.get_memory();
00522 
00523    if (mem == null) begin
00524       `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");
00525       status = vmm_rw::ERROR;
00526       return;
00527    end
00528 
00529    if (burst.start_offset > this.len ||
00530        burst.max_offset   > this.len) begin
00531       `vmm_error(this.parent.log,
00532                  $psprintf("Attempting to burst-read from an offset outside of the allocated region ([%0d:%0d] > %0d)",
00533                            burst.start_offset, burst.max_offset, this.len));
00534       status = vmm_rw::ERROR;
00535       return;
00536    end
00537 
00538    begin
00539       vmm_ral_mem_burst b = new burst;
00540       b.start_offset += this.get_start_offset();
00541       b.max_offset   += this.get_start_offset();
00542 
00543       mem.burst_read(status, b, value,
00544                      path, domain,
00545                      data_id, scenario_id, stream_id);
00546    end
00547 endtask: burst_read
00548 
00549 
00550 task vmm_mam_region::poke(output vmm_rw::status_e              status,
00551                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00552                           input  bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00553                           input  int                           data_id,
00554                           input  int                           scenario_id,
00555                           input  int                           stream_id);
00556    vmm_ral_mem mem = this.parent.get_memory();
00557 
00558    if (mem == null) begin
00559       `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");
00560       status = vmm_rw::ERROR;
00561       return;
00562    end
00563 
00564    if (offset > this.len) begin
00565       `vmm_error(this.parent.log,
00566                  $psprintf("Attempting to poke to an offset outside of the allocated region (%0d > %0d)",
00567                            offset, this.len));
00568       status = vmm_rw::ERROR;
00569       return;
00570    end
00571 
00572    mem.poke(status, offset + this.get_start_offset(), value,
00573             data_id, scenario_id, stream_id);
00574 endtask: poke
00575 
00576 
00577 task vmm_mam_region::peek(output vmm_rw::status_e              status,
00578                           input  bit [`VMM_RAL_ADDR_WIDTH-1:0] offset,
00579                           output bit [`VMM_RAL_DATA_WIDTH-1:0] value,
00580                           input  int                           data_id,
00581                           input  int                           scenario_id,
00582                           input  int                           stream_id);
00583    vmm_ral_mem mem = this.parent.get_memory();
00584 
00585    if (mem == null) begin
00586       `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");
00587       status = vmm_rw::ERROR;
00588       return;
00589    end
00590 
00591    if (offset > this.len) begin
00592       `vmm_error(this.parent.log,
00593                  $psprintf("Attempting to peek from an offset outside of the allocated region (%0d > %0d)",
00594                            offset, this.len));
00595       status = vmm_rw::ERROR;
00596       return;
00597    end
00598 
00599    mem.peek(status, offset + this.get_start_offset(), value,
00600             data_id, scenario_id, stream_id);
00601 endtask: peek
00602 
00603 
00604 `endif  // VMM_MAM__SV