1-- EMACS settings: -*- tab-width: 2; indent-tabs-mode: t -*- 2-- vim: tabstop=2:shiftwidth=2:noexpandtab 3-- kate: tab-width 2; replace-tabs off; indent-width 2; 4-- ============================================================================= 5-- Authors: Patrick Lehmann 6-- Thomas B. Preusser 7-- 8-- Package: Simulation constants, functions and utilities. 9-- 10-- Description: 11-- ------------------------------------- 12-- .. TODO:: No documentation available. 13-- 14-- License: 15-- ============================================================================= 16-- Copyright 2007-2016 Technische Universitaet Dresden - Germany 17-- Chair of VLSI-Design, Diagnostics and Architecture 18-- 19-- Licensed under the Apache License, Version 2.0 (the "License"); 20-- you may not use this file except in compliance with the License. 21-- You may obtain a copy of the License at 22-- 23-- http://www.apache.org/licenses/LICENSE-2.0 24-- 25-- Unless required by applicable law or agreed to in writing, software 26-- distributed under the License is distributed on an "AS IS" BASIS, 27-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28-- See the License for the specific language governing permissions and 29-- limitations under the License. 30-- ============================================================================= 31 32use STD.TextIO.all; 33 34library IEEE; 35use IEEE.STD_LOGIC_1164.all; 36 37library PoC; 38use PoC.utils.all; 39use PoC.strings.all; 40use PoC.vectors.all; 41use PoC.physical.all; 42 43use PoC.sim_types.all; 44 45 46package sim_protected is 47 -- Simulation Task and Status Management 48 -- =========================================================================== 49 type T_SIM_STATUS is protected 50 -- Initializer and Finalizer 51 procedure initialize(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high); 52 procedure finalize; 53 54 -- Assertions 55 procedure fail(Message : string := ""); 56 procedure assertion(Condition : boolean; Message : string := ""); 57 procedure writeMessage(Message : string); 58 procedure writeReport; 59 60 -- Process Management 61 impure function registerProcess(Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; 62 impure function registerProcess(TestID : T_SIM_TEST_ID; Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID; 63 procedure deactivateProcess(procID : T_SIM_PROCESS_ID; SkipLowPriority : boolean := FALSE); 64 procedure stopAllProcesses; 65 procedure stopProcesses(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID); 66 67 -- Test Management 68 procedure createDefaultTest; 69 impure function createTest(Name : string) return T_SIM_TEST_ID; 70 procedure activateDefaultTest; 71 procedure finalizeTest; 72 procedure finalizeTest(TestID : T_SIM_TEST_ID); 73 74 -- Run Management 75 procedure stopAllClocks; 76 procedure stopClocks(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID); 77 78 impure function isStopped(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; 79 impure function isFinalized(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean; 80 impure function isAllFinalized return boolean; 81 end protected; 82end package; 83 84 85package body sim_protected is 86 -- Simulation process and Status Management 87 -- =========================================================================== 88 type T_SIM_STATUS_STATE is record 89 IsInitialized : boolean; 90 IsFinalized : boolean; 91 end record; 92 93 type T_SIM_STATUS is protected body 94 -- status 95 variable State : T_SIM_STATUS_STATE := (FALSE, FALSE); 96 97 variable Max_AssertFailures : natural := natural'high; 98 variable Max_SimulationRuntime : time := time'high; 99 100 -- Internal state variable to log a failure condition for final reporting. 101 -- Once de-asserted, this variable will never return to a value of true. 102 variable Passed : boolean := TRUE; 103 variable AssertCount : natural := 0; 104 variable FailedAssertCount : natural := 0; 105 106 -- Clock Management 107 variable MainProcessEnables : T_SIM_BOOLVEC(T_SIM_TEST_ID) := (others => TRUE); 108 variable MainClockEnables : T_SIM_BOOLVEC(T_SIM_TEST_ID) := (others => TRUE); 109 110 -- Process Management 111 variable ProcessCount : natural := 0; 112 variable ActiveProcessCount : natural := 0; 113 variable Processes : T_SIM_PROCESS_VECTOR(T_SIM_PROCESS_ID); 114 115 -- Test Management 116 variable TestCount : natural := 0; 117 variable ActiveTestCount : natural := 0; 118 variable Tests : T_SIM_TEST_VECTOR(T_SIM_TEST_ID); 119 120 -- Initializer 121 procedure init is 122 begin 123 if (State.IsInitialized = FALSE) then 124 if C_SIM_VERBOSE then report "init:" severity NOTE; end if; 125 State.IsInitialized := TRUE; 126 createDefaultTest; 127 end if; 128 end procedure; 129 130 procedure initialize(MaxAssertFailures : natural := natural'high; MaxSimulationRuntime : TIME := TIME'high) is 131 begin 132 if C_SIM_VERBOSE then report "initialize:" severity NOTE; end if; 133 init; 134 Max_AssertFailures := MaxAssertFailures; 135 Max_SimulationRuntime := MaxSimulationRuntime; 136 end procedure; 137 138 procedure finalize is 139 begin 140 if (State.IsFinalized = FALSE) then 141 if C_SIM_VERBOSE then report "finalize: " severity NOTE; end if; 142 State.IsFinalized := TRUE; 143 for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop 144 finalizeTest(i); 145 end loop; 146 writeReport; 147 end if; 148 end procedure; 149 150 procedure writeReport_Header is 151 variable LineBuffer : LINE; 152 begin 153 write(LineBuffer, ( string'("========================================"))); 154 write(LineBuffer, (LF & string'("POC TESTBENCH REPORT"))); 155 write(LineBuffer, (LF & string'("========================================"))); 156 writeline(output, LineBuffer); 157 end procedure; 158 159 procedure writeReport_TestReport(Prefix : string := "") is 160 variable LineBuffer : LINE; 161 begin 162 if (Tests(C_SIM_DEFAULT_TEST_ID).Status /= SIM_TEST_STATUS_CREATED) then 163 write(LineBuffer, Prefix & "Tests " & integer'image(TestCount + 1)); 164 write(LineBuffer, LF & Prefix & " " & str_ralign("-1", log10ceilnz(TestCount + 1) + 1) & ": " & C_SIM_DEFAULT_TEST_NAME); 165 else 166 write(LineBuffer, Prefix & "Tests " & integer'image(TestCount)); 167 end if; 168 for i in 0 to TestCount - 1 loop 169 write(LineBuffer, LF & Prefix & " " & str_ralign(integer'image(i), log10ceilnz(TestCount)) & ": " & str_trim(Tests(i).Name)); 170 end loop; 171 writeline(output, LineBuffer); 172 end procedure; 173 174 procedure writeReport_AssertReport(Prefix : string := "") is 175 variable LineBuffer : LINE; 176 begin 177 write(LineBuffer, Prefix & "Assertions " & integer'image(AssertCount)); 178 write(LineBuffer, LF & Prefix & " failed " & integer'image(FailedAssertCount) & ite((FailedAssertCount >= Max_AssertFailures), " Too many failed asserts!", "")); 179 writeline(output, LineBuffer); 180 end procedure; 181 182 procedure writeReport_ProcessReport(Prefix : string := "") is 183 variable LineBuffer : LINE; 184 begin 185 write(LineBuffer, Prefix & "Processes " & integer'image(ProcessCount)); 186 write(LineBuffer, LF & Prefix & " active " & integer'image(ActiveProcessCount)); 187 -- report killed processes 188 for i in 0 to ProcessCount - 1 loop 189 if ((Processes(i).Status = SIM_PROCESS_STATUS_ACTIVE) and (Processes(i).IsLowPriority = FALSE)) then 190 write(LineBuffer, LF & Prefix & " " & str_ralign(integer'image(i), log10ceilnz(ProcessCount)) & ": " & str_trim(Processes(i).Name)); 191 end if; 192 end loop; 193 writeline(output, LineBuffer); 194 end procedure; 195 196 procedure writeReport_RuntimeReport(Prefix : string := "") is 197 variable LineBuffer : LINE; 198 begin 199 write(LineBuffer, Prefix & "Runtime " & to_string(now, 1)); 200 writeline(output, LineBuffer); 201 end procedure; 202 203 procedure writeReport_SimulationResult is 204 variable LineBuffer : LINE; 205 begin 206 write(LineBuffer, ( string'("========================================"))); 207 if not Passed then write(LineBuffer, (LF & string'("SIMULATION RESULT = FAILED"))); 208 elsif AssertCount = 0 then write(LineBuffer, (LF & string'("SIMULATION RESULT = NO ASSERTS"))); 209 elsif Passed then write(LineBuffer, (LF & string'("SIMULATION RESULT = PASSED"))); 210 end if; 211 write(LineBuffer, (LF & string'("========================================"))); 212 writeline(output, LineBuffer); 213 end procedure; 214 215 procedure writeReport is 216 variable LineBuffer : LINE; 217 begin 218 writeReport_Header; 219 writeReport_TestReport(""); 220 write(LineBuffer, LF & "Overall"); 221 writeline(output, LineBuffer); 222 writeReport_AssertReport(" "); 223 writeReport_ProcessReport(" "); 224 writeReport_RuntimeReport(" "); 225 writeReport_SimulationResult; 226 end procedure; 227 228 procedure assertion(condition : boolean; Message : string := "") is 229 begin 230 AssertCount := AssertCount + 1; 231 if not condition then 232 fail(Message); 233 FailedAssertCount := FailedAssertCount + 1; 234 if (FailedAssertCount >= Max_AssertFailures) then 235 stopAllProcesses; 236 end if; 237 end if; 238 end procedure; 239 240 procedure fail(Message : string := "") is 241 begin 242 if (Message'length > 0) then 243 report Message severity ERROR; 244 end if; 245 Passed := FALSE; 246 end procedure; 247 248 procedure writeMessage(Message : string) is 249 variable LineBuffer : LINE; 250 begin 251 write(LineBuffer, Message); 252 writeline(output, LineBuffer); 253 end procedure; 254 255 procedure createDefaultTest is 256 variable Test : T_SIM_TEST; 257 begin 258 if (State.IsInitialized = FALSE) then 259 init; 260 end if; 261 if C_SIM_VERBOSE then report "createDefaultTest(" & C_SIM_DEFAULT_TEST_NAME & "):" severity NOTE; end if; 262 Test.ID := C_SIM_DEFAULT_TEST_ID; 263 Test.Name := resize(C_SIM_DEFAULT_TEST_NAME, T_SIM_TEST_NAME'length); 264 Test.Status := SIM_TEST_STATUS_CREATED; 265 Test.ProcessIDs := (others => 0); 266 Test.ProcessCount := 0; 267 Test.ActiveProcessCount := 0; 268 -- add to the internal structure 269 Tests(Test.ID) := Test; 270 end procedure; 271 272 impure function createTest(Name : string) return T_SIM_TEST_ID is 273 variable Test : T_SIM_TEST; 274 begin 275 if (State.IsInitialized = FALSE) then 276 init; 277 end if; 278 if C_SIM_VERBOSE then report "createTest(" & Name & "): => " & T_SIM_TEST_ID'image(TestCount) severity NOTE; end if; 279 Test.ID := TestCount; 280 Test.Name := resize(Name, T_SIM_TEST_NAME'length); 281 Test.Status := SIM_TEST_STATUS_ACTIVE; 282 Test.ProcessIDs := (others => 0); 283 Test.ProcessCount := 0; 284 Test.ActiveProcessCount := 0; 285 -- add to the internal structure 286 Tests(Test.ID) := Test; 287 TestCount := TestCount + 1; 288 ActiveTestCount := ActiveTestCount + 1; 289 -- return TestID for finalizeTest 290 return Test.ID; 291 end function; 292 293 procedure activateDefaultTest is 294 begin 295 if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_CREATED) then 296 Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ACTIVE; 297 ActiveTestCount := ActiveTestCount + 1; 298 end if; 299 end procedure; 300 301 procedure finalizeTest is 302 begin 303 finalizeTest(C_SIM_DEFAULT_TEST_ID); 304 end procedure; 305 306 procedure finalizeTest(TestID : T_SIM_TEST_ID) is 307 begin 308 if (TestID >= TestCount) then 309 report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; 310 return; 311 end if; 312 313 if TestID = C_SIM_DEFAULT_TEST_ID then 314 if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_CREATED) then 315 if C_SIM_VERBOSE then report "finalizeTest(" & integer'image(C_SIM_DEFAULT_TEST_ID) & "): inactive" severity NOTE; end if; 316 Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ENDED; 317 stopProcesses(C_SIM_DEFAULT_TEST_ID); 318 return; 319 elsif (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ACTIVE) then 320 if ActiveTestCount > 1 then 321 for ProcIdx in 0 to Tests(C_SIM_DEFAULT_TEST_ID).ProcessCount - 1 loop 322 deactivateProcess(Tests(C_SIM_DEFAULT_TEST_ID).ProcessIDs(ProcIdx), TRUE); 323 end loop; 324 Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ZOMBI; 325 return; 326 else 327 if C_SIM_VERBOSE then report "finalizeTest(" & integer'image(C_SIM_DEFAULT_TEST_ID) & "): active" severity NOTE; end if; 328 Tests(C_SIM_DEFAULT_TEST_ID).Status := SIM_TEST_STATUS_ENDED; 329 ActiveTestCount := ActiveTestCount - 1; 330 stopProcesses(C_SIM_DEFAULT_TEST_ID); 331 end if; 332 end if; 333 elsif (Tests(TestID).Status /= SIM_TEST_STATUS_ENDED) then 334 if C_SIM_VERBOSE then report "finalizeTest(TestID=" & T_SIM_TEST_ID'image(TestID) & "): " severity NOTE; end if; 335 Tests(TestID).Status := SIM_TEST_STATUS_ENDED; 336 ActiveTestCount := ActiveTestCount - 1; 337 338 if (Tests(TestID).ActiveProcessCount > 0) then 339 fail("Test " & integer'image(TestID) & " '" & str_trim(Tests(TestID).Name) & "' has still active process while finalizing:"); 340 for ProcIdx in 0 to Tests(TestID).ProcessCount - 1 loop 341 if (Processes(Tests(TestID).ProcessIDs(ProcIdx)).Status = SIM_PROCESS_STATUS_ACTIVE) then 342 report " " & Processes(Tests(TestID).ProcessIDs(ProcIdx)).Name severity WARNING; 343 end if; 344 end loop; 345 end if; 346 stopProcesses(TestID); 347 end if; 348 349 if ActiveTestCount = 0 then 350 finalize; 351 elsif ActiveTestCount = 1 then 352 if (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ACTIVE) then 353 finalizeTest(C_SIM_DEFAULT_TEST_ID); 354 elsif (Tests(C_SIM_DEFAULT_TEST_ID).Status = SIM_TEST_STATUS_ZOMBI) then 355 stopProcesses(C_SIM_DEFAULT_TEST_ID); 356 else 357 return; 358 end if; 359 finalize; 360 end if; 361 end procedure; 362 363 impure function registerProcess(Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is 364 begin 365 return registerProcess(C_SIM_DEFAULT_TEST_ID, Name, IsLowPriority); 366 end function; 367 368 impure function registerProcess(TestID : T_SIM_TEST_ID; Name : string; IsLowPriority : boolean := FALSE) return T_SIM_PROCESS_ID is 369 variable Proc : T_SIM_PROCESS; 370 variable TestProcID : T_SIM_TEST_ID; 371 begin 372 if (State.IsInitialized = FALSE) then 373 init; 374 end if; 375 if TestID = C_SIM_DEFAULT_TEST_ID then 376 activateDefaultTest; 377 end if; 378 379 if (TestID >= TestCount) then 380 report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; 381 return T_SIM_PROCESS_ID'high; 382 end if; 383 384 if C_SIM_VERBOSE then report "registerProcess(TestID=" & T_SIM_TEST_ID'image(TestID) & ", " & Name & "): => " & T_SIM_PROCESS_ID'image(ProcessCount) severity NOTE; end if; 385 Proc.ID := ProcessCount; 386 Proc.TestID := TestID; 387 Proc.Name := resize(Name, T_SIM_PROCESS_NAME'length); 388 Proc.Status := SIM_PROCESS_STATUS_ACTIVE; 389 Proc.IsLowPriority := IsLowPriority; 390 391 -- add process to list 392 Processes(Proc.ID) := Proc; 393 ProcessCount := ProcessCount + 1; 394 ActiveProcessCount := inc_if(not IsLowPriority, ActiveProcessCount); 395 -- add process to test 396 TestProcID := Tests(TestID).ProcessCount; 397 Tests(TestID).ProcessIDs(TestProcID) := Proc.ID; 398 Tests(TestID).ProcessCount := TestProcID + 1; 399 Tests(TestID).ActiveProcessCount := inc_if(not IsLowPriority, Tests(TestID).ActiveProcessCount); 400 -- return the process ID 401 return Proc.ID; 402 end function; 403 404 procedure deactivateProcess(ProcID : T_SIM_PROCESS_ID; SkipLowPriority : boolean := FALSE) is 405 variable TestID : T_SIM_TEST_ID; 406 begin 407 if (ProcID >= ProcessCount) then 408 report "ProcID (" & T_SIM_PROCESS_ID'image(ProcID) & ") is unknown." severity FAILURE; 409 return; 410 elsif (Processes(ProcID).IsLowPriority and SkipLowPriority) then 411 return; 412 end if; 413 414 TestID := Processes(ProcID).TestID; 415 -- deactivate process 416 if (Processes(ProcID).Status = SIM_PROCESS_STATUS_ACTIVE) then 417 if C_SIM_VERBOSE then report "deactivateProcess(ProcID=" & T_SIM_PROCESS_ID'image(ProcID) & "): TestID=" & T_SIM_TEST_ID'image(TestID) & " Name=" & str_trim(Processes(ProcID).Name) severity NOTE; end if; 418 Processes(ProcID).Status := SIM_PROCESS_STATUS_ENDED; 419 ActiveProcessCount := dec_if(not Processes(ProcID).IsLowPriority, ActiveProcessCount); 420 Tests(TestID).ActiveProcessCount := dec_if(not Processes(ProcID).IsLowPriority, Tests(TestID).ActiveProcessCount); 421 if (Tests(TestID).ActiveProcessCount = 0) then 422 finalizeTest(TestID); 423 end if; 424 end if; 425 end procedure; 426 427 procedure stopAllProcesses is 428 begin 429 if C_SIM_VERBOSE then report "stopAllProcesses:" severity NOTE; end if; 430 for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop 431 stopProcesses(i); 432 end loop; 433 end procedure; 434 435 procedure stopProcesses(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) is 436 begin 437 if (TestID >= TestCount) then 438 report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; 439 return; 440 end if; 441 442 if C_SIM_VERBOSE then report "stopProcesses(TestID=" & T_SIM_TEST_ID'image(TestID) & "): Name=" & str_trim(Tests(TestID).Name) severity NOTE; end if; 443 MainProcessEnables(TestID) := FALSE; 444 stopClocks(TestID); 445 end procedure; 446 447 procedure stopAllClocks is 448 begin 449 if C_SIM_VERBOSE then report "stopAllClocks:" severity NOTE; end if; 450 for i in C_SIM_DEFAULT_TEST_ID to TestCount - 1 loop 451 stopClocks(i); 452 end loop; 453 end procedure; 454 455 procedure stopClocks(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) is 456 begin 457 if (TestID >= TestCount) then 458 report "TestID (" & T_SIM_TEST_ID'image(TestID) & ") is unknown." severity FAILURE; 459 return; 460 end if; 461 462 if C_SIM_VERBOSE then report "stopClocks(TestID=" & T_SIM_TEST_ID'image(TestID) & "): Name=" & str_trim(Tests(TestID).Name) severity NOTE; end if; 463 MainClockEnables(TestID) := FALSE; 464 end procedure; 465 466 impure function isStopped(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is 467 begin 468 return not MainClockEnables(TestID); 469 end function; 470 471 impure function isFinalized(TestID : T_SIM_TEST_ID := C_SIM_DEFAULT_TEST_ID) return boolean is 472 begin 473 return (Tests(TestID).Status = SIM_TEST_STATUS_ENDED); 474 end function; 475 476 impure function isAllFinalized return boolean is 477 begin 478 if (State.IsFinalized = TRUE) then 479 if ActiveTestCount = 0 then 480 return TRUE; 481 end if; 482 report "isAllFinalized: " severity ERROR; 483 return FALSE; 484 else 485 return FALSE; 486 end if; 487 end function; 488 end protected body; 489end package body; 490