diff --git a/generator/coder/syscall_fsm.py b/generator/coder/syscall_fsm.py index ee0cd2261337fbbfb5e9987b13db205f7a3111d3..a7f82f248de7eaa4c42564705dc49c6117bd2b56 100644 --- a/generator/coder/syscall_fsm.py +++ b/generator/coder/syscall_fsm.py @@ -10,11 +10,15 @@ import logging class FSMSystemCalls(FullSystemCalls): - def __init__(self): + def __init__(self, use_pla = False): super(FSMSystemCalls, self).__init__() self.alarms = FSMAlarmTemplate - self.fsm_template = SimpleFSMTemplate + if use_pla: + self.fsm_template = PLA_FSMTemplate + else: + self.fsm_template = SimpleFSMTemplate + def generate_system_code(self): self.generator.source_file.include("syscall.h") @@ -178,7 +182,6 @@ class SimpleFSMTemplate(CodeTemplate): def action_rename(action): task_id = action.impl.task_id if task_id == None: - print(action.subtask) task_id = 255 return task_id self.fsm.rename(actions = action_rename) @@ -266,8 +269,100 @@ class SimpleFSMTemplate(CodeTemplate): ret.append(self.expand_snippet(body)) return ret +class PLA_FSMTemplate(CodeTemplate): + def __init__(self, syscall_fsm): + CodeTemplate.__init__(self, syscall_fsm.generator, "os/fsm/pla-fsm.h.in") + self.syscall_fsm = syscall_fsm + self.system_graph = self.generator.system_graph + self.logic = self.system_graph.get_pass("LogicMinimizer") + self.fsm = self.logic.fsm + + def add_transition_table(self): + # Truth table is generated in pla-fsm.h + return + + + def fsm_event(self, syscall, userspace, kernelspace): + event = None + for ev in self.fsm.events: + if self.fsm.event_mapping[ev.name] == syscall: + event = ev + break + if not event: + return # No Dispatch + # kernelspace.add(Statement('kout << "%s" << endl' % syscall.path())) + task = self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.event", + "unsigned", [str(int(event.name, 2))]) + return task + + def fsm_schedule(self, syscall, userspace, kernelspace): + task = self.fsm_event(syscall, userspace, kernelspace) + if not task: + return + if type(task) == int: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.dispatch", + "void", [str(task)]) + else: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.dispatch", + "void", [task.name]) + + def fsm_iret(self, syscall, userspace, kernelspace): + task = self.fsm_event(syscall, userspace, kernelspace) + if not task: + return + + if type(task) == int: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.iret", + "void", [str(task)]) + else: + self.syscall_fsm.call_function(kernelspace, "os::fsm::fsm_engine.iret", + "void", [task.name]) + + ################################################################ + # Used in Template Code + ################################################################ + def truth_table(self, *args): + # Generate the transition table + initializer = [] + for (mask, pattern, output_state, output_action) in self.logic.truth_table: + initializer.append("{{{0}, {1}, {2}, {3}}}".format( + int(mask, 2), + int(pattern, 2), + int(output_state, 2), + int(output_action, 2))) + + return "{" + (", ".join(initializer)) + "}" + + def mask_pattern_len(self, *args): + return str(self.logic.event_len + self.logic.state_len) + + def truth_table_entries(self, *args): + return str(len(self.logic.truth_table)) + + def initial_state(self, *args): + return str(int(self.fsm.initial_state,2)) + + def dispatch_table(self, *args): + mapping = {} + for k, subtask in self.fsm.action_mapping.items(): + mapping[int(k, 2)] = subtask + if not 0 in mapping: + mapping[0] = None + self.NO_DISPATCH = 0 + + initializer = [] + for k,subtask in sorted(mapping.items(), key = lambda x:x[0]): + if not subtask or subtask.conf.is_isr: + initializer.append("0 /* NO_DISPATCH */") + elif subtask == self.system_graph.idle_subtask: + initializer.append("0 /* IDLE */") + self.IDLE = k + else: + initializer.append("&" +subtask.impl.task_descriptor.name) + if not hasattr(self, "IDLE"): + self.IDLE = len(mapping) + 100 + return ", ".join(initializer) class FSMAlarmTemplate(AlarmTemplate): def __init__(self, rules): AlarmTemplate.__init__(self, rules) - diff --git a/generator/main.py b/generator/main.py index e75db2114bfcbd121347a1ce89bc50a230f76ef2..d91ec7f6f98b340015ba7799c3874c13b0adbd74 100755 --- a/generator/main.py +++ b/generator/main.py @@ -188,7 +188,7 @@ if __name__ == "__main__": else: os_rules = EncodedOS() - assert options.systemcalls in ("full", "specialized", "fsm") + assert options.systemcalls in ("full", "specialized", "fsm", "fsm:pla") if options.systemcalls == "specialized": # Only when we want to specialize the system calls, run the @@ -201,7 +201,13 @@ if __name__ == "__main__": logging.info("Global control flow information is provided by %s", global_abb_information.name()) syscall_rules = SpecializedSystemCalls(global_abb_information) + elif options.systemcalls == "fsm:pla": + assert options.arch == "posix", "FSM Encoding is only supported for arch=posix" + pass_manager.enqueue_analysis("LogicMinimizer") + pass_manager.enqueue_analysis("fsm") + syscall_rules = FSMSystemCalls(use_pla = True) elif options.systemcalls == "fsm": + assert options.arch == "posix", "FSM Encoding is only supported for arch=posix" pass_manager.enqueue_analysis("fsm") syscall_rules = FSMSystemCalls() else: diff --git a/generator/transform/FiniteStateMachineBuilder.py b/generator/transform/FiniteStateMachineBuilder.py index d06e0d4e47206e498b0dd72449cbaea55a1d662f..01d155fcd3e089b5ed140fa602ba2d5f9ea54748 100644 --- a/generator/transform/FiniteStateMachineBuilder.py +++ b/generator/transform/FiniteStateMachineBuilder.py @@ -20,7 +20,7 @@ class Transition: return self._event.name def __repr__(self): - return "<Transition(%s) %d -> %d: %s>" %(self.event, self.source, self.target, self.action) + return "<Transition(%s) %s -> %s: %s>" %(self.event, self.source, self.target, self.action) class Event: diff --git a/generator/transform/LogicMinimizer.py b/generator/transform/LogicMinimizer.py index df5d807ed60a880c68f16c4e40e9587318d459f2..e346b66bd78ebb4f173ad09af38ebe06416a2316 100644 --- a/generator/transform/LogicMinimizer.py +++ b/generator/transform/LogicMinimizer.py @@ -15,7 +15,6 @@ class LogicMinimizer(Analysis): def do(self): fsm = self.system_graph.get_pass("fsm").fsm.copy() - self.fsm = self.call_nova(fsm) def call_nova(self, fsm): @@ -74,6 +73,8 @@ class LogicMinimizer(Analysis): fd.write(".e\n") stdout = subprocess.check_output(["nova", nova_input]).decode('ascii', 'ignore') + with open("%s.nova.stdout" % nova_input, "w+") as fd: + fd.write(stdout) event_mapping = {} state_mapping = {} for line in stdout.split("\n"): @@ -134,5 +135,9 @@ class LogicMinimizer(Analysis): got_output_word |= output_word matches[i] += 1 assert got_output_word == desired_output_word + + #for transition in fsm.transitions: + # print(transition, fsm.event_mapping[transition.event], fsm.action_mapping[transition.action]) + logging.info("%d lines in minimzed truth table", len(self.truth_table)) return fsm diff --git a/os/fsm/pla-fsm.h.in b/os/fsm/pla-fsm.h.in new file mode 100644 index 0000000000000000000000000000000000000000..e416a64265553e89db3d5c397d2f08d1f8f75f60 --- /dev/null +++ b/os/fsm/pla-fsm.h.in @@ -0,0 +1,68 @@ +#include "dispatch.h" + +namespace os { +namespace fsm { + +constexpr const os::scheduler::Task * dispatch_table[] = { + {{{!dispatch_table}}} +}; + + +class SchedulerFSM { + public: + struct Row { + unsigned mask : {{{!mask_pattern_len}}}; + unsigned pattern : {{{!mask_pattern_len}}}; + unsigned output_state : {{{!get:logic.state_len}}}; + unsigned output_action : {{{!get:logic.action_len}}}; + } __attribute__((packed)); + + enum { + IDLE = {{{!get:IDLE}}}, + NO_DISPATCH = {{{!get:NO_DISPATCH}}}, + }; + + SchedulerFSM(unsigned state) : internal_state(state) {} + + unsigned event(unsigned event) { + unsigned input_word = event << {{{!get:logic.state_len}}} | internal_state; + unsigned output_state = 0, output_action = 0; + for (unsigned i = 0; i < {{{!truth_table_entries}}}; i++) { + if ((truth_table[i].mask & input_word) == truth_table[i].pattern) { + output_state |= truth_table[i].output_state; + output_action |= truth_table[i].output_action; + } + } + internal_state = output_state; + return output_action; + } + + void dispatch(unsigned task_id) { + if (task_id == IDLE) { + arch::Dispatcher::idle(); + } else if (task_id == NO_DISPATCH) { + return; + } else if (task_id >= sizeof(dispatch_table)/sizeof(*dispatch_table)) { + CALL_HOOK(FaultDetectedHook, LOGIC_ERRORdetected, 0, 0); + } else { + arch::Dispatcher::Dispatch(*dispatch_table[task_id]); + } + } + + void iret(unsigned task_id) { + if (task_id != NO_DISPATCH && task_id != IDLE) { + dispatch(task_id); + } + } + + private: + unsigned internal_state : {{{!get:logic.state_len}}}; + static Row truth_table[{{{!truth_table_entries}}}]; +}; + +SchedulerFSM fsm_engine({{{!initial_state}}}); +SchedulerFSM::Row SchedulerFSM::truth_table[] = {{{!truth_table}}}; + + +} +}