SCCD_execute.alc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. include "primitives.alh"
  2. include "modelling.alh"
  3. include "object_operations.alh"
  4. include "utils.alh"
  5. include "random.alh"
  6. include "library.alh"
  7. include "io.alh"
  8. Element function resolve_function(location : String, data : Element):
  9. if (bool_not(dict_in(data["cache_operations"], location))):
  10. dict_add(data["cache_operations"], location, get_func_AL_model(import_node(location)))
  11. return data["cache_operations"][location]!
  12. Void function print_states(model : Element, data : Element):
  13. Element classes
  14. Element states
  15. Element class
  16. String state
  17. log("Current states:")
  18. classes = set_copy(data["classes"])
  19. while (read_nr_out(classes) > 0):
  20. class = set_pop(classes)
  21. log(string_join(string_join(string_join(" ", class["ID"]), " : "), read_attribute(model, class["type"], "name")))
  22. log(" Attributes: " + dict_to_string(class["attributes"]))
  23. states = set_copy(class["states"])
  24. log(" States:")
  25. while (read_nr_out(states) > 0):
  26. state = set_pop(states)
  27. log(string_join(" ", read_attribute(model, state, "name")))
  28. return!
  29. Element function filter(model : Element, set : Element, attribute_name : String, attribute_value : Element):
  30. Element keys
  31. String key
  32. Element result
  33. result = create_node()
  34. while (read_nr_out(set) > 0):
  35. key = set_pop(set)
  36. if (value_eq(read_attribute(model, key, attribute_name), attribute_value)):
  37. set_add(result, key)
  38. return result!
  39. Element function filter_exists(model : Element, set : Element, attribute_name : String):
  40. Element keys
  41. String key
  42. Element result
  43. result = create_node()
  44. while (read_nr_out(set) > 0):
  45. key = set_pop(set)
  46. if (element_neq(read_attribute(model, key, attribute_name), read_root())):
  47. set_add(result, key)
  48. return result!
  49. Element function expand_current_state(model : Element, state : String, data : Element):
  50. // Find the hierarchy of all current states, and select those that contain the currently selected state
  51. Element result
  52. Element current_states
  53. result = create_node()
  54. current_states = set_copy(data["classes"][data["current_class"]]["states"])
  55. Element hierarchy
  56. String deep_state
  57. while (read_nr_out(current_states) > 0):
  58. deep_state = set_pop(current_states)
  59. hierarchy = find_hierarchy(model, deep_state, data)
  60. // Got the hierarchy of one of the states
  61. if (set_in(hierarchy, state)):
  62. // This hierarchy contains the root state we are checking for, so add to set
  63. set_add(result, deep_state)
  64. return result!
  65. Element function expand_initial_state(model : Element, state : String, data : Element):
  66. String t
  67. t = read_type(model, state)
  68. if (t == "SCCD/CompositeState"):
  69. // Recurse further in the composite
  70. return expand_composite_state(model, state, data)!
  71. elif (t == "SCCD/ParallelState"):
  72. // Split up all components
  73. return expand_parallel_state(model, state, data)!
  74. elif (t == "SCCD/HistoryState"):
  75. // Reset the history
  76. // This is not really an initial state, but it is called in exactly the same places
  77. return data["classes"][data["current_class"]]["history"][get_parent(model, state)]!
  78. else:
  79. // Probably just an atomic, so return this one only
  80. Element result
  81. result = create_node()
  82. set_add(result, state)
  83. return result!
  84. Element function expand_composite_state(model : Element, composite_state : String, data : Element):
  85. // Resolve all initial states from a single composite state
  86. String initial
  87. // Fetch the initial state
  88. initial = set_pop(filter(model, allAssociationDestinations(model, composite_state, "SCCD/composite_children"), "isInitial", True))
  89. // Expand the initial state, depending on what it is
  90. return expand_initial_state(model, initial, data)!
  91. Element function expand_parallel_state(model : Element, parallel_state : String, data : Element):
  92. // Resolve all initial states from a single parallel state
  93. Element children
  94. Element result
  95. Element expanded_children
  96. children = allAssociationDestinations(model, parallel_state, "SCCD/parallel_children")
  97. result = create_node()
  98. while (read_nr_out(children) > 0):
  99. set_merge(result, expand_initial_state(model, set_pop(children), data))
  100. return result!
  101. Void function delete_class(model : Element, data : Element, identifier : String):
  102. // Stop a specific class instance, with attached statechart, from executing
  103. dict_delete(data["classes"], identifier)
  104. Void function start_class(model : Element, data : Element, class : String, identifier : String, parameters : Element):
  105. // Start up the class and assign its initial state to it
  106. // Create the data structure for a running class
  107. Element class_handle
  108. class_handle = create_node()
  109. dict_add(class_handle, "type", class)
  110. dict_add(class_handle, "ID", identifier)
  111. dict_add(class_handle, "timers", create_node())
  112. dict_add(data["classes"], class_handle["ID"], class_handle)
  113. String prev_class
  114. prev_class = data["current_class"]
  115. dict_overwrite(data, "current_class", identifier)
  116. // Add the current state of the class
  117. String initial_state
  118. // Should only be one behaviour linked to it!
  119. initial_state = set_pop(allAssociationDestinations(model, class, "SCCD/behaviour"))
  120. dict_add(class_handle, "states", expand_initial_state(model, initial_state, class_handle))
  121. // Initialize history for all composite states
  122. Element history
  123. Element cstates
  124. String cstate
  125. history = create_node()
  126. dict_add(class_handle, "history", history)
  127. cstates = allInstances(model, "SCCD/CompositeState")
  128. while (read_nr_out(cstates) > 0):
  129. cstate = set_pop(cstates)
  130. dict_add(history, cstate, expand_initial_state(model, cstate, class_handle))
  131. // Add all attributes
  132. Element attributes
  133. attributes = create_node()
  134. Element attrs
  135. attrs = allAssociationDestinations(model, class, "SCCD/class_attributes")
  136. while (read_nr_out(attrs) > 0):
  137. dict_add(attributes, read_attribute(model, set_pop(attrs), "name"), read_root())
  138. dict_add(class_handle, "attributes", attributes)
  139. // Invoke constructor
  140. Element constructor
  141. constructor = read_attribute(model, class, "constructor_body")
  142. if (element_neq(constructor, read_root())):
  143. // Constructor, so execute
  144. constructor = resolve_function(constructor, data)
  145. constructor(attributes, parameters)
  146. // Execute all entry actions
  147. Element init
  148. init = create_node()
  149. set_add(init, "")
  150. // Initial state before initialization is the set with an empty hierarchy
  151. // Empty set would not find any difference between the source and target
  152. execute_actions(model, init, set_copy(class_handle["states"]), data, "")
  153. dict_overwrite(data, "current_class", prev_class)
  154. return!
  155. Element function get_enabled_transitions(model : Element, state : String, data : Element):
  156. // Returns all enabled transitions
  157. Element result
  158. Element to_filter
  159. String attr
  160. String transition
  161. Element cond
  162. String evt_name
  163. Element evt
  164. Element events
  165. Element event_names
  166. Element event_parameters
  167. result = create_node()
  168. to_filter = allOutgoingAssociationInstances(model, state, "SCCD/transition")
  169. event_names = create_node()
  170. event_parameters = create_node()
  171. events = set_copy(data["events"])
  172. while (read_nr_out(events) > 0):
  173. evt = set_pop(events)
  174. evt_name = list_read(evt, 0)
  175. if (bool_not(set_in(event_names, evt_name))):
  176. // Not yet registered the event
  177. set_add(event_names, evt_name)
  178. dict_add(event_parameters, evt_name, create_node())
  179. // Add event parameters
  180. set_add(event_parameters[evt_name], list_read(evt, 1))
  181. while (read_nr_out(to_filter) > 0):
  182. transition = set_pop(to_filter)
  183. // Check event
  184. attr = read_attribute(model, transition, "event")
  185. if (bool_not(bool_or(element_eq(attr, read_root()), set_in(event_names, attr)))):
  186. // At least one enabled event is found
  187. continue!
  188. // Check after
  189. // Only an after if there was no event!
  190. if (bool_and(element_eq(attr, read_root()), read_attribute(model, transition, "after"))):
  191. if (dict_in(data["classes"][data["current_class"]]["timers"], transition)):
  192. // Registered timer already, let's check if it has expired
  193. if (float_gt(data["classes"][data["current_class"]]["timers"][transition], data["time_sim"])):
  194. // Not enabled yet
  195. continue!
  196. else:
  197. // Not registered even, so not enabled either
  198. continue!
  199. // Check condition, but depends on whether there was an event or not
  200. cond = read_attribute(model, transition, "cond")
  201. if (element_neq(cond, read_root())):
  202. // Got a condition, so resolve
  203. cond = resolve_function(cond, data)
  204. if (element_neq(attr, read_root())):
  205. // We have an event to take into account!
  206. Element params
  207. Element param
  208. params = set_copy(event_parameters[attr])
  209. while (read_nr_out(params) > 0):
  210. param = set_pop(params)
  211. if (element_neq(cond, read_root())):
  212. // Got a condition to check first
  213. if (bool_not(cond(data["classes"][data["current_class"]]["attributes"], param))):
  214. // Condition failed, so skip
  215. continue!
  216. // Fine to add this one with the specified parameters
  217. set_add(result, create_tuple(transition, param))
  218. else:
  219. // No event to think about, just add the transition
  220. if (element_neq(cond, read_root())):
  221. // Check the condition first
  222. if (bool_not(cond(data["classes"][data["current_class"]]["attributes"], read_root()))):
  223. // Condition false, so skip
  224. continue!
  225. // Fine to add this one without event parameters (no event)
  226. set_add(result, create_tuple(transition, read_root()))
  227. return result!
  228. Void function process_raised_event(model : Element, event : Element, parameter_action : Element, data : Element):
  229. String scope
  230. scope = read_attribute(model, event, "scope")
  231. if (scope == "cd"):
  232. // Is an event for us internally, so don't append
  233. // Instead, we process it directly
  234. String operation
  235. operation = read_attribute(model, event, "event")
  236. if (operation == "create_instance"):
  237. // Start up a new class of the desired type
  238. // Parameters of this call:
  239. // class -- type of the class to instantiate
  240. // identifier -- name of this instance, for future reference
  241. // parameters -- parameters for constructor
  242. String class
  243. String identifier
  244. Element parameters
  245. class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "name", list_read(parameter_action, 0)))
  246. identifier = list_read(parameter_action, 1)
  247. parameters = list_read(parameter_action, 2)
  248. start_class(model, data, class, identifier, parameters)
  249. elif (operation == "delete_instance"):
  250. // Delete the requested class
  251. String identifier
  252. identifier = list_read(parameter_action, 0)
  253. delete_class(model, data, identifier)
  254. else:
  255. set_add(data["events"], create_tuple(read_attribute(model, event, "event"), parameter_action))
  256. return !
  257. Element function execute_transition(model : Element, data : Element, transition_tuple : Element):
  258. // Execute the script (if any)
  259. Element script
  260. String transition
  261. Element event_parameter
  262. transition = list_read(transition_tuple, 0)
  263. event_parameter = list_read(transition_tuple, 1)
  264. script = read_attribute(model, transition, "script")
  265. if (element_neq(script, read_root())):
  266. script = resolve_function(script, data)
  267. script(data["classes"][data["current_class"]]["attributes"], event_parameter)
  268. // Raise events (if any)
  269. Element events
  270. String event
  271. events = allAssociationDestinations(model, transition, "SCCD/transition_raises")
  272. while (read_nr_out(events) > 0):
  273. event = set_pop(events)
  274. Element parameter_action
  275. parameter_action = read_attribute(model, event, "parameter")
  276. if (element_neq(parameter_action, read_root())):
  277. // Got a parameter to evaluate
  278. parameter_action = resolve_function(parameter_action, data)
  279. parameter_action = parameter_action(data["classes"][data["current_class"]]["attributes"], event_parameter)
  280. process_raised_event(model, event, parameter_action, data)
  281. // Find new set of states
  282. Element target_states
  283. Element source_states
  284. source_states = expand_current_state(model, readAssociationSource(model, transition), data)
  285. target_states = expand_initial_state(model, readAssociationDestination(model, transition), data)
  286. execute_actions(model, source_states, target_states, data, readAssociationSource(model, transition))
  287. return target_states!
  288. Boolean function step_class(model : Element, data : Element, class : String):
  289. // Find enabled transitions in a class and execute it, updating the state
  290. // Iterate over all current states, searching for enabled transitions
  291. // Search for enabled transitions in higher levels as well!
  292. Element states
  293. Element new_states
  294. String state
  295. Element transitions
  296. String transition
  297. Boolean transitioned
  298. Element hierarchy
  299. String current_state
  300. Boolean found
  301. if (bool_not(dict_in(data["classes"], class))):
  302. // Seems like this class was removed, so stop execution
  303. return False!
  304. // Notify everyone of the current class
  305. dict_overwrite(data, "current_class", class)
  306. states = set_copy(data["classes"][data["current_class"]]["states"])
  307. new_states = create_node()
  308. transitioned = False
  309. while (read_nr_out(states) > 0):
  310. state = set_pop(states)
  311. found = False
  312. // Loop over the hierarchy of this state and try to apply transitions
  313. hierarchy = find_hierarchy(model, state, data)
  314. while (read_nr_out(hierarchy) > 0):
  315. current_state = list_pop(hierarchy, 0)
  316. transitions = get_enabled_transitions(model, current_state, data)
  317. if (read_nr_out(transitions) > 0):
  318. // Found an enabled transition, so store that one
  319. transition = random_choice(transitions)
  320. // Execute transition
  321. set_merge(new_states, execute_transition(model, data, transition))
  322. // When leaving an orthogonal component, we must also pop all related states that might be processed in the future!
  323. Element leaving
  324. leaving = expand_current_state(model, current_state, data)
  325. set_difference(states, leaving)
  326. transitioned = True
  327. found = True
  328. break!
  329. if (bool_not(found)):
  330. // Nothing found, so stay in the current state
  331. set_add(new_states, state)
  332. // Update states
  333. dict_overwrite(data["classes"][data["current_class"]], "states", new_states)
  334. return transitioned!
  335. String function get_parent(model : Element, state : String):
  336. Element tmp_set
  337. tmp_set = allAssociationOrigins(model, state, "SCCD/composite_children")
  338. set_merge(tmp_set, allAssociationOrigins(model, state, "SCCD/parallel_children"))
  339. if (read_nr_out(tmp_set) > 0):
  340. return set_pop(tmp_set)!
  341. else:
  342. return ""!
  343. Element function find_hierarchy(model : Element, state : String, data : Element):
  344. // Try to cache as much as possible!
  345. if (bool_not(dict_in(data["cache_hierarchy"], state))):
  346. Element result
  347. if (state == ""):
  348. result = create_node()
  349. else:
  350. String parent
  351. parent = get_parent(model, state)
  352. // We have a parent, so take the parent list first
  353. result = find_hierarchy(model, parent, data)
  354. list_append(result, state)
  355. dict_add(data["cache_hierarchy"], state, result)
  356. return dict_copy(data["cache_hierarchy"][state])!
  357. Void function execute_actions(model : Element, source_states : Element, target_states : Element, data : Element, transition_source : String):
  358. Element exit
  359. Element entry
  360. exit = create_node()
  361. entry = create_node()
  362. source_states = set_copy(source_states)
  363. target_states = set_copy(target_states)
  364. // Add all exit and entry actions to the list of actions to execute
  365. // Do this by finding the common parent, and then doing all exit actions up to that node, and all entry actions up to the target_state
  366. // First, find the hierarchy!
  367. Element hierarchy_sources
  368. Element hierarchy_targets
  369. Element all_hierarchies
  370. hierarchy_sources = create_node()
  371. while (read_nr_out(source_states) > 0):
  372. set_add(hierarchy_sources, find_hierarchy(model, set_pop(source_states), data))
  373. hierarchy_targets = create_node()
  374. while (read_nr_out(target_states) > 0):
  375. set_add(hierarchy_targets, find_hierarchy(model, set_pop(target_states), data))
  376. all_hierarchies = set_copy(hierarchy_sources)
  377. set_merge(all_hierarchies, hierarchy_targets)
  378. // Difference these all lists, finding the first common entry
  379. Element iter_hierarchies
  380. Integer i
  381. String current
  382. Element hierarchy
  383. Boolean finished
  384. Integer transition_depth
  385. Integer lca_depth
  386. lca_depth = 0
  387. finished = False
  388. if (transition_source != ""):
  389. // Find out the level of the transition_source by fetching its hierarchy
  390. transition_depth = list_len(find_hierarchy(model, transition_source, data)) - 1
  391. // Now check for the least common ancestor
  392. while (bool_not(finished)):
  393. // Check the i-th element in both and see if they are equal
  394. current = ""
  395. iter_hierarchies = set_copy(all_hierarchies)
  396. while (read_nr_out(iter_hierarchies) > 0):
  397. hierarchy = set_pop(iter_hierarchies)
  398. // Exhausted one of the lists
  399. if (lca_depth >= list_len(hierarchy)):
  400. finished = True
  401. break!
  402. // Reached the same level as transition depth already, so no need to increase
  403. if (lca_depth == transition_depth):
  404. finished = True
  405. break!
  406. // First entry, so read out value as reference
  407. if (current == ""):
  408. current = list_read(hierarchy, lca_depth)
  409. // Check with reference element
  410. if (bool_not(value_eq(list_read(hierarchy, lca_depth), current))):
  411. finished = True
  412. break!
  413. // i-th element equal for all hierarchies, so go to next element
  414. if (bool_not(finished)):
  415. lca_depth = lca_depth + 1
  416. if (lca_depth < transition_depth):
  417. i = lca_depth
  418. else:
  419. i = transition_depth
  420. else:
  421. // Initial, so just set i to zero
  422. i = 0
  423. // Found the first differing element at position i
  424. // All elements remaining in hierarchy_source are to be traversed in REVERSE order for the exit actions
  425. // All elements remaining in hierarchy_target are to be traversed in NORMAL order for the entry actions
  426. // This is not that simple either, as we need to consider that some actions might already have been added to the list...
  427. // Add hierarchy_sources actions
  428. String state
  429. Element visited
  430. Element action
  431. Element spliced_hierarchy
  432. Element hierarchy_source
  433. Element hierarchy_target
  434. visited = create_node()
  435. while (read_nr_out(hierarchy_sources) > 0):
  436. // Get one of these hierarchies
  437. hierarchy_source = set_pop(hierarchy_sources)
  438. spliced_hierarchy = list_splice(hierarchy_source, i, list_len(hierarchy_source))
  439. while (list_len(spliced_hierarchy) > 0):
  440. state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
  441. if (set_in(visited, state)):
  442. // Already added this state, so don't bother
  443. continue!
  444. else:
  445. // New state, so prepend it to the list
  446. // Prepend, instead of append, as we want to do these operations in reverse order!
  447. list_insert(exit, state, 0)
  448. // Add this state as visited
  449. set_add(visited, state)
  450. // Add hierarchy_targets actions
  451. // Clear visited, just to be safe, though it should not matter
  452. visited = create_node()
  453. while (read_nr_out(hierarchy_targets) > 0):
  454. // Get one of these hierarchies
  455. hierarchy_target = set_pop(hierarchy_targets)
  456. spliced_hierarchy = list_splice(hierarchy_target, i, list_len(hierarchy_target))
  457. while (list_len(spliced_hierarchy) > 0):
  458. state = list_pop(spliced_hierarchy, list_len(spliced_hierarchy) - 1)
  459. if (set_in(visited, state)):
  460. // Already added this state, so don't bother
  461. continue!
  462. else:
  463. // New state, so append it to the list
  464. // Append, instead of prepend, as we want to do these operations in normal order!
  465. list_append(entry, state)
  466. // Add this state as visited, even though there might not have been an associated action
  467. set_add(visited, state)
  468. // Now we have a list of traversed states!
  469. // Start executing all their operations in order
  470. Element events
  471. String event
  472. // First do exit actions
  473. while (read_nr_out(exit) > 0):
  474. state = list_pop(exit, 0)
  475. // Set history when leaving
  476. if (read_type(model, state) == "SCCD/CompositeState"):
  477. dict_overwrite(data["classes"][data["current_class"]]["history"], state, expand_current_state(model, state, data))
  478. // Do exit actions
  479. action = read_attribute(model, state, "onExitScript")
  480. if (element_neq(action, read_root())):
  481. // Got a script, so execute!
  482. action = resolve_function(action, data)
  483. action(data["classes"][data["current_class"]]["attributes"])
  484. // Raise events
  485. events = allAssociationDestinations(model, state, "SCCD/onExitRaise")
  486. while (read_nr_out(events) > 0):
  487. event = set_pop(events)
  488. Element parameter_action
  489. parameter_action = read_attribute(model, event, "parameter")
  490. if (element_neq(parameter_action, read_root())):
  491. // Got a parameter to evaluate
  492. parameter_action = resolve_function(parameter_action, data)
  493. parameter_action = parameter_action(data["classes"][data["current_class"]]["attributes"])
  494. process_raised_event(model, event, parameter_action, data)
  495. // Unschedule after events
  496. Element timed_transitions
  497. timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
  498. while (read_nr_out(timed_transitions) > 0):
  499. dict_delete(data["classes"][data["current_class"]]["timers"], set_pop(timed_transitions))
  500. // Then do entry actions
  501. while (read_nr_out(entry) > 0):
  502. state = list_pop(entry, 0)
  503. // Do entry actions
  504. action = read_attribute(model, state, "onEntryScript")
  505. if (element_neq(action, read_root())):
  506. // Got a script, so execute!
  507. action = resolve_function(action, data)
  508. action(data["classes"][data["current_class"]]["attributes"])
  509. // Raise events
  510. events = allAssociationDestinations(model, state, "SCCD/onEntryRaise")
  511. while (read_nr_out(events) > 0):
  512. event = set_pop(events)
  513. Element parameter_action
  514. parameter_action = read_attribute(model, event, "parameter")
  515. if (element_neq(parameter_action, read_root())):
  516. // Got a parameter to evaluate
  517. parameter_action = resolve_function(parameter_action, data)
  518. parameter_action = parameter_action(data["classes"][data["current_class"]]["attributes"])
  519. process_raised_event(model, event, parameter_action, data)
  520. // Schedule after events
  521. Element timed_transitions
  522. String transition
  523. Element after
  524. timed_transitions = filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after")
  525. while (read_nr_out(timed_transitions) > 0):
  526. transition = set_pop(timed_transitions)
  527. after = resolve_function(read_attribute(model, transition, "after"), data)
  528. dict_add(data["classes"][data["current_class"]]["timers"], transition, float_addition(data["time_sim"], after(data["classes"][data["current_class"]]["attributes"])))
  529. return !
  530. Float function step(model : Element, data : Element):
  531. // Step through all classes
  532. Element classes
  533. Element class
  534. Float t_min
  535. Float t_current
  536. Boolean transitioned
  537. Element keys
  538. String key
  539. t_min = 999999.0
  540. classes = dict_keys(data["classes"])
  541. transitioned = False
  542. while (read_nr_out(classes) > 0):
  543. class = set_pop(classes)
  544. if (step_class(model, data, class)):
  545. transitioned = True
  546. if (bool_not(transitioned)):
  547. // Find minimum timer for this class, and store that
  548. keys = dict_keys(data["classes"][class]["timers"])
  549. while (read_nr_out(keys) > 0):
  550. key = set_pop(keys)
  551. t_current = data["classes"][class]["timers"][key]
  552. if (t_current < t_min):
  553. t_min = t_current
  554. if (transitioned):
  555. // Do another step, as we can transition
  556. return data["time_sim"]!
  557. else:
  558. return t_min!
  559. Boolean function main(model : Element):
  560. // Executes the provided SCCD model
  561. Element data
  562. data = create_node()
  563. dict_add(data, "classes", create_node())
  564. dict_add(data, "cache_operations", create_node())
  565. dict_add(data, "cache_hierarchy", create_node())
  566. dict_add(data, "current_class", "")
  567. Float time_0
  568. Float time_sim
  569. Float time_wallclock
  570. time_0 = time()
  571. time_sim = 0.0
  572. dict_add(data, "time_sim", 0.0)
  573. // Prepare for input
  574. output("Ready for input!")
  575. // Find initial
  576. String default_class
  577. default_class = set_pop(filter(model, allInstances(model, "SCCD/Class"), "default", True))
  578. // Start up the default class
  579. start_class(model, data, default_class, "main", read_root())
  580. Float timeout
  581. Element interrupt
  582. timeout = 0.0
  583. while (True):
  584. interrupt = input_timeout(timeout)
  585. if (value_eq(interrupt, "#EXIT#")):
  586. // Stop execution
  587. return True!
  588. dict_overwrite(data, "events", create_node())
  589. if (element_neq(interrupt, read_root())):
  590. // Got interrupt
  591. set_add(data["events"], create_tuple(interrupt, read_root()))
  592. output("Processed event, ready for more!")
  593. // Update the simulated time to the time of interrupt
  594. time_sim = time() - time_0
  595. // Else we timeout, and thus keep the time_sim
  596. dict_overwrite(data, "time_sim", time_sim)
  597. time_sim = step(model, data)
  598. if (float_gt(time_sim, data["time_sim"])):
  599. print_states(model, data)
  600. if (read_nr_out(data["classes"]) == 0):
  601. // No more active classes left: terminate!
  602. log("Finished SCCD execution")
  603. break!
  604. time_wallclock = time() - time_0
  605. timeout = time_sim - time_wallclock
  606. log("Pause for: " + cast_v2s(timeout))
  607. // We should never get here!
  608. return False!