def expose_internal_scheduling_signals(self,
                                           num_rules_per_module=None,
                                           scheduling_order=None,
                                           add_force_fire=False):
        # if schedule isn't provided, assume rules first then modules
        if scheduling_order is None:
            scheduling_order = [
                'RL_' + x for x in self.get_rules_in_scheduling_order()
            ] + ['MODULE_' + x for x, y in self.get_submodules()]
        instance_to_module = {x: y for x, y in self.get_submodules()}
        can_fires = []
        will_fires = []
        # compute total number of bits
        total_num_bits = 0
        for name in scheduling_order:
            if name.startswith('RL_'):
                total_num_bits += 1
            elif name.startswith('MODULE_'):
                instance_name = name[len('MODULE_'):]
                module_name = instance_to_module[instance_name]
                if num_rules_per_module is None:
                    continue
                if module_name not in num_rules_per_module:
                    continue
                num_submodule_rules = num_rules_per_module[module_name]
                if num_submodule_rules == 0:
                    continue
                total_num_bits += num_submodule_rules
        # now add the signals
        curr_bit_index = 0
        for name in scheduling_order:
            if name.startswith('RL_'):
                self.add_decls('BLOCK_FIRE_' + name, ast.Wire)
                if add_force_fire:
                    self.add_decls('FORCE_FIRE_' + name, ast.Wire)
                # definition of BLOCK_FIRE and FORCE_FILE
                assign = self.get_assign('WILL_FIRE_' + name)
                if add_force_fire:
                    new_rhs = ast.Or(
                        ast.Identifier('FORCE_FIRE_' + name),
                        ast.And(ast.Unot(ast.Identifier('BLOCK_FIRE_' + name)),
                                assign.right.var))
                else:
                    new_rhs = ast.And(
                        ast.Unot(ast.Identifier('BLOCK_FIRE_' + name)),
                        assign.right.var)
                assign.right.var = new_rhs
                # definition of BLOCK_FIRE_* and FORCE_FIRE_* signals from top-level BLOCK_FIRE and FORCE_FIRE
                if total_num_bits == 1:
                    self.add_assign('BLOCK_FIRE_' + name,
                                    ast.Identifier('BLOCK_FIRE'))
                    if add_force_fire:
                        self.add_assign('FORCE_FIRE_' + name,
                                        ast.Identifier('FORCE_FIRE'))
                else:
                    self.add_assign(
                        'BLOCK_FIRE_' + name,
                        ast.Partselect(ast.Identifier('BLOCK_FIRE'),
                                       ast.IntConst(curr_bit_index),
                                       ast.IntConst(curr_bit_index)))
                    if add_force_fire:
                        self.add_assign(
                            'FORCE_FIRE_' + name,
                            ast.Partselect(ast.Identifier('FORCE_FIRE'),
                                           ast.IntConst(curr_bit_index),
                                           ast.IntConst(curr_bit_index)))
                curr_bit_index += 1
                can_fires.append(ast.Identifier('CAN_FIRE_' + name))
                will_fires.append(ast.Identifier('WILL_FIRE_' + name))
            elif name.startswith('MODULE_'):
                instance_name = name[len('MODULE_'):]
                module_name = instance_to_module[instance_name]
                if num_rules_per_module is None:
                    continue
                if module_name not in num_rules_per_module:
                    continue
                num_submodule_rules = num_rules_per_module[module_name]
                if num_submodule_rules == 0:
                    continue
                instance = self.get_instance(instance_name)
                for signal_type in [
                        'CAN_FIRE', 'WILL_FIRE', 'BLOCK_FIRE', 'FORCE_FIRE'
                ]:
                    if signal_type == 'FORCE_FIRE' and not add_force_fire:
                        continue
                    # declarations of all FIRE signals for the submodule
                    self.add_decls(signal_type + '_' + name,
                                   ast.Wire,
                                   width=num_submodule_rules)
                    # connection of all FIRE signals to the submodule
                    # this assumes the submodule has ports named CAN_FIRE, WILL_FIRE, BLOCK_FIRE, and if add_force_fire is true, FORCE_FIRE
                    instance.portlist += (ast.PortArg(
                        signal_type,
                        ast.Identifier(signal_type + '_' + name)), )
                # assignments of BLOCK_FIRE_* and FORCE_FIRE_* signals from top-level BLOCK_FIRE and FORCE_FIRE
                lsb = curr_bit_index
                msb = curr_bit_index + num_submodule_rules - 1
                curr_bit_index += num_submodule_rules
                if total_num_bits == 1:
                    self.add_assign('BLOCK_FIRE_' + name,
                                    ast.Identifier('BLOCK_FIRE'))
                    if add_force_fire:
                        self.add_assign('FORCE_FIRE_' + name,
                                        ast.Identifier('FORCE_FIRE'))
                else:
                    self.add_assign(
                        'BLOCK_FIRE_' + name,
                        ast.Partselect(ast.Identifier('BLOCK_FIRE'),
                                       ast.IntConst(msb), ast.IntConst(lsb)))
                    if add_force_fire:
                        self.add_assign(
                            'FORCE_FIRE_' + name,
                            ast.Partselect(ast.Identifier('FORCE_FIRE'),
                                           ast.IntConst(msb),
                                           ast.IntConst(lsb)))
                can_fires.append(ast.Identifier('CAN_FIRE_' + name))
                will_fires.append(ast.Identifier('WILL_FIRE_' + name))
            elif name.startswith('METH_'):
                raise ValueError(
                    '"METH_" scheduling signals are not supported yet')
            else:
                raise ValueError('unexpected entry "%s" in scheduling_order' %
                                 name)

        if total_num_bits != 0:
            # new ports
            self.add_ports(['CAN_FIRE', 'WILL_FIRE', 'BLOCK_FIRE'])
            if add_force_fire:
                self.add_ports(['FORCE_FIRE'])
            self.add_decls('CAN_FIRE', ast.Output, width=total_num_bits)
            self.add_decls('WILL_FIRE', ast.Output, width=total_num_bits)
            self.add_decls('BLOCK_FIRE', ast.Input, width=total_num_bits)
            if add_force_fire:
                self.add_decls('FORCE_FIRE', ast.Input, width=total_num_bits)
            self.add_decls('CAN_FIRE', ast.Wire, width=total_num_bits)
            self.add_decls('WILL_FIRE', ast.Wire, width=total_num_bits)
            # connect CAN_FIRE and WILL_FIRE
            can_fires.reverse()
            will_fires.reverse()
            self.add_assign('CAN_FIRE', ast.Concat(can_fires))
            self.add_assign('WILL_FIRE', ast.Concat(will_fires))

        return total_num_bits
Exemple #2
0
 def visit_Cat(self, node):
     vars = tuple([self.visit(var) for var in node.vars])
     return vast.Concat(vars)