00001 //---------------------------------------------------------------------- 00002 // Copyright 2007-2008 Mentor Graphics Corporation 00003 // Copyright 2007-2008 Cadence Design Systems, 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 typedef enum {TYPE_REQ, TYPE_LOCK} REQ_TYPE; 00022 typedef enum {FIFO, WEIGHTED, RANDOM} ARBITRATION_TYPE; 00023 00024 typedef class ovm_scenario_base; 00025 typedef class ovm_scenario_driver_base; 00026 00027 class ovm_scenario_controller_base extends ovm_threaded_component; 00028 00029 protected REQ_TYPE arb_req_q[$]; 00030 protected ovm_scenario_base arb_scen_q[$]; 00031 protected ovm_scenario_base lock_list[$]; 00032 local ovm_scenario_controller_base m_push_if; 00033 00034 // Weighted Priority 00035 local ARBITRATION_TYPE arbitration = FIFO; 00036 00038 00039 function new (string name, ovm_component parent, ovm_scenario_controller_base push_if = null); 00040 super.new(name, parent); 00041 m_push_if = push_if; 00042 endfunction // new 00043 00045 // 00046 // Local functions 00047 // 00049 00050 local function string display_queues(); 00051 string s; 00052 00053 $sformat(s, " -- arb i/type/id: "); 00054 foreach (arb_scen_q[i]) begin 00055 $sformat(s, "%s %0d/%s/%0d ", s, i, arb_req_q[i], arb_scen_q[i].get_id()); 00056 end 00057 $sformat(s, "%s\n -- lock i/id: ", s); 00058 foreach (lock_list[i]) begin 00059 $sformat(s, "%s %0d/%0d ", s, i, lock_list[i].get_id()); 00060 end 00061 return(s); 00062 endfunction 00063 00064 00066 // 00067 // arb_lock_grant() 00068 // Find all queued lock requests and grant them if 00069 // possible 00071 00072 local function void arb_lock_grant(); 00073 int i, temp; 00074 00075 for (i = 0; i < arb_scen_q.size(); i++) begin 00076 00077 // If this is a lock request, and the lock is available, 00078 // then grant the lock 00079 00080 temp = 0; 00081 if (i < arb_scen_q.size()) begin 00082 if (arb_req_q[i] == TYPE_LOCK) begin 00083 temp = is_blocked(arb_scen_q[i]) == 0; 00084 end 00085 end 00086 00087 00088 while (temp) begin 00089 lock_list.push_back(arb_scen_q[i]); 00090 arb_scen_q[i].grant(null); 00091 arb_req_q.delete(i); 00092 arb_scen_q.delete(i); 00093 00094 temp = 0; 00095 if (i < arb_scen_q.size()) 00096 if (arb_req_q[i] == TYPE_LOCK) 00097 temp = is_blocked(arb_scen_q[i]) == 0; 00098 end 00099 end // for (i = 0; i < arb_scen_q.size(); i++) 00100 endfunction // arb_lock_grant 00101 00103 // 00104 // choose_next_request 00105 // When a driver requests an operation, this funciton 00106 // must find the next available, unlocked, relevant scenario 00108 00109 local function int choose_next_request(); 00110 int i, temp; 00111 int avail_scen_count; 00112 int sum_priority_val; 00113 int avail_scenarios[$]; 00114 00115 avail_scen_count = 0; 00116 for (i = 0; i < arb_scen_q.size(); i++) begin 00117 // If this is a lock request, and the lock is available, 00118 // then grant the lock 00119 00120 temp = 0; 00121 if (i < arb_scen_q.size()) begin 00122 if (arb_req_q[i] == TYPE_LOCK) begin 00123 temp = is_blocked(arb_scen_q[i]) == 0; 00124 end 00125 end 00126 while (temp) begin 00127 lock_list.push_back(arb_scen_q[i]); 00128 arb_scen_q[i].grant(null); 00129 arb_req_q.delete(i); 00130 arb_scen_q.delete(i); 00131 00132 temp = 0; 00133 if (i < arb_scen_q.size()) begin 00134 if (arb_req_q[i] == TYPE_LOCK) begin 00135 temp = is_blocked(arb_scen_q[i]) == 0; 00136 end 00137 end 00138 end 00139 00140 // choose the first i that is ready and is a request 00141 if (i < arb_scen_q.size()) 00142 if (arb_req_q[i] == TYPE_REQ) 00143 if (is_blocked(arb_scen_q[i]) == 0) 00144 if (arb_scen_q[i].is_relevant() == 1) begin 00145 if (arbitration == FIFO) return (i); 00146 else avail_scenarios.push_back(i); 00147 end 00148 end // for (i = 0; i < arb_scen_q.size(); i++) 00149 00150 // Return immediately if there are 0 or 1 available scenarios 00151 if (arbitration == FIFO) return (-1); 00152 if (avail_scenarios.size() < 1) return (-1); 00153 if (avail_scenarios.size() == 1) return (avail_scenarios[0]); 00154 00155 // If any locks are in place, then the available queue must 00156 // be checked to see if a lock prevents any scenario from proceeding 00157 if (lock_list.size() > 0) begin 00158 for (i = 0; i < avail_scenarios.size(); i++) begin 00159 if (is_blocked(arb_scen_q[avail_scenarios[i]]) != 0) begin 00160 avail_scenarios.delete(i); 00161 i--; 00162 end 00163 end 00164 if (avail_scenarios.size() < 1) return (-1); 00165 if (avail_scenarios.size() == 1) return (avail_scenarios[0]); 00166 end 00167 00169 // Weighted Priority Distribution 00171 if (arbitration == WEIGHTED) begin 00172 sum_priority_val = 0; 00173 for (i = 0; i < avail_scenarios.size(); i++) begin 00174 sum_priority_val += arb_scen_q[avail_scenarios[i]].get_weighted_priority(); 00175 end 00176 00177 // Pick an available scenario based on weighted priorities of available scenarios 00178 temp = $urandom_range(sum_priority_val-1, 0); 00179 sum_priority_val = 0; 00180 for (i = 0; i < avail_scenarios.size(); i++) begin 00181 if ((arb_scen_q[avail_scenarios[i]].get_weighted_priority() + 00182 sum_priority_val) > temp) begin 00183 return (avail_scenarios[i]); 00184 end 00185 sum_priority_val += arb_scen_q[avail_scenarios[i]].get_weighted_priority(); 00186 end 00187 end // if (arbitration == WEIGHTED) 00188 00190 // Random Distribution 00192 if (arbitration == RANDOM) begin 00193 i = $urandom_range(avail_scenarios.size()-1, 0); 00194 return (avail_scenarios[i]); 00195 return avail_scenarios[i]; 00196 end 00197 ovm_report_fatal("Scenario controller", "Internal error: Failed to choose scenario"); 00198 endfunction 00199 00200 function void set_arbitration(ARBITRATION_TYPE val); 00201 arbitration = val; 00202 endfunction // void 00203 00205 // 00206 // is_child 00207 // Determine if a scenario is a child of a parent 00209 00210 function bit is_child (ovm_scenario_base parent, ovm_scenario_base child); 00211 ovm_scenario_base scenario_ptr; 00212 00213 scenario_ptr = child.get_parent_scenario(); 00214 while (scenario_ptr != null) begin 00215 if (scenario_ptr.get_id() == (parent.get_id())) begin 00216 return (1); 00217 end 00218 scenario_ptr = scenario_ptr.get_parent_scenario(); 00219 end 00220 return (0); 00221 endfunction // bit 00222 00224 // 00225 // is_blocked 00226 // Determine if a scenario is locked out 00228 00229 function bit is_blocked(ovm_scenario_base scenario_ptr); 00230 00231 if (scenario_ptr == null) 00232 ovm_report_fatal("ovm_scenario_controller", "is_blocked passed null scenario_ptr"); 00233 00234 if (m_push_if == null) begin 00235 foreach (lock_list[i]) begin 00236 if ((lock_list[i].get_id() != scenario_ptr.get_id()) && 00237 (is_child(lock_list[i], scenario_ptr) == 0)) begin 00238 return (1); 00239 end 00240 end 00241 return (0); 00242 end else begin 00243 return (m_push_if.is_blocked(scenario_ptr)); 00244 end 00245 endfunction // is_locked 00246 00248 // 00249 // lock_req 00250 // Called by a scenario to request a lock. Puts 00251 // the lock request onto the arbitration queue 00253 00254 function void lock_req(ovm_scenario_base scenario_ptr); 00255 if (scenario_ptr == null) 00256 ovm_report_fatal("ovm_scenario_controller", "lock_req passed null scenario_ptr"); 00257 00258 if (m_push_if == null) begin 00259 arb_scen_q.push_back(scenario_ptr); 00260 arb_req_q.push_back(TYPE_LOCK); 00261 end else begin 00262 m_push_if.lock_req(scenario_ptr); 00263 end 00264 endfunction 00265 00267 // 00268 // unlock_req 00269 // Called by a scenario to request an unlock. This 00270 // will remove a lock for this scenario if it exists 00272 00273 function void unlock_req(ovm_scenario_base scenario_ptr); 00274 if (scenario_ptr == null) 00275 ovm_report_fatal("ovm_scenario_controller", "unlock_req passed null scenario_ptr"); 00276 if (m_push_if == null) begin 00277 foreach (lock_list[i]) begin 00278 if (lock_list[i].get_id() == scenario_ptr.get_id()) begin 00279 lock_list.delete(i); 00280 return; 00281 end 00282 end 00283 end else begin 00284 m_push_if.unlock_req(scenario_ptr); 00285 end 00286 endfunction 00287 00289 // 00290 // request 00291 // Called by a scenario to request a ovm_transaction 00292 // to be executed by the driver 00294 00295 function void request(ovm_scenario_base scenario_ptr); 00296 if (scenario_ptr == null) 00297 ovm_report_fatal("ovm_scenario_controller", "request passed null scenario_ptr"); 00298 00299 if (m_push_if == null) begin 00300 arb_scen_q.push_back(scenario_ptr); 00301 arb_req_q.push_back(TYPE_REQ); 00302 end else begin 00303 m_push_if.request(scenario_ptr); 00304 end // else: !if(lock_list[i].get_id() == scenario_ptr.get_id()) 00305 endfunction 00306 00308 // 00309 // Driver request 00310 // Called by a driver to request a ovm_transaction 00312 00313 task driver_request (input ovm_scenario_driver_base driver_ptr, 00314 output ovm_scenario_base chosen_scen, input bit non_blocking = 0 ); 00315 ovm_scenario_base scenario_ptr; 00316 int select_num, req_size; 00317 00318 if (driver_ptr == null) 00319 ovm_report_fatal("ovm_scenario_controller", "driver_request passed null driver ptr"); 00320 00321 #0; //Allow scenario requests in before arbitrating. Needed for weighted distribution 00322 select_num = choose_next_request(); 00323 00324 // Non-blocking logic - if no item availabe, and a non-blocking 00325 // request was made, then return a null 00326 if ((select_num < 0) && (non_blocking == 1)) begin 00327 chosen_scen = null; 00328 return; 00329 end 00330 00331 while (select_num < 0) begin 00332 // If we just granted a lock, allow the scenario 00333 // to put a request in the queue 00334 req_size = arb_scen_q.size(); 00335 wait (arb_scen_q.size() != req_size); 00336 select_num = choose_next_request(); 00337 end 00338 00339 // If no scenario was chosen, then return null 00340 if (select_num < 0) begin 00341 chosen_scen = null; 00342 return; 00343 end 00344 00345 scenario_ptr = arb_scen_q[select_num]; 00346 arb_scen_q.delete(select_num); 00347 arb_req_q.delete(select_num); 00348 00349 // return the driver pointer when granting the scenario 00350 scenario_ptr.grant(driver_ptr); 00351 // return the scenario pointer to the driver 00352 chosen_scen = scenario_ptr; 00353 endtask // driver_request 00354 00355 virtual task run(); 00356 return; 00357 endtask // run 00358 00359 endclass 00360 00361 00362 class ovm_scenario_controller #(type REQ = ovm_transaction, 00363 type RSP = ovm_transaction) extends ovm_scenario_controller_base; 00364 00365 // For driver ports to connect to the request_driver 00366 ovm_blocking_get_export #(REQ) get_req_export; 00367 ovm_blocking_put_export #(RSP) put_rsp_export; 00368 00369 // For stimulus generators to connect to the stimulus scenario 00370 ovm_blocking_put_export #(REQ) put_req_export; 00371 00372 request_driver #(REQ, RSP) req_driver; 00373 ovm_stimulus_scenario #(REQ) stimulus_scenario; 00374 00375 function new (string name, ovm_component parent, ovm_scenario_controller_base push_if = null); 00376 super.new(name, parent, push_if); 00377 req_driver = new("nscenr_drv", this); 00378 req_driver.set_scenario_controller(this); 00379 stimulus_scenario = new("scenario_stim", this); 00380 get_req_export = new("reqdrv_req_export", this); 00381 put_rsp_export = new("reqdrv_rsp_export", this); 00382 put_req_export = new("stimscen_req_export", this); 00383 endfunction // new 00384 00385 function void connect(); 00386 get_req_export.connect(req_driver.get_req_export); 00387 put_rsp_export.connect(req_driver.put_rsp_export); 00388 put_req_export.connect(stimulus_scenario.put_req_export); 00389 endfunction 00390 00391 task run(); 00392 stimulus_scenario.start(this, null); 00393 endtask // run 00394 00395 endclass 00396
![]() Intelligent Design Verification Project: OVM, Revision: 1.1.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.4.6 Mon Sep 29 14:20:12 2008 |