96 lines
3.1 KiB
Python
96 lines
3.1 KiB
Python
from ScEpTIC.AST.elements.instructions.other_operations import CallOperation
|
|
from ScEpTIC.analysis.utils.saved_state_calculator import SavedStateCalculator
|
|
from ScEpTIC.analysis.utils.settings_cache import SettingsCache
|
|
|
|
|
|
class MaxStateIdentifier:
|
|
"""
|
|
Utility that identifies the volatile state maximum size.
|
|
"""
|
|
|
|
cache_element = "max_state"
|
|
|
|
def __init__(self, vm):
|
|
"""
|
|
:param vm: ScEpTIC vm
|
|
"""
|
|
self.vm = vm
|
|
self.n_registers = 0
|
|
self.n_memory_cells = 0
|
|
self.save_only_pc = True
|
|
|
|
self.has_static_placement = self.vm.state_retention.static_placement
|
|
|
|
self.state_calc = SavedStateCalculator(self.vm)
|
|
|
|
# Cache
|
|
file_name = self.vm.state.config.program.file
|
|
cache_target = "{}_{}".format(file_name, 'static' if self.has_static_placement else 'interrupt')
|
|
self._cache = SettingsCache(self.cache_element, cache_target)
|
|
|
|
|
|
def _load_cache(self):
|
|
"""
|
|
Load data from the cache file
|
|
"""
|
|
self._cache.load()
|
|
|
|
try:
|
|
self.n_registers = self._cache.data['n_registers']
|
|
self.n_memory_cells = self._cache.data['n_memory_cells']
|
|
self.save_only_pc = self._cache.data['save_only_pc']
|
|
print(f"Max state loaded - Regs: {self.n_registers}; Memory: {self.n_memory_cells}; Save only pc: {self.save_only_pc}")
|
|
return True
|
|
|
|
except KeyError:
|
|
return False
|
|
|
|
|
|
def _save_cache(self):
|
|
"""
|
|
Save data into the cache file
|
|
"""
|
|
self._cache.data = {
|
|
'n_registers': self.n_registers,
|
|
'n_memory_cells': self.n_memory_cells,
|
|
'save_only_pc': self.save_only_pc
|
|
}
|
|
self._cache.save()
|
|
|
|
|
|
def identify(self):
|
|
"""
|
|
Identifies the maximum state to be saved
|
|
"""
|
|
if self._load_cache():
|
|
return
|
|
|
|
print(f"Identifying maximum state")
|
|
|
|
self.vm.reset()
|
|
|
|
state_save_function_name = self.vm.state_retention.routine_names['save']
|
|
|
|
while not self.vm.state.program_end_reached:
|
|
current_instruction = self.vm.state.current_instruction
|
|
|
|
self.vm.state.run_step()
|
|
|
|
# Static placement -> state saved only when state-save operation reached
|
|
if self.has_static_placement:
|
|
# Skip calc if state-saving operation not reached
|
|
if not isinstance(current_instruction, CallOperation) or current_instruction.resolve_function_name() != state_save_function_name:
|
|
continue
|
|
|
|
save_only_pc, n_registers = self.state_calc.get_saved_registers(current_instruction)
|
|
n_memory_cells = self.state_calc.get_saved_memory_cells(current_instruction)
|
|
|
|
self.n_registers = max(self.n_registers, n_registers)
|
|
self.n_memory_cells = max(self.n_memory_cells, n_memory_cells)
|
|
self.save_only_pc = self.save_only_pc & save_only_pc
|
|
|
|
self._save_cache()
|
|
print(f" -> Regs: {self.n_registers}; Memory: {self.n_memory_cells}; Save only pc: {self.save_only_pc}")
|
|
|
|
self.vm.reset()
|