vmm_mam.sv

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

Intelligent Design Verification
Intelligent Design Verification
Project: VMM, Revision: 1.0.0
Copyright (c) 2008 Intelligent Design Verification.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included here:
http://www.intelligentdv.com/licenses/fdl.txt
doxygen
Doxygen Version: 1.5.6
Sat Oct 18 11:38:21 2008
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV