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 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 Version: 1.5.6 Sat Oct 18 11:38:21 2008 |