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"
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)
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");', )
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)