diff --git a/lr_automaton_gateware.py b/lr_automaton_gateware.py
index 2b6c8ef2a43c648f7eeec28edd34455816445380..c70d3a160ee508a6d090953dd21a4b01fc063a3f 100644
--- a/lr_automaton_gateware.py
+++ b/lr_automaton_gateware.py
@@ -9,6 +9,12 @@ from skidbuffer import RegisteredSkidBuffer
 
 
 class ParseStack(Elaboratable):
+    PUSH = 0
+    POP  = 1
+    MULTIPOP = 2
+    INTROSPECT = 3
+    READ_SP    = 4
+    READ_TOS   = 5
     def __init__(self, width, depth):
         # Parameters
         self.width = width
@@ -34,9 +40,9 @@ class ParseStack(Elaboratable):
         self.strobe       = Signal(1) # when 1, execute the command
 
         # Data inputs
-        self.in_data_port      = Signal(1)
+        self.in_data_port      = Signal(width)
         self.in_aux_port       = Signal(range(depth))
-        self.in_valid          = Signal(width)
+        self.in_valid          = Signal(1)
 
         # Control outputs
         self.valid_out      = Signal(1)
@@ -50,1140 +56,163 @@ class ParseStack(Elaboratable):
         self.mem = Memory(width=self.width, depth=self.depth)
 
 
-    def elaborate(self, platform):
-
-        stack_pointer = Signal(range(self.depth))
-
-        item_in_slot_zero    = Signal(1) # to disambiguate between sp=0 with nothing in 0 and sp=0 with one item pushed
-
-        m = Module()
-        return m
-
-
-
-class InspectableRegister(Elaboratable):
-    def __init__(self, width):
-        self.width = width
-        # interface
-        self.write_enable = Signal(1)
-        self.write_port   = Signal(width) #data to write
-
-        self.read_port    = Signal(width) #always-on output
-
-    def elaborate(self, platform):
-        m = Module()
-        data = Signal(self.width) # internal register
-
-        m.d.comb += self.read_port.eq(data)
-
-        with m.If(self.write_enable == 1):
-            m.d.sync += data.eq(self.write_port)
-
-        return m
-
-
-class StacksInSync(Elaboratable):
-    def __init__(self, bigstack_item_width, sidestack_item_width, stack_depth):
-
-        self.bigstack_item_width = bigstack_item_width
-        self.sidestack_item_width = sidestack_item_width
-
-        self.depth = stack_depth
-
-        self.command_in   = Signal(2)      # whether to push or pop
-        self.command_in_strobe = Signal(1) # start the command
-
-        self.big_push_port = Signal(bigstack_item_width) # input data
-
-        self.side_push_port = Signal(sidestack_item_width) # input data
-
-
-        self.bigpop_port_valid = Signal(1) # ouput data is valid
-        self.bigpop_port  = Signal(bigstack_item_width) # output data
-
-        self.sidepop_port_valid = Signal(1) # ouput data is valid
-        self.sidepop_port  = Signal(sidestack_item_width) # output data
-
-
-        self.occupancy_bitmap = Signal(self.depth)
-
-        self.internal_fault = Signal(1)
-
-
-        # read-only access to the top K entries, connected to the
-        # reduction-detection logic
-
-        self.bigperm_out = Array([Signal(bigstack_item_width) for _ in range(stack_depth)])
-        self.sideperm_out = Array([Signal(sidestack_item_width) for _ in range(stack_depth)])
-
-    def elaborate(self, platform):
-        m = Module()
-
-        bigstack = InspectableStack(self.bigstack_item_width, self.depth)
-        sidestack = InspectableStack(self.sidestack_item_width, self.depth)
-        m.submodules += bigstack
-        m.submodules += sidestack
-
-        m.d.comb += bigstack.command_in.eq(self.command_in)
-        m.d.comb += bigstack.command_in_strobe.eq(self.command_in_strobe)
-        m.d.comb += bigstack.push_port.eq(self.big_push_port)
-        m.d.comb += self.bigpop_port.eq(bigstack.pop_port)
-        m.d.comb += self.bigpop_port_valid.eq(bigstack.pop_port_valid)
-
-        for idx, sig in enumerate(bigstack.perm_out):
-            m.d.comb += (self.bigperm_out[idx]).eq(sig)
-
-
-        m.d.comb += sidestack.command_in.eq(self.command_in)
-        m.d.comb += sidestack.command_in_strobe.eq(self.command_in_strobe)
-        m.d.comb += sidestack.push_port.eq(self.side_push_port)
-        m.d.comb += self.sidepop_port.eq(sidestack.pop_port)
-        m.d.comb += self.sidepop_port_valid.eq(sidestack.pop_port_valid)
-
-        for idx, sig in enumerate(sidestack.perm_out):
-            m.d.comb += (self.sideperm_out[idx]).eq(sig)
-
-
-
-
-        m.d.comb += self.occupancy_bitmap.eq(bigstack.occupancy_bitmap)
-
-        m.d.comb += self.internal_fault.eq(bigstack.fault | sidestack.fault)
-
-        return m
-
-class InspectableStack(Elaboratable):
-    def __init__(self, item_width, stack_depth):
-        self.item_width = item_width
-        self.depth = stack_depth
-
-#        self.command_ready = Signal(1) # output 1 if we're ready for a new command
-
-        self.command_in   = Signal(2)      # whether to push or pop
-        self.command_in_strobe = Signal(1) # start the command
-
-        self.push_port = Signal(item_width) # input data
-
-        self.pop_port_valid = Signal(1) # ouput data is valid
-        self.pop_port  = Signal(item_width) # output data
-        self.occupancy_bitmap = Signal(self.depth)
-
-
-        self.overfill = Signal(1)
-        self.underfill = Signal(1)
-
-        self.fault = Signal(1)
-
-
-        # read-only access to the top K entries, connected to the
-        # reduction-detection logic
-
-        self.perm_out = Array([Signal(item_width) for _ in range(stack_depth)])
-
-
-    def elaborate(self, platform):
-        m = Module()
-
-        # first create the stack item registers and their driving signals
-        reversal = Signal(1) # 1 if popping, 0 if pushing
-        move_em = Signal(1)  # write_enable for the entire stack
-
-        all_registers = []
-        i = 0
-        for z in range(self.depth):
-            element_z = InspectableRegister(self.item_width)
-            all_registers.append(element_z)
-            m.submodules += element_z
-            m.d.comb += (self.perm_out[i]).eq(element_z.read_port)
-
-            m.d.comb += element_z.write_enable.eq(move_em)
-            i = i + 1
-
-        assert(len(all_registers) > 3) # will need to special case len 3
-        head_write_port = Signal(self.item_width)
-        tail_write_port = Signal(self.item_width)
-
-
-        for cursor, postcursor in zip(all_registers[1:-2], all_registers[2:-1]):
-            with m.If(0 == reversal):
-                m.d.comb += postcursor.write_port.eq(cursor.read_port)
-            with m.Else():
-                m.d.comb += cursor.write_port.eq(postcursor.read_port)
-
-        # and now the edge cases
-        with m.If(0 == reversal):
-            # when we add a TAIL READ PORT add something here to connect it
-
-            m.d.comb +=  all_registers[0].write_port.eq(head_write_port)
-            m.d.comb +=  all_registers[1].write_port.eq(all_registers[0].read_port)
-
-            m.d.comb += all_registers[-1].write_port.eq(all_registers[-2].read_port)
-
-        with m.Else():
-            # when we add a HEAD READ PORT add something here to connect it
-
-            m.d.comb += all_registers[0].write_port.eq(all_registers[1].read_port)
-            m.d.comb += all_registers[-1].write_port.eq(tail_write_port)
-
-            m.d.comb += all_registers[-2].write_port.eq(all_registers[-1].read_port)
-
-        # now for the command logic
-
-        with m.If(1 == self.command_in_strobe):
-            with m.If(2 == self.command_in): # push
-                m.d.comb += head_write_port.eq(self.push_port)
-                m.d.comb += reversal.eq(0)
-                m.d.comb += move_em.eq(1)
-                m.d.sync += self.occupancy_bitmap.eq(Cat(1,self.occupancy_bitmap[0:-1]))
-                m.d.comb += self.overfill.eq(self.occupancy_bitmap[-1])
-            with m.Elif(1 == self.command_in): # pop
-                m.d.comb += self.pop_port.eq(all_registers[0].read_port)
-                m.d.comb += reversal.eq(1)
-                m.d.comb += move_em.eq(1)
-                m.d.sync += self.occupancy_bitmap.eq(Cat(self.occupancy_bitmap[1:],0))
-                m.d.comb += self.underfill.eq(~self.occupancy_bitmap[0])
-
-
-        m.d.comb += self.fault.eq(self.overfill | self.underfill)
-
-        return m
-
-
-
-# HitOrMiss is the current rule lookup engine.
-#
-# It is fully combinatorial; every cycle it ingests the current state
-# of the stack and the new item, and determines:
-#
-# 1. Valid Item: Whether the new item can be immediately rejected.
-#    This corresponds to a blank space in an LR parser table
-#
-# 2. Force Shift: Whether the new item must be shifted onto the stack
-#    *without* looking at possible reduction rules to apply to the current
-#    state of the stack.
-#
-# 3. Reduce Select: Which reduction rule applies to the current stack.
-#
-# Note that this list is in decreasing priority -- if the item is invalid,
-# the results of Force Shift or Reduce Select are immaterial. Similarly, if
-# Force Shift triggers, we shall ignore the results of Reduce Select.
-#
-# Valid Item allows to, well, immediately reject invalid data and avoid
-# getting the stack in an invalid state. Force Shift allows the resolving of
-# Shift/Reduce conflicts -- otherwise, the parser would immediately reduce
-# everything it sees, as far as possible. Reduce Select resolves Reduce/Reduce
-# conflicts.
-#
-# When generating HDL, HitOrMiss must be provided a rulepack. The rulepack is
-# composed of several rulesets:
-#
-# 1. Stack State Descriptions
-# 2. Disambiguation Pairwise Priority
-# 3. Valid Item Ruleset
-# 4. Force Shift Ruleset
-# 5. Reduce Ruleset
-#
-# Stack State Descriptions contains descriptions of stack states.
-# A stack state is described by a list of "stack conditions". A stack state
-# match holds when every stack condition is valid.
-#
-# Currently, each each "stack condition" and each "new item" condition
-# is a tuple composed of: (index of stack, tag mask, tag value), but later
-# we will add provisions for more flexible matching predicates;
-# for example, range matching.
-#
-# Example: if our rule is [(0, 0xff00, 0x4200), (1, 0xf000, 0x6000),
-# it will match a stack iff the top item of the stack has a tag A and
-# the item below it has a tag B such that:
-# (A & (0xff00)) == 0x4200
-# (B & (0xf000)) == 0x6000
-#
-# The mask value allows us to store data inside the stack items that does
-# not affect the grammar's rules. This semantic data -- which may be
-# raw literals or indices into an external RAM are known as "data tags".
-#
-# The same (tag mask, tag value) scheme is used to describe the New Item.
-#
-# The Pairwise Priority mechanism works as follows: if the current stack state
-# matches multiple stack state descriptions, the list of
-# (inhibited rule, dominator rule) pairs determines pairwise priority amongst
-# rules -- and the winning rule is the one selected for application. This is
-# to handle reduce/reduce conflicts if there is a rule whose stack state is
-# a subset of an other -- in order to allow the more specific rule to match.
-
-
-
-
-
-# Once we have determined which stack state description corresponds to the
-# current state of the stack, we know which row of the traditional LR table
-# is relevant. The current stack state (a one hot signal) acts as an index
-# into the three following tables:
-#
-# The Valid Item Ruleset is composed of a list of rules, one per stack state.
-# Each rule has the form: {list of all new items that can be accepted}.
-#
-# The Force Shift Ruleset is composed of a list of rules, one per stack state.
-# Each rule has the form: {list of all new items that must be shifted}.
-#
-# The Reduce Ruleset is composed of a list of rules, one per stack state.
-# Each rule is a list of tuples {(new item A, rule number n),
-#                                (new item B, rule number m), ...}.
-#
-#
-#
-# We therefore have a "master" ruleset which is indexed by stack state and
-# contains the following information:
-# 1) Which new items can be accepted?
-# 2) If an item can be accepted, should it be pushed or should we consult the reduce rules?
-# 3) If we should consult the reduce rules (WITHOUT pushing the new item),
-#    what reduction rules apply.
-#
-
-class HitOrMiss(Elaboratable):
-    def __init__(self, item_width, stack_depth, reduction_rule_count, stack_state_descriptions, pairwise_priority_ruleset, validitem_ruleset, forceshift_ruleset, reduce_ruleset, endofparse_marker):
-        # Parameters
-        self.item_width           = item_width
-        self.stack_depth          = stack_depth
-        self.reduction_rule_count = reduction_rule_count
-        # Rulepack
-        self.stack_state_descriptions  = stack_state_descriptions
-        self.pairwise_priority_ruleset = pairwise_priority_ruleset
-
-        self.validitem_ruleset         = validitem_ruleset
-        self.forceshift_ruleset        = forceshift_ruleset
-        self.reduce_ruleset            = reduce_ruleset
-
-        self.endofparse_marker = endofparse_marker
-
-        assert(len(stack_state_descriptions) == len(validitem_ruleset))   # blank spaces in LR table
-        assert(len(stack_state_descriptions) == len(forceshift_ruleset))  # shift entries in LR table
-        assert(len(stack_state_descriptions) == len(reduce_ruleset))      # reduce entries in LR table
-
-        # Input signals
-        self.new_item_in   = Signal(item_width)
-        self.stack_view_in = Array([Signal(item_width) for _ in range(stack_depth)])
-        self.occupancy_bitmap_in = Signal(stack_depth)
-
-        # Output signals
-        self.internal_fault     = Signal(1)
-
-        self.endofparse_reached = Signal(1)
-
-        self.invalid_item       = Signal(1)
-        self.force_shift        = Signal(1)
-        self.match_index_out    = Signal(reduction_rule_count)
-
-
-    def elaborate(self, platform):
-        m = Module()
-
-
-        # Unified stack state matching (with pairwise priority mechanism to resolve subsetting)
-
-        # Normally each stack state should be matched by only one possible stack state description, but it
-        # is possible that one stack state description is a subset of an other such that both stack state
-        # descriptions are triggered for a current stack. Think, with top of stack at idx 0,
-        # (A, B, C) and (A, B, C, D, E). A stack that looks like (A, B, C, D, E) will show both stack state
-        # descriptions as matching, but we want to only trigger the latter rule. This is an artefact of the
-        # fact that we are ignoring the unique numbering of stack states that a more conventional implementation
-        # of LR parser would use.
-        #
-        # This disambiguation is carried out by an ancillary list of pairwise priority values. This list of
-        # (inhibited rule number, dominating rule number) is generated by the software that processes a
-        # language description into LR parser tables -- not by this software nor by the RTL in real-time.
-
-
-        stack_state_bitmap = []
-        for stack_state in self.stack_state_descriptions:
-            stack_as_described = Signal(1)
-            stack_predicates = []
-
-            for stack_predicate in stack_state:
-                (stack_index, mask, value) = stack_predicate
-                stack_predicate_status = Signal(1)
-                m.d.comb += stack_predicate_status.eq(((self.stack_view_in[stack_index] & mask) == value) & self.occupancy_bitmap_in[stack_index])
-                stack_predicates.append(stack_predicate_status)
-
-            m.d.comb += stack_as_described.eq(reduce(lambda x, y: x & y, stack_predicates))
-            stack_state_bitmap.append(stack_as_described)
-
-        # Now we apply the Disambiguation Pairwise Priorities
-        for priority_pair in self.pairwise_priority_ruleset:
-            (inhibited_rule_number, dominator_rule_number) = priority_pair
-            dom_value = stack_state_bitmap[dominator_rule_number]
-            inh_value = stack_state_bitmap[inhibited_rule_number]
-            new_inh = Signal(1)
-            m.d.comb += new_inh.eq(inh_value & (~dom_value))
-            stack_state_bitmap[inhibited_rule_number] = new_inh
-
-        stack_state_onehot = Signal(len(self.stack_state_descriptions))
-        stack_state_onehot = Cat(stack_state_bitmap)
-
-        # verify it's one-hot
-        one_hot = Signal(1)
-        m.d.comb += one_hot.eq(0 == (stack_state_onehot & (stack_state_onehot - 1)))
-
-
-
-
-        # we've identified which stack state description corresponds to the current state of the stack,
-        # aka, which row of the LR table we are on. Now we will identify which outcome applies for the
-        # combination of the current stack state and also the new item.
-        all_new_item_predicates = []
-        all_shift_predicates    = []
-
-        reduce_rule_bitmap = []
-
-        # Random-access (at synth time) bitmap without combinatorial loop issues
-        for i in range(self.reduction_rule_count):
-            reduce_rules_bitmap_component = Signal(1)
-            reduce_rule_bitmap.append(reduce_rules_bitmap_component)
-
-        with m.If(one_hot == 1): # only do this if the signal is one-hot
-            validitem_result  = Signal(1)
-            forceshift_result = Signal(1)
-            for rule_idx in range(len(self.stack_state_descriptions)):
-                with m.If(stack_state_onehot[rule_idx] == 1):
-                    validitem_rule  = self.validitem_ruleset[rule_idx]
-                    forceshift_rule = self.forceshift_ruleset[rule_idx]
-                    reduce_rule     = self.reduce_ruleset[rule_idx]
-
-                    new_item_in_acceptset = Signal(1)
-                    new_item_predicates   = []
-
-                    for candidate in validitem_rule:
-                        (mask, value) = candidate
-                        new_item_predicate_status = Signal(1)
-                        m.d.comb += new_item_predicate_status.eq(((self.new_item_in & mask) == value))
-                        new_item_predicates.append(new_item_predicate_status)
-                    m.d.comb += new_item_in_acceptset.eq(reduce(lambda x, y: x | y, new_item_predicates))
-
-
-                    new_item_in_shiftset = Signal(1)
-                    shift_item_predicates   = []
-                    if (forceshift_rule == []):
-                        m.d.comb += new_item_in_shiftset.eq(0)
-                    else:
-                        for candidate in forceshift_rule:
-                            (mask, value) = candidate
-                            shift_item_predicate_status = Signal(1)
-                            m.d.comb += shift_item_predicate_status.eq(((self.new_item_in & mask) == value))
-                            shift_item_predicates.append(shift_item_predicate_status)
-                        m.d.comb += new_item_in_shiftset.eq(reduce(lambda x, y: x | y, shift_item_predicates))
-
-                    for candidate in reduce_rule:
-                        reduce_item_predicate_status = Signal(1)
-                        (newitem, reduce_rule_number) = candidate
-                        (mask, value) = newitem
-                        m.d.comb += reduce_item_predicate_status.eq(((self.new_item_in & mask) == value))
-                        with m.If(reduce_item_predicate_status == 1):
-                            m.d.comb += reduce_rule_bitmap[reduce_rule_number].eq(1)
-
-                    all_new_item_predicates.append(new_item_in_acceptset)
-                    all_shift_predicates.append(new_item_in_shiftset)
-
-
-            m.d.comb += validitem_result.eq(reduce(lambda x, y: x | y, all_new_item_predicates))
-            m.d.comb += forceshift_result.eq(reduce(lambda x, y: x | y, all_shift_predicates))
-
-            # We now have:
-            # 1) a single-bit signal whether the new item is a valid new item or not
-            # 2) a single-bit signal whether the new item must be shifted
-            # 3) a one-hot signal that tells us which reduce rule (if any) matched
-
-            # and we must output three signals: match_index_out force_shift invalid_item
-
-            with m.If(validitem_result == 0):  # Invalid item, raise error
-                m.d.comb += self.invalid_item.eq(1)
-                m.d.comb += self.force_shift.eq(0)
-                m.d.comb += self.match_index_out.eq(0)
-
-            with m.If(validitem_result == 1): # Valid item
-                m.d.comb += self.invalid_item.eq(0)
-
-                with m.If(forceshift_result == 1): # Shift
-                    m.d.comb += self.force_shift.eq(1)
-                    m.d.comb += self.match_index_out.eq(0)
-
-                with m.If(forceshift_result == 0): # Reduce
-                    m.d.comb += self.force_shift.eq(0)
-                    matching_reduce_rules_onehot = Signal(self.reduction_rule_count)
-                    m.d.comb += matching_reduce_rules_onehot.eq(Cat(reduce_rule_bitmap))
-
-                    m.d.comb += self.internal_fault.eq(0 != (matching_reduce_rules_onehot & (matching_reduce_rules_onehot - 1)))
-
-                    with m.If(self.internal_fault == 0):
-                        m.d.comb += self.match_index_out.eq(matching_reduce_rules_onehot)
-
-
-        with m.If(one_hot == 0):
-            m.d.comb += self.internal_fault.eq(1)
-
-        (mask, value) = self.endofparse_marker
-        with m.If((self.stack_view_in[0] & mask) == value):
-            m.d.comb += self.endofparse_reached.eq(1)
-
-
-        return m
-
-
-# Rule Execution Engine: input is a one-hot signal for the rule that got triggered,
-# output is: 1) how many items we can destroy off the top of the stack and
-# 2) what item (language item tag, data tag) we replace it with
-#
-# The execution ruleset is composed of a list of execution rules. Each execution
-# rule has:
-# 1) An implicit index number (which must match the implicit rule number in the Matcher ruleset)
-# 2) A number of items to pop
-# 3) The language tag of the item to push.
-#
-# Later, there will be a way to specify what computation is done with the data tags
-# of the popped items -- and what data tag is affixed to the pushed item.
-
-# Also we have a view to the stack so we can extract the data tags of the popped items
-# and do computation on them with a lambda that is fed to us in the execution ruleset
-
-
-class RuleExecutor(Elaboratable):
-    def __init__(self, item_width, stack_depth, execution_ruleset):
-        # Parameters
-        self.execution_ruleset = execution_ruleset
-        self.item_width = item_width
-        self.stack_depth = stack_depth
-
-        self.match_index_in = Signal(len(execution_ruleset))
-
-        self.stack_view_in = Array([Signal(item_width) for _ in range(stack_depth)])
-
-        self.number_to_pop = Signal(range(stack_depth))
-        self.created_item = Signal(item_width)
-
     def elaborate(self, platform):
         m = Module()
 
-        for rule_idx, rule in enumerate(self.execution_ruleset[::-1]):
-            (items_to_pop, new_item_func) = rule
+        m.submodules.rport = rport = (self.mem).read_port()
+        m.submodules.wport = wport = (self.mem).write_port()
+        stack_pointer = Signal(range(self.depth), reset=0)
 
-            with m.If(self.match_index_in[len(self.execution_ruleset) - rule_idx -1] == 1):
-                m.d.comb += self.number_to_pop.eq(items_to_pop)
-                m.d.comb += self.created_item.eq(new_item_func(self.stack_view_in))
-        return m
 
-# We create a serialized parse tree from the bottom up, with 
+        # To represent the state of a k-item stack, we need an additional bit of state to
+        # disambiguate the case where there are zero items on the stack and the case where
+        # there is a single item pushed on the stack.
 
-class TreeSerializer(Elaboratable):
-    def __init__(self, item_width, indices_width, stack_depth, serialized_tree_length, serializing_ruleset):
-        # Parameters
-        self.item_width    = item_width
-        self.stack_depth   = stack_depth
-        self.indices_width = indices_width
-        self.serialized_tree_length = serialized_tree_length
-        self.mem_address_width = indices_width
-        self.serializing_ruleset = serializing_ruleset
-        self.serialized_tree_length = serialized_tree_length
-
-        # inputs
-
-        # Activated only once per reduction
-        self.start_reduction             = Signal(1)
-        # When ^ goes high, the three below are registered
-
-        self.number_to_pop               = Signal(range(stack_depth))
-        self.reduce_rule_number          = Signal(item_width)
-        self.item_created_by_reduce_rule = Signal(item_width)
-
-        # Varies with every popped item
-        self.destroyed_item_valid_in        = Signal(1)
-        self.destroyed_item_in              = Signal(item_width)     # off main stack
-        self.destroyed_item_index_in        = Signal(indices_width)  # off side stack
+        # bottom_of_stack_valid = 0 implies zero items on the stack (which means s_p must be 0), and
+        # popping generates an error
 
-        # outputs
-        # output to state machine
-        self.ready_out                   = Signal(1)
-        self.internal_fault              = Signal(1)
+        # bottom_of_stack_valid = 1 implies that there is at least one item on the stack, and s_p can take
+        # any value.
 
-        self.serialized_index            = Signal(indices_width)    # push *this* onto side stack for the
-                                                                    # newly created item
-        # interface with serialization memory
-        self.memory_write_port           = Signal(item_width + 1)
-        self.memory_address_port         = Signal(self.mem_address_width)
-        self.memory_write_enable         = Signal(1)
+        # 0 items on stack (bottom_of_stack_valid = 0, stack_pointer = 0)
+        # PUSH
+        # 1 item on stack  (bottom_of_stack_valid = 1, stack_pointer = 0)
+        # PUSH
+        # 2 items on stack (bottom_of_stack_valid = 1, stack_pointer = 1)
+        # PUSH
+        # 3 items on stack (bottom_of_stack_valid = 1, stack_pointer = 2)
 
+        # and for popping, it proceeds in reverse.
 
-        self.mem = Memory(width=(self.item_width + 1), depth=serialized_tree_length)
-
-    def elaborate(self, platform):
-        m = Module()
-
-        start_of_record = Signal(self.mem_address_width) # start of next/yet-unwritten node record, advanced only
-                                                         # after each reduce
+        bottom_of_stack_valid = Signal(1)
 
-        m.submodules.parse_tree = wport = (self.mem).write_port()
-
-
-
-        m.d.comb += wport.en.eq(self.memory_write_enable),
-        m.d.comb += wport.addr.eq(self.memory_address_port),
-        m.d.comb += wport.data.eq(self.memory_write_port)
-
-
-        # Per-reduce registered signals:
-        number_of_children          = Signal(range(self.stack_depth))
-
-        reduce_rule_number          = Signal(self.item_width)
-        item_created_by_reduce_rule = Signal(self.item_width)
-
-        # incremented each cycle
-        number_written              = Signal(range(self.stack_depth))
-        m.d.comb += self.serialized_index.eq(start_of_record)
 
+        multipop_left = Signal(range(self.depth))
 
         with m.FSM() as fsm:
-            with m.State("INITIALIZE"):
-                m.d.comb += self.ready_out.eq(0)
-                m.d.comb += self.internal_fault.eq(0)
-
-                m.d.sync += start_of_record.eq(0)
-                m.d.sync += number_written.eq(0)
-
-                m.next="NODE"
-
-
-            with m.State("NODE"):
-                m.d.comb += self.ready_out.eq(1)
-                m.d.comb += self.internal_fault.eq(0)
-
-                #m.d.sync += reduce_rule_number.eq(self.reduce_rule_number)
-                m.d.sync += item_created_by_reduce_rule.eq(self.item_created_by_reduce_rule)
-
-                with m.If(self.start_reduction == 1):
-                    with m.If(self.destroyed_item_index_in == 0):
-                        m.d.comb += self.memory_write_port.eq(self.destroyed_item_in)
-                    with m.Else():
-                        m.d.comb += self.memory_write_port.eq(self.destroyed_item_index_in)
-                    m.d.comb += self.memory_address_port.eq(start_of_record + 2)
-                    m.d.comb += self.memory_write_enable.eq(1)
-
-                    m.d.sync += number_of_children.eq(self.number_to_pop)
-                    m.d.sync += number_written.eq(1)
-
-                    m.next = "SUBNODES"
-
-                with m.If(self.memory_address_port > (self.serialized_tree_length - 1)):
-                    m.next = "ABORT"
-
-            with m.State("SUBNODES"):
-                m.d.comb += self.ready_out.eq(0)
-                m.d.comb += self.internal_fault.eq(0)
-
-                with m.If(self.destroyed_item_valid_in == 1):
-                    with m.If(self.destroyed_item_index_in == 0):
-                        m.d.comb += self.memory_write_port.eq(self.destroyed_item_in)
-                    with m.Else():
-                        m.d.comb += self.memory_write_port.eq(self.destroyed_item_index_in)
-                    m.d.comb += self.memory_address_port.eq(start_of_record + 2 + number_written)
-                    m.d.comb += self.memory_write_enable.eq(1)
-
-                    m.d.sync += number_written.eq(number_written + 1)
-
-
-                with m.If(number_written == number_of_children):
-                    m.d.comb += self.memory_write_port.eq(item_created_by_reduce_rule)
-                    m.d.comb += self.memory_address_port.eq(start_of_record)
-                    m.d.comb += self.memory_write_enable.eq(1)
-
-                    m.next = "FIXUP"
-
-                with m.If(self.memory_address_port > (self.serialized_tree_length - 1)):
-                    m.next = "ABORT"
-
-            with m.State("FIXUP"):
-                    m.d.comb += self.ready_out.eq(0)
-                    m.d.comb += self.internal_fault.eq(0)
-
-                    m.d.comb += self.memory_write_port.eq(number_of_children)
-                    m.d.comb += self.memory_address_port.eq(start_of_record + 1)
-                    m.d.comb += self.memory_write_enable.eq(1)
-                    m.d.sync += start_of_record.eq(start_of_record + 2 + number_of_children)
-
-                    m.next = "NODE"
-
-                    with m.If(self.memory_address_port > (self.serialized_tree_length - 1)):
-                        m.next = "ABORT"
-
-            with m.State("ABORT"):
-                m.d.comb += self.ready_out.eq(0)
+            with m.State("EMPTY"):
+                with m.If(self.strobe == 1):
+                    with m.Switch(self.command_port):
+                        with m.Case(self.PUSH):
+                            with m.If(self.in_valid == 1):
+                                m.d.comb += wport.addr.eq(stack_pointer)
+                                m.d.comb += wport.data.eq(self.in_data_port)
+                                m.d.comb += wport.en.eq(1)
+                                m.next = "AT_LEAST_ONE_ITEM"
+                        with m.Case(self.POP):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.MULTIPOP):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.INTROSPECT):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.READ_TOS):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.READ_SP):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+
+            with m.State("AT_LEAST_ONE_ITEM"):
+                with m.If(self.strobe == 1):
+                    with m.Switch(self.command_port):
+                        with m.Case(self.PUSH):
+                            with m.If(self.in_valid == 1):
+                                m.d.sync += stack_pointer.eq(stack_pointer + 1)
+                                m.d.comb += wport.addr.eq(stack_pointer + 1)
+                                m.d.comb += wport.data.eq(self.in_data_port)
+                                m.d.comb += wport.en.eq(1)
+                                m.next = "AT_LEAST_ONE_ITEM"
+                        with m.Case(self.POP):
+                            m.d.comb += rport.addr.eq(stack_pointer)
+                            m.d.comb += self.out_data_port.eq(rport.data)
+
+                            with m.If(stack_pointer == 0):
+                                m.next = "EMPTY"
+                            with m.Else():
+                                m.next = "AT_LEAST_ONE_ITEM"
+                                m.d.sync += stack_pointer.eq(stack_pointer - 1)
+                        with m.Case(self.MULTIPOP):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.INTROSPECT):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.READ_TOS):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+                        with m.Case(self.READ_SP):
+                            m.d.comb += self.internal_fault.eq(1)
+                            m.next = "FAULTED"
+            with m.State("FAULTED"):
                 m.d.comb += self.internal_fault.eq(1)
+                m.next = "FAULTED"
 
 
 
 
-        return m
-
-# This is the master state machine -- it interfaces with the outside
-# and feeds data to the above subcomponents as appropriate. For
-# multi-cycle operations (popping multiple items off the InspectableStack)
-# it stalls the input.
-
-class MasterStateMachine(Elaboratable):
-    def __init__(self, item_width, indices_width, stack_depth, serialized_tree_length, stack_state_descriptions, validitem_ruleset, forceshift_ruleset, pairwise_priority_ruleset, reduce_ruleset, execute_rules, startofparse_marker, endofparse_marker):
-        self.item_width    = item_width
-        self.stack_depth   = stack_depth
-        self.indices_width = indices_width
-
-        # Rule pack
-        self.validitem_ruleset         = validitem_ruleset
-        self.forceshift_ruleset        = forceshift_ruleset
-        self.pairwise_priority_ruleset = pairwise_priority_ruleset
-        self.reduce_ruleset            = reduce_ruleset
-        self.execute_rules             = execute_rules
-        self.stack_state_descriptions  = stack_state_descriptions
-
-        self.endofparse_marker = endofparse_marker
-        self.startofparse_marker = startofparse_marker
-
-        # Data stream in
-        self.data_in = Signal(item_width)
-        self.data_in_valid = Signal(1)
-        self.data_in_ready = Signal(1)
-
-        # Data stream out
-        #self.data_out = Signal(item_width)
-        #self.data_out_valid = Signal(1)
-        #self.data_out_ready = Signal(1)
-
-        # Sideband signals
-        self.parse_complete_out = Signal(1)
-        self.parse_success_out  = Signal(1)
-        self.internal_fault     = Signal(1)
-        self.last_index_to_smem = Signal(32)
-        self.serializer = TreeSerializer(item_width=self.item_width, indices_width=(self.indices_width+1), stack_depth=self.stack_depth, serialized_tree_length=serialized_tree_length, serializing_ruleset=[])
-        self.tapir = self.serializer.mem
 
+ 
 
 
 
-    def elaborate(self, platform):
-        m = Module()
-        #stack         = InspectableStack(item_width=self.item_width,    stack_depth=self.stack_depth)
-        doublestacks  = StacksInSync(bigstack_item_width=self.item_width, sidestack_item_width=self.indices_width + 1, stack_depth = self.stack_depth)
-
-        rule_matcher = HitOrMiss(item_width=self.item_width, stack_depth=self.stack_depth,
-            validitem_ruleset         = self.validitem_ruleset,
-            forceshift_ruleset        = self.forceshift_ruleset,
-            pairwise_priority_ruleset = self.pairwise_priority_ruleset,
-            reduce_ruleset            = self.reduce_ruleset,
-            reduction_rule_count=len(self.execute_rules), stack_state_descriptions = self.stack_state_descriptions, endofparse_marker = self.endofparse_marker)
-        rex = RuleExecutor(item_width=self.item_width, stack_depth=self.stack_depth, execution_ruleset=self.execute_rules)
-        skbuffer = RegisteredSkidBuffer(width = self.item_width)
-#        serializer = TreeSerializer(item_width=self.item_width, indices_width=(self.indices_width+1), stack_depth=self.stack_depth, serializing_ruleset=[])
-        #m.submodules.Stack = stack
-        m.submodules.Stacks = doublestacks
-        m.submodules.RuleMatcher = rule_matcher
-        m.submodules.RuleExecute = rex
-        m.submodules.skidbuffer = skbuffer
-
-        serializer = m.submodules.Serializer = self.serializer
-
-
-        # Skid buffer
-        fsm_ready = Signal(1)
-        new_item_valid = Signal(1)
-        new_item = Signal(self.item_width)
-
-
-        m.d.comb += skbuffer.upstream_valid_in.eq(self.data_in_valid)
-        m.d.comb += self.data_in_ready.eq(skbuffer.upstream_ready_out)
-        m.d.comb += skbuffer.upstream_data_in.eq(self.data_in)
-
-        m.d.comb += skbuffer.downstream_ready_in.eq(fsm_ready)
-        m.d.comb += new_item.eq(skbuffer.downstream_data_out)
-        m.d.comb += new_item_valid.eq(skbuffer.downstream_valid_out)
-
-
-        execution_result = Signal(self.item_width)
-        number_to_pop = Signal(8)
-
-
-        m.d.comb += rex.match_index_in.eq(rule_matcher.match_index_out)
-        m.d.comb += rule_matcher.occupancy_bitmap_in.eq(doublestacks.occupancy_bitmap)
-        for idx, x in enumerate(doublestacks.bigperm_out):
-            m.d.comb += rule_matcher.stack_view_in[idx].eq(x)
-            m.d.comb += rex.stack_view_in[idx].eq(x)
-
-        m.d.comb += rule_matcher.new_item_in.eq(new_item)
-
-
-        # Rule Matcher output signals are:
-        #
-        # internal_fault  (one bit)
-        # invalid_item    (one bit)
-        # force_shift     (one bit)
-        # match_index_out (one hot)
-
-
-        # LR parser state machine
-        with m.FSM() as fsm:
-
-            with m.State("INITIALIZE"):
-                m.next = "SHIFTREDUCE"
-                m.d.comb += fsm_ready.eq(0)
-                m.d.comb += doublestacks.command_in_strobe.eq(1)
-                m.d.comb += doublestacks.big_push_port.eq(self.startofparse_marker)
-                m.d.comb += doublestacks.side_push_port.eq(0x0) # XXX FIXME
-                m.d.comb += doublestacks.command_in.eq(2)
-
-                with m.If(doublestacks.internal_fault | serializer.internal_fault == 1):
-                    m.next="ABORT"
-
-
-            with m.State("SHIFTREDUCE"):
-                with m.If(new_item_valid == 1):
-                    with m.If(rule_matcher.internal_fault == 1):
-                        m.next = "ABORT"
-                        m.d.comb += fsm_ready.eq(0)
-                        m.d.comb += doublestacks.command_in_strobe.eq(0)
-
-                    with m.If(doublestacks.internal_fault | serializer.internal_fault == 1):
-                        m.next="ABORT"
-
-                    with m.If(rule_matcher.invalid_item   == 1):
-                        m.next = "ABORT"
-                        m.d.comb += fsm_ready.eq(0)
-                        m.d.comb += doublestacks.command_in_strobe.eq(0)
-
-                    with m.If(rule_matcher.force_shift    == 1):
-                        m.d.comb += doublestacks.command_in.eq(2)
-                        m.d.comb += doublestacks.command_in_strobe.eq(1)
-                        m.d.comb += doublestacks.big_push_port.eq(new_item)
-                        m.d.comb += doublestacks.side_push_port.eq(0x0) # XXX FIXME
-                        m.d.comb += fsm_ready.eq(1)
-
-                    with m.If((rule_matcher.force_shift == 0) & (rule_matcher.match_index_out == 0)):
-                        m.next = "ABORT"
-                        m.d.comb += fsm_ready.eq(0)
-                        m.d.comb += doublestacks.command_in_strobe.eq(0)
-
-                    with m.If((serializer.ready_out == 1)& (rule_matcher.match_index_out != 0)):
-                        m.next = "REDUCE"
-                        m.d.comb += fsm_ready.eq(0)
-                        #m.d.comb += stack.command_in_strobe.eq(0)
-                        # register the data from the combinatorial CAMs since the stack will change when we manipulate it
-
-                        m.d.sync += number_to_pop.eq(rex.number_to_pop - 1)
-                        m.d.sync += execution_result.eq(rex.created_item)
-
-
-                        m.d.comb += serializer.start_reduction.eq(1)
-                        m.d.comb += serializer.destroyed_item_valid_in.eq(1)
-
-                        m.d.comb += serializer.destroyed_item_in.eq(doublestacks.bigpop_port)
-                        m.d.comb += serializer.destroyed_item_index_in.eq(doublestacks.sidepop_port)
-
-
-                        m.d.comb += serializer.number_to_pop.eq(rex.number_to_pop)
-                        m.d.comb += serializer.item_created_by_reduce_rule.eq(rex.created_item)
-                        m.d.comb += serializer.reduce_rule_number.eq(rule_matcher.match_index_out)
-
-                        with m.If(rex.number_to_pop != 0):
-                            m.d.comb += doublestacks.command_in.eq(1)
-                            m.d.comb += doublestacks.command_in_strobe.eq(1)
-
-                    with m.If(rule_matcher.endofparse_reached == 1):
-                        m.next = "SUCCESS"
-                        m.d.comb += self.internal_fault.eq(1)
-                        m.d.comb += self.parse_success_out.eq(1)
-                        m.d.comb += self.parse_complete_out.eq(1)
-
-            with m.State("SUCCESS"):
-                m.next = "SUCCESS"
-                m.d.comb += self.internal_fault.eq(1)
-                m.d.comb += self.parse_success_out.eq(1)
-                m.d.comb += self.parse_complete_out.eq(1)
-                m.d.sync += self.last_index_to_smem.eq(serializer.serialized_index)
-
-                with m.If(doublestacks.internal_fault | serializer.internal_fault == 1):
-                    m.next="ABORT"
-
-
-            with m.State("REDUCE"):
-                m.d.comb += fsm_ready.eq(0)
-
-                # FIXME XXX make this into an FSM
-                with m.If(number_to_pop != 0):
-
-                    m.d.comb += serializer.destroyed_item_valid_in.eq(1)
-                    m.d.comb += serializer.destroyed_item_in.eq(doublestacks.bigpop_port)
-                    m.d.comb += serializer.destroyed_item_index_in.eq(doublestacks.sidepop_port)
-
-                    m.d.comb += doublestacks.command_in.eq(1)
-                    m.d.comb += doublestacks.command_in_strobe.eq(1)
-                    m.d.sync += number_to_pop.eq(number_to_pop - 1)
-
-                with m.If(number_to_pop == 0):
-                    m.d.comb += doublestacks.command_in.eq(2)
-                    m.d.comb += doublestacks.big_push_port.eq(execution_result)
-                    m.d.comb += doublestacks.side_push_port.eq(serializer.serialized_index | (1<<(self.indices_width)))
-                    m.d.comb += doublestacks.command_in_strobe.eq(1)
-
-#                    m.d.comb += fsm_ready.eq(1)
-                    
-                    m.next = "SHIFTREDUCE"
-
-                with m.If(doublestacks.internal_fault | serializer.internal_fault == 1):
-                    m.next="ABORT"
-
-
-            with m.State("ABORT"):
-                m.d.comb += fsm_ready.eq(0)
-                m.d.comb += doublestacks.command_in_strobe.eq(0)
-
-                m.d.comb += self.internal_fault.eq(1)
-                m.d.comb += self.parse_success_out.eq(0)
-                m.d.comb += self.parse_complete_out.eq(1)
 
         return m
 
 
-
 class DummyPlug(Elaboratable):
 
-    def elaborate(self, platform):
-        cntr = Signal(8)
-        resetted = Signal(1)
-
-        valid_data_out = Signal(1)
-        romem_ready = Signal(1)
-        data_port = Signal(16)
+    #def __init__(self):
 
 
-        BOTTOM      = 0x5a00
-        ENDOFPARSE  = 0x5500
-
-        EXPRESSION  = 0xEE00
-        TERM        = 0xE700
-        FACTOR      = 0xEF00
-        INTEGER     = 0xE100
-
-        OPENPAREN   = 0xCA00
-        CLOSEPAREN  = 0xCB00
-
-        ADDOP       = 0xAA00
-        MULTOP      = 0xAB00
-        STDMASK     = 0xff00
 
+    def elaborate(self, platform):
         m = Module()
-        # BOTTOM = start of parse
-        mem = Memory(width=16, depth=256, init=[OPENPAREN, OPENPAREN, 0XE102, CLOSEPAREN, ADDOP, 0XE103, CLOSEPAREN, ADDOP, 0XE101, ENDOFPARSE])
-        m.submodules.parse_data = rdport = mem.read_port()
-
-
-        common_stack_states = [
-        # State 0 in the paper
-        # Bottom of parse stack
-        [(0, STDMASK, BOTTOM)],
-
-        # State 1 in the paper
-        # Bottom of parse stack        Expression
-        [(1, STDMASK, BOTTOM),          (0, STDMASK, EXPRESSION)],
-
-        # state 2 in paper
-        # TERM
-        [(0, STDMASK, TERM)],
-
-        # state 3 in paper
-        # FACTOR
-        [(0, STDMASK, FACTOR)],
-
-        # State 4 in paper
-        # OPEN PAREN
-        [(0, STDMASK, OPENPAREN)],
-
-        # State 5 in paper
-        # INTEGER
-        [(0, STDMASK, INTEGER)],
-
-        # State 6 in paper
-        # EXPRESSION             PLUS
-        [(1, STDMASK, EXPRESSION), (0, STDMASK, ADDOP)],
-
-        # State 7 in paper
-        # TERM                     MULTIPLY
-        [(1, STDMASK, TERM), (0, STDMASK, MULTOP)],
-
-        # State 8 in paper
-        # OPEN PAREN             EXPRESSION
-        [(1, STDMASK, OPENPAREN), (0, STDMASK, EXPRESSION)],
-
-        # State 9 in paper
-        #  EXPRESSION             PLUS                 TERM
-        [(2, STDMASK, EXPRESSION), (1, STDMASK, ADDOP), (0, STDMASK, TERM)],
-
-        # State 10 in paper
-        # TERM                    MULTIPLY             FACTOR
-        [(2, STDMASK, TERM), (1, STDMASK, MULTOP), (0, STDMASK, FACTOR)],
-
-        # State 11 in paper
-        # OPEN PAREN             EXPRESSION             CLOSE PAREN
-        [(2, STDMASK, OPENPAREN), (1, STDMASK, EXPRESSION), (0, STDMASK, CLOSEPAREN)]
-        ]
-
-        pairwise_priority_ruleset = [(1,8),(2,9), (3,10)]
-
-
-
-        validitem_ruleset = [
-        # For state 0:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 1:
-        [(STDMASK, ADDOP),                                           (STDMASK, ENDOFPARSE)],
-        # For state 2:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        # For state 3:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        # For state 4:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 5:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        # For state 6:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 7:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 8:
-        [(STDMASK, ADDOP),                    (STDMASK, CLOSEPAREN)],
-        # For state 9:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        # For state 10:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        # For state 11:
-        [(STDMASK, ADDOP), (STDMASK, MULTOP), (STDMASK, CLOSEPAREN), (STDMASK, ENDOFPARSE)],
-        ]
-
-
-        forceshift_ruleset = [
-        # For state 0:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 1:
-        [(STDMASK, ADDOP),                                           (STDMASK, ENDOFPARSE)],
-        # For state 2:
-        [(STDMASK, MULTOP)],
-        # For state 3:
-        [],
-        # For state 4:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 5:
-        [],
-        # For state 6:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 7:
-        [(STDMASK, INTEGER),                  (STDMASK, OPENPAREN)],
-        # For state 8:
-        [(STDMASK, ADDOP),                    (STDMASK, CLOSEPAREN)],
-        # For state 9:
-        [(STDMASK, MULTOP)],
-        # For state 10:
-        [],
-        # For state 11:
-        []
-        ]
-
-
-        reduce_ruleset = [
-        # For state 0:
-        [],
-        # For state 1:
-        [],
-        # For state 2:
-        [((STDMASK, ADDOP),1), ((STDMASK, CLOSEPAREN),1), ((STDMASK, ENDOFPARSE),1)],
-        # For state 3:
-        [((STDMASK, ADDOP),3), ((STDMASK, MULTOP),3), ((STDMASK, CLOSEPAREN),3), ((STDMASK, ENDOFPARSE),3)],
-        # For state 4:
-        [],
-        # For state 5:
-        [((STDMASK, ADDOP),5), ((STDMASK, MULTOP),5), ((STDMASK, CLOSEPAREN),5), ((STDMASK, ENDOFPARSE),5)],
-        # For state 6:
-        [],
-        # For state 7:
-        [],
-        # For state 8:
-        [],
-        # For state 9:
-        [((STDMASK, ADDOP),0), ((STDMASK, CLOSEPAREN),0), ((STDMASK, ENDOFPARSE),0)],
-        # For state 10:
-        [((STDMASK, ADDOP),2), ((STDMASK, MULTOP),2), ((STDMASK, CLOSEPAREN),2), ((STDMASK, ENDOFPARSE),2)],
-        # For state 11:
-        [((STDMASK, ADDOP),4), ((STDMASK, MULTOP),4), ((STDMASK, CLOSEPAREN),4), ((STDMASK, ENDOFPARSE),4)],
-        ]
-
-        def extractor(x): return (x & 0x00ff)
-        execute_rules = [
-        (3, (lambda stackview: EXPRESSION + (extractor(stackview[0]) + extractor(stackview[2])))),
-
-        (1, (lambda stackview: EXPRESSION + extractor(stackview[0]))),
-
-        (3, (lambda stackview: TERM + (extractor(stackview[0]) * extractor(stackview[2])))),
-
-        (1, (lambda stackview: TERM + extractor(stackview[0]))),
-
-        (3, (lambda stackview: FACTOR + extractor(stackview[1]))),
-
-        (1, (lambda stackview: FACTOR + extractor(stackview[0])))
-        ]
-
-        msm = MasterStateMachine(item_width=16, indices_width=16, stack_depth=10,
-            validitem_ruleset = validitem_ruleset,
-            pairwise_priority_ruleset = pairwise_priority_ruleset,
-            forceshift_ruleset = forceshift_ruleset,
-            reduce_ruleset=reduce_ruleset,
-            execute_rules=execute_rules, stack_state_descriptions=common_stack_states, startofparse_marker = 0x5a00, endofparse_marker=(0xffff, ENDOFPARSE))
-
-        m.submodules.StateMachine = msm
-
-
-        with m.If(resetted == 0):
-            m.d.sync += resetted.eq(1)
-        with m.If(resetted == 1):
-            m.d.comb += msm.data_in_valid.eq(1)
-
-        stall_recovery = Signal(1)
 
-        cashew_register = Signal(16)
-        m.d.sync += stall_recovery.eq(msm.data_in_ready) # one-cycle-delayed
+        m.submodules.stack = ParseStack(8,8)
+        counter = Signal(8)
+        m.d.sync += counter.eq(counter+1)
 
-        with m.If(msm.data_in_ready == 1):
-            m.d.sync += cntr.eq(cntr + 1)
-            m.d.comb += msm.data_in.eq((rdport).data)
+        with m.If(counter==1):
+            m.d.comb += m.submodules.stack.strobe.eq(1)
+            m.d.comb += m.submodules.stack.in_valid.eq(1)
+            m.d.comb += m.submodules.stack.in_data_port.eq(42)
 
-        with m.If((msm.data_in_ready == 0) & (stall_recovery == 1)):
-            m.d.sync += cashew_register.eq(rdport.data)
-            m.d.comb += msm.data_in.eq((rdport).data)
 
-        with m.If(stall_recovery == 0):
-            m.d.comb += msm.data_in.eq(cashew_register)
+        with m.If(counter==2):
+            m.d.comb += m.submodules.stack.command_port.eq(0)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
+            m.d.comb += m.submodules.stack.in_valid.eq(1)
+            m.d.comb += m.submodules.stack.in_data_port.eq(43)
 
+        with m.If(counter==3):
+            m.d.comb += m.submodules.stack.command_port.eq(0)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
+            m.d.comb += m.submodules.stack.in_valid.eq(1)
+            m.d.comb += m.submodules.stack.in_data_port.eq(44)
 
-        m.d.comb += (rdport).addr.eq(cntr)
+        with m.If(counter==4):
+            m.d.comb += m.submodules.stack.command_port.eq(1)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
 
+        with m.If(counter==5):
+            m.d.comb += m.submodules.stack.command_port.eq(1)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
 
 
-#        egg_0 = platform.request("led",0)
-#        egg_1 = platform.request("led",1)
-#        egg_2 = platform.request("led",2)
-#        egg_3 = platform.request("led",3)
-#        egg_4 = platform.request("led",4)
-#        egg_5 = platform.request("led",5)
-#        egg_6 = platform.request("led",6)
-#        egg_7 = platform.request("led",7)
-#
-#        oeuf = Cat(egg_0, egg_1, egg_2, egg_3, egg_4, egg_5, egg_6, egg_7)
-#        m.d.comb += oeuf.eq(msm.data_out[8:15] ^ msm.data_out[0:7])
+        with m.If(counter==6):
+            m.d.comb += m.submodules.stack.command_port.eq(1)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
+        with m.If(counter==7):
+            m.d.comb += m.submodules.stack.command_port.eq(1)
+            m.d.comb += m.submodules.stack.strobe.eq(1)
         return m
 
 
 
 if __name__ == '__main__':
-    platform = ICE40HX8KBEVNPlatform()
     baka =DummyPlug()
     main(baka)
     #platform.build(DummyPlug())