def add_constant(self, const: Constant) -> bool:
     """! @brief Add a new Constant to this AsModuleGroup.
     If a constant with the same code_name is already present, do nothing.
     Returns True on success, False if the Constant has a duplicate name."""
     # Check if the new constant has a duplicate name
     if any((const.code_name == c.code_name for c in self.constants)):
         return False
     # Otherwise, associate the constant with this group and add it
     const.assign_to(self)
     self.constants.append(const)
    def set_config_constant(self, const: Constant) -> bool:
        """! @brief Define the Constant defining the register configuration.
        Set the configuration constant, defining the register types of
        this interface. This method expects a Constant object,
        defined in as_automatics_constant.py."""
        # Is the config constant already assigned?
        if self.config is None:
            # Check if the config constants prefix and suffix
            # match those of the ports
            this_prefix, this_suffix = as_help.get_prefix_suffix(
                const.name, const.code_name, [])
            if (this_suffix != self.name_suffix) or (this_prefix !=
                                                     self.name_prefix):
                LOG.debug(
                    ("Config constant '%s' didn't fit, "
                     "prefix/suffix mismatch!"),
                    const.code_name,
                )
                return False
            # If the names match
            if const.name == self.CONST_NAME:
                # Log some data about the constant. Implicitely checks type
                try:
                    LOG.debug(
                        ("Check constant '%s': data type: '%s',"
                         " value: '%s'"),
                        const.code_name,
                        const.data_type,
                        const.value,
                    )
                except AttributeError:
                    LOG.warning("set_config_constant was passed a wrong type!")
                    raise TypeError("set_config_constant")

                # If we get to here, the constant should be fine
                LOG.debug(
                    "Assigned config constant '%s' to '%s'",
                    const.code_name,
                    str(self.parent),
                )
                const.assign_to(self)
                self.config = const
                self.config_applied = False
                return True
        else:
            LOG.debug("Config constant already set!")
            return False
        return False
    def __get_constant__(self, file_obj) -> str:
        # Make sure the current line is the complete constant definition
        if ";" not in self.line:
            self.line = self.line.strip(" \n") + self.__next_clean_statement__(
                file_obj)
        # Clean current line, remove the 'constant' keyword and split on ':'
        words = self.line.replace("constant", "", 1).strip(" \n").split(":", 1)
        if len(words) > 1:  # Was there a ':' in this line?
            # If so, we can extract the constant's name
            name = words[0].strip()
            # Split on value assignment
            words = words[1].strip().split(":=", 1)
            if len(words) > 1:  # Was there a ':=' in this line?
                # If so, we can extract both the data type and value.
                data_type = words[0].strip()
                value = words[1].strip(" ;").upper()
                data_width = Port.DataWidth(1, None, None)
                # If the data type is a vector (contains a "(a to/downto b)")
                if "(" in data_type:
                    words = data_type.strip().split("(", maxsplit=1)
                    data_type = words[0].strip()
                    # Get the data width (remove closing bracket)
                    data_width = self.__get_data_width__(words[1][:-1])

                # That's all infos for this constant! Create and add it:
                self.found_constants.append(
                    Constant(
                        code_name=name,
                        data_type=data_type,
                        value=value,
                        data_width=data_width,
                    ))
                LOG.debug(
                    "Found constant '%s' of type '%s' with value '%s'",
                    name,
                    data_type,
                    value,
                )
                return ""

            LOG.error(
                ("Malformed 'constant' declaration: '%s' in '%s': "
                 "Missing ':='!"),
                self.line,
                file_obj.name,
            )
            return "malformed constant declaration"

        LOG.error(
            ("Malformed 'constant' declaration: '%s' in '%s': "
             "Missing ':'!"),
            self.line,
            file_obj.name,
        )
        return "malformed constant declaration"
Beispiel #4
0
 def test_set_config_constant(self):
     LOG.debug("*UNITTEST* <running test_set_config_constant>")
     testconfig = Constant(
         name="slave_register_configuration",
         value='("11","11","01","01","01","10","10","00");',
     )
     # setUp() already adds a config constant, this should fail
     self.assertFalse(self.regif.set_config_constant(testconfig))
     # Remove the present config and check if that worked
     self.regif.clear_config_const()
     self.assertIsNone(self.regif.config, "clear_config_const failed!")
     # Try to add a Port object as the config. This should raise a TypeError
     testport = Port(name="slave_register_configuration")
     with self.assertRaises(TypeError):
         self.regif.set_config_constant(testport)
     # Try to add a config with an invalid suffix
     testconfig.code_name = "slave_register_configuration_42"
     self.assertFalse(self.regif.set_config_constant(testconfig))
     # Try to add a valid config constant
     testconfig.code_name = "slave_register_configuration"
     self.assertTrue(self.regif.set_config_constant(testconfig))
    def _add_register_interface(self):
        """! @brief Add a register interface to this module group.
        This method defines and adds the necessary signals to this module group
        comrising an ASTERICS slave register interface.
        This method is called by methods adding port-register connections."""
        # Slave register interface:
        # Create ports for the slave register interface

        ctrl_reg = Port(
            "slv_ctrl_reg",
            data_type="slv_reg_data",
            data_width=Port.DataWidth(0, "to", 0),
        )
        status_reg = Port(
            "slv_status_reg",
            direction="out",
            data_type="slv_reg_data",
            data_width=Port.DataWidth(0, "to", 0),
        )
        mod_reg = Port(
            "slv_reg_modify",
            direction="out",
            data_type="std_logic_vector",
            data_width=Port.DataWidth(0, "to", 0),
        )
        config_reg = Port(
            "slv_reg_config",
            direction="out",
            data_type="slv_reg_config_table",
            data_width=Port.DataWidth(0, "to", 0),
        )
        config_const = Constant(
            "slave_register_configuration",
            data_type="slv_reg_config_table",
            data_width=Port.DataWidth(0, "to", 0),
            value="()",
        )
        self.entity_ports = [config_reg, ctrl_reg, status_reg, mod_reg]
        self.entity_constants = [config_const]
        self.constants = [config_const]

        self.__assign_interfaces__()

        reginter = self.get_slave_register_interface()
        self.register_if = reginter
        self.regmod = self.define_signal("reg_modify_vect", "std_logic_vector")
        # Hack to suppress neutral value assignment; Assigned object is not used
        config_reg.incoming = config_const
        status_reg.incoming = config_const

        mod_reg.connect(self.regmod)
Beispiel #6
0
 def setUp(self):
     self.regif = SlaveRegisterInterface()
     testports = [
         Port(name="slv_status_reg",
              data_type="slv_reg_data",
              direction="out"),
         Port(name="slv_reg_modify",
              data_type="std_logic_vector",
              direction="out"),
         Port(name="slv_reg_config",
              data_type="slv_reg_config_table",
              direction="out"),
     ]
     self.regif.ports = testports
     self.regif.config = Constant(
         name="slave_register_configuration",
         value='("11","11","01","01","01","10","10","00");',
     )
Beispiel #7
0
 def test_decode_slvreg_table(self):
     LOG.debug("*UNITTEST* <running test_decode_slvreg_table>")
     # Prepare a config constant with too many definitions
     testconfig_h = Constant(
         name="slave_register_configuration",
         value=('("11","11","01","01","01","10",'
                '"10","00","00","00");'),
     )
     result_h = [
         "HW <=> SW",
         "HW <=> SW",
         "HW -> SW",
         "HW -> SW",
         "HW -> SW",
         "HW <- SW",
         "HW <- SW",
         "None",
         "None",
         "None",
     ]
     # And one with too few
     testconfig_l = Constant(
         name="slave_register_configuration",
         value='("11","11","01","01","01","10");',
     )
     result_l = [
         "HW <=> SW",
         "HW <=> SW",
         "HW -> SW",
         "HW -> SW",
         "HW -> SW",
         "HW <- SW",
     ]
     # One with the correct number of definitions including an invalid value
     testconfig_i = Constant(
         name="slave_register_configuration",
         value=('("11","11","21","01",'
                '"01","10","00","00");'),
     )
     # Another one that uses the "(others => X)" syntax
     testconfig_o = Constant(
         name="slave_register_configuration",
         value='("11","11","01",(others => "10");',
     )
     result_o = ["HW <=> SW", "HW <=> SW", "HW -> SW", "HW <- SW"]
     # Another one now with an invalid value in the others-clause
     testconfig_oi = Constant(
         name="slave_register_configuration",
         value='("11","11","01",(others => "12");',
     )
     # Run the decoding (indirectly) for the setUp config and compare
     # to the expected result: (2, 3, 2)
     self.assertEqual(self.regif.get_register_numbers(), (2, 3, 2))
     # Set a different config
     self.regif.clear_config_const()
     self.regif.config = testconfig_h
     # Directly call the decode function.
     # Using a config with ten registers, check if all are recognized:
     self.assertTrue(self.regif.__decode_slvreg_table__())
     self.assertEqual(self.regif.reg_count, 7)
     self.assertEqual(self.regif.register_table, result_h)
     # Same test, now using the config with fewer definitions
     self.regif.clear_config_const()
     self.regif.config = testconfig_l
     self.assertTrue(self.regif.__decode_slvreg_table__())
     self.assertEqual(self.regif.reg_count, 6)
     self.assertEqual(self.regif.register_table, result_l)
     # Same test, now using the config with an invalid value
     self.regif.clear_config_const()
     self.regif.config = testconfig_i
     self.assertFalse(self.regif.__decode_slvreg_table__())
     # Now using the config with the others-clause
     self.regif.clear_config_const()
     self.regif.config = testconfig_o
     # This should work and return a result
     self.assertEqual(self.regif.get_register_numbers(), (2, 1, 1))
     self.assertEqual(self.regif.register_table, result_o)
     # Now using the config with an invalid value in the others-clause
     self.regif.clear_config_const()
     self.regif.config = testconfig_oi
     self.assertFalse(self.regif.__decode_slvreg_table__())
    def assign_trained_values(self, weights: list, biases: list,
                              quant_mults: list):
        filter_count = self.get_generic("FILTER_COUNT").get_value()
        kernel_size = self.get_generic("KERNEL_SIZE").get_value()
        # Depth of pipeline in module: 4 + (filter_count - 1)
        self.processing_delay += filter_count - 1

        # Generate kernel weight value string
        channel_count = self.get_generic("CHANNEL_COUNT").get_value()
        kernel_str = weights_to_string_for_serial_filter(
            weights, channel_count, filter_count)

        # Calculate quantization BIAS extension from weights
        weights_per_filter = len(weights) // filter_count
        biases = tuple(biases)
        biases_new = []
        for f_idx in range(filter_count):
            biases_new.append(
                calc_extended_quantized_bias(
                    weights[weights_per_filter * f_idx:weights_per_filter *
                            (f_idx + 1)],
                    biases[f_idx],
                ))

        # Convert values to strings
        if filter_count == 1:
            kernel_str = "(0 => " + kernel_str[1:]
            qmult_str = "(0 => {})".format(quant_mults[0])
            biases_str = "(0 => {})".format(biases_new[0])
        else:
            qmult_str = str(tuple(quant_mults))
            biases_str = str(tuple(biases_new))

        kernel_const_name = self.name + "_kernel_values"
        biases_const_name = self.name + "_bias_values"
        quant_mults_const_name = self.name + "_quantization_factors"

        # Create constants for each value type
        kernel_value_const = Constant(
            kernel_const_name,
            kernel_const_name,
            "t_generic_filter_array",
            kernel_str,
            "(0 to {filter_count}, 0 to {channel_count}, 0 to {kernel_values})"
            .format(
                filter_count=filter_count - 1,
                channel_count=channel_count - 1,
                kernel_values=(kernel_size**2) - 1,
            ),
        )
        biases_value_const = Constant(
            biases_const_name,
            biases_const_name,
            "t_integer_array",
            biases_str,
            Port.DataWidth(0, "to", filter_count - 1),
        )
        quant_mult_const = Constant(
            quant_mults_const_name,
            quant_mults_const_name,
            "t_real_array",
            qmult_str,
            Port.DataWidth(0, "to", filter_count - 1),
        )
        self.parent.add_constant(kernel_value_const)
        self.parent.add_constant(biases_value_const)
        self.parent.add_constant(quant_mult_const)

        # Assign constants to the generics
        self.set_generic_value("KERNEL_VALUES", kernel_const_name)
        self.set_generic_value("BIAS_VALUES", biases_const_name)
        self.set_generic_value("QUANTIZATION_MULTIPLIERS",
                               quant_mults_const_name)