diff --git a/unoptimized_lr/simple_lr_automaton.py b/unoptimized_lr/simple_lr_automaton.py index 77c486ef509bf11f791842b76e02618f4269ac73..97b1c1b609768366751a0351dccc93457f9d467c 100644 --- a/unoptimized_lr/simple_lr_automaton.py +++ b/unoptimized_lr/simple_lr_automaton.py @@ -175,6 +175,42 @@ from functools import reduce +class ParametrizationConstants(): + def __init__(self, *, number_of_terminals, number_of_nonterminals, + number_of_states, number_of_reduce_rules, + length_of_longest_rule_RHS, maximum_number_of_stack_items, + longest_serialized_parse_tree): + self.number_of_terminals = number_of_terminals + self.number_of_nonterminals = number_of_nonterminals + self.number_of_states = number_of_states + self.number_of_reduce_rules = number_of_reduce_rules + self.length_of_longest_rule_RHS = length_of_longest_rule_RHS + self.maximum_number_of_stack_items = maximum_number_of_stack_items + self.longest_serialized_parse_tree = longest_serialized_parse_tree + + # We calculate the ceil(log_2())'s here all in one go: + + dummy_signal = Signal(range(number_of_terminals)) + self.W_terminal = len(dummy_signal) + + dummy_signal = Signal(range(number_of_nonterminals)) + self.W_nonterminal = len(dummy_signal) + + dummy_signal = Signal(range(number_of_states)) + self.W_state = len(dummy_signal) + + dummy_signal = Signal(range(number_of_reduce_rules)) + self.W_rule = len(dummy_signal) + + dummy_signal = Signal(range(length_of_longest_rule_RHS)) + self.W_max_RHS = len(dummy_signal) + + dummy_signal = Signal(range(maximum_number_of_stack_items)) + self.W_stackdepth = len(dummy_signal) + + dummy_signal = Signal(range(longest_serialized_parse_tree)) + self.W_parsetree_index = len(dummy_signal) + diff --git a/unoptimized_lr/simple_lr_table.py b/unoptimized_lr/simple_lr_table.py index 82a90e2b9c2d3912b086676c6b52064b88ccc8e1..e72ddf9c360c24ec78694688fc34fbad19021fea 100644 --- a/unoptimized_lr/simple_lr_table.py +++ b/unoptimized_lr/simple_lr_table.py @@ -7,6 +7,9 @@ import skidbuffer from functools import reduce +# WARNING! NONE OF THESE ARE SYNTHESIZABLE! WE NEED TO FINISH THE ARBITRARYWIDTHMEMORY +# MODULE BEFORE WE CAN REWRITE THESE TO USE FPGA BLOCK RAM! + # We know this is not really likely to synthesize well, but we implement here so # we can get a gold-standard/reference implementation, against which we can test # our further optimizations, including compression and non-standard representations. @@ -19,6 +22,8 @@ from functools import reduce + + class TableBusLayout(Layout): def __init__(self, *, row_input_width, column_input_width, output_width): super().__init__([ @@ -40,9 +45,28 @@ class TableBus(Record): super().__init__(TableBusLayout(row_input_width=row_input_width, column_input_width=column_input_width, output_width=output_width)) +class OneDimensionTableBusLayout(Layout): + def __init__(self, *, row_input_width, output_width): + super().__init__([ + # INPUTS + ("row_idx", unsigned(row_input_width)), # FROM SOURCE + ("valid_in", 1), # FROM SOURCE + ("ready_in", 1), # FROM DEST + + # OUTPUTS + ("output_data", unsigned(output_width)), # TO DEST + ("valid_out", 1), # TO DEST + ("ready_out", 1), # TO SOURCE + + ]) + +class OneDimensionTableBus(Record): + def __init__(self, *, row_input_width, output_width): + super().__init__(OneDimensionTableBusLayout(row_input_width=row_input_width, output_width=output_width)) + class LRTable(Elaboratable): - def __init__(self, number_of_states, number_of_terminals, number_of_reduce_rules, input_array): + def __init__(self, *, lang_params, input_array): # Parameters # So the LR table is a two-dimensional array, where one of the dimensions (rows) @@ -64,33 +88,26 @@ class LRTable(Elaboratable): # depth = number_of_states * number_of_terminals # We calculate these now: + self.lang_params = lang_params - reduce_rule_signal = Signal(range(number_of_reduce_rules)) - reduce_rule_bits = len(reduce_rule_signal) - self.table_width = (reduce_rule_bits + 2) - self.table_depth = number_of_states * number_of_terminals - - self.number_of_terminals = number_of_terminals - + self.table_width = (lang_params.W_rule + 2) + self.table_depth = lang_params.number_of_states * lang_params.number_of_terminals - dummy_row = Signal(range(number_of_states)) - dummy_column = Signal(range(number_of_terminals)) - # Interfaces - self.bus = TableBus(row_input_width=len(dummy_row), - column_input_width=len(dummy_column), + self.bus = TableBus(row_input_width=lang_params.W_state, + column_input_width=lang_params.W_terminal, output_width=self.table_width) # Interfaces # Prepare the table for consumption - assert(len(input_array) == number_of_states) + assert(len(input_array) == lang_params.number_of_states) rasterized = [] for row in input_array: - assert(len(row) == number_of_terminals) + assert(len(row) == lang_params.number_of_terminals) rasterized.extend(row) # Memory @@ -110,7 +127,7 @@ class LRTable(Elaboratable): # Now we calculate the address: tgt_address = Signal(self.table_depth) with m.If(self.bus.valid_in == 1): - m.d.comb += tgt_address.eq(self.bus.row_idx * self.number_of_terminals + self.bus.col_idx) + m.d.comb += tgt_address.eq(self.bus.row_idx * self.lang_params.number_of_terminals + self.bus.col_idx) m.d.comb += rport.addr.eq(tgt_address) with m.If(self.bus.valid_out == 1): m.d.comb += self.bus.output_data.eq((rport.data)) @@ -120,7 +137,7 @@ class LRTable(Elaboratable): class GOTOtable(Elaboratable): - def __init__(self, number_of_states, number_of_nonterminals, input_array): + def __init__(self, *, lang_params, input_array): # Parameters # So the GOTO table is a two-dimensional array, where one of the dimensions (rows) @@ -147,32 +164,26 @@ class GOTOtable(Elaboratable): # depth = number_of_states # We calculate these now: + self.lang_params = lang_params - nonterminal_signal = Signal(range(number_of_nonterminals)) - nonterminal_bits = len(nonterminal_signal) - self.table_width = (nonterminal_bits + 1) - print(number_of_nonterminals) - self.table_depth = number_of_nonterminals * number_of_states - - self.number_of_nonterminals = number_of_nonterminals + self.table_width = (lang_params.W_nonterminal + 1) + print(lang_params.number_of_nonterminals) + self.table_depth = lang_params.number_of_nonterminals * lang_params.number_of_states - dummy_row = Signal(range(number_of_states)) - dummy_column = Signal(range(number_of_nonterminals)) - # Interfaces - self.bus = TableBus(row_input_width=len(dummy_row), - column_input_width=len(dummy_column), + self.bus = TableBus(row_input_width=lang_params.W_state, + column_input_width=lang_params.W_nonterminal, output_width=self.table_width) # Prepare the table for consumption - assert(len(input_array) == number_of_states) + assert(len(input_array) == lang_params.number_of_states) rasterized = [] for row in input_array: - assert(len(row) == number_of_nonterminals) + assert(len(row) == lang_params.number_of_nonterminals) rasterized.extend(row) # Memory @@ -192,7 +203,7 @@ class GOTOtable(Elaboratable): # Now we calculate the address: tgt_address = Signal(self.table_depth) with m.If(self.bus.valid_in == 1): - m.d.comb += tgt_address.eq(self.bus.row_idx * self.number_of_nonterminals + self.bus.col_idx) + m.d.comb += tgt_address.eq(self.bus.row_idx * self.lang_params.number_of_nonterminals + self.bus.col_idx) m.d.comb += rport.addr.eq(tgt_address) with m.If(self.bus.valid_out == 1): m.d.comb += self.bus.output_data.eq(rport.data) @@ -204,6 +215,48 @@ class GOTOtable(Elaboratable): + +class ReduceRuleTable(Elaboratable): + def __init__(self, *, lang_params, input_array): + # Parameters + + # So the Reduce Rule lookup table is a one-dimensional array, indexed by + # rule number: + + # Each element of the array is of the form: + + # [Number of items to pop] [Generated nonterminal] + + # This means that the length of each element has to be: + # TIW = (WLongestRule + number of bits to index the nonterminals) + + + self.table_width = (nonterminal_bits + 1) + print(number_of_nonterminals) + self.table_depth = number_of_nonterminals * number_of_states + + self.number_of_nonterminals = number_of_nonterminals + + + # Interfaces + self.bus = OneDimensionTableBus(row_input_width=W_nonterminal, + output_width=self.table_width) + + + self.mem = Memory(width=self.table_width, depth=self.table_depth, init=rasterized) + + + def elaborate(self, platform): + m = Module() + m.submodules.rport = rport = (self.mem).read_port() + m.submodules.wport = wport = (self.mem).write_port() + + + return m + + + + class DummyPlug(Elaboratable): #def __init__(self): diff --git a/unoptimized_lr/skidbuffer.py b/unoptimized_lr/skidbuffer.py old mode 100755 new mode 100644