Commit dc5a8d10 authored by Christian Dietrich's avatar Christian Dietrich
Browse files

generator: syscall FSM/PLA implementation

Implement all system calls as PLA implementations.

Change-Id: I1f0bdcdc085727f5ce7e0aa6e6d83db87ae4896a
parent 9346b2d0
......@@ -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)
......@@ -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:
......
......@@ -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:
......
......@@ -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
#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}}};
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment