def __init__(self, config_data_width: int): super().__init__("PowerDomainOR") self.not_gate = FromMagma(mantle.DefineInvert(1)) self._and_gate = [None] * config_data_width for i in range(config_data_width): self._and_gate[i] = FromMagma(mantle.DefineAnd(2, 1)) for i in range(config_data_width): self.wire(self._and_gate[i].ports.I1[0], self.not_gate.ports.O[0]) self._or_gate = FromMagma(mantle.DefineOr(2, config_data_width)) for i in range(config_data_width): self.wire(self._and_gate[i].ports.O[0], self._or_gate.ports.I0[i]) # only add necessary ports here so that we can replace without # problem self.add_ports(I0=magma.In(magma.Bits[config_data_width]), I1=magma.In(magma.Bits[config_data_width]), O=magma.Out(magma.Bits[config_data_width])) for i in range(config_data_width): self.wire(self.ports.I0[i], self._and_gate[i].ports.I0[0]) self.wire(self.ports.I1, self._or_gate.ports.I1) self.wire(self._or_gate.ports.O, self.ports.O)
def tile_to_feature(tile, tile_eq, feature, feature_idx): feature.add_ports(config_en=magma.In(magma.Bit)) feature_eq = FromMagma(mantle.DefineEQ(8)) tile.wire(tile.config.config_addr[16:24], feature_eq.I0) tile.wire(Const(magma.bits(feature_idx, 8)), feature_eq.I1) feature_en = FromMagma(mantle.DefineAnd()) tile.wire(feature_eq.O, feature_en.I0) tile.wire(tile_eq.O, feature_en.I1) tile.wire(feature_en.O, feature.config_en)
def __init__(self, num_inputs, width, sel_bits, default): super().__init__() self.num_inputs = num_inputs self.width = width self.sel_bits = sel_bits self.default = default if 2**self.sel_bits <= self.num_inputs: raise ValueError(f"(2 ^ sel_bits) must be > num_inputs " f"(sel_bits={self.sel_bits}, " f"num_inputs={self.num_inputs})") self.data_mux = MuxWrapper(self.num_inputs, self.width) self.default_mux = MuxWrapper(2, self.width) lt = mantle.DefineULT(self.sel_bits) and_gate = mantle.DefineAnd(2) self.lt = FromMagma(lt) self.and_gate = FromMagma(and_gate) T = magma.Bits[self.width] self.add_ports( I=magma.In(magma.Array[self.num_inputs, T]), S=magma.In(magma.Bits[self.sel_bits]), EN=magma.In(magma.Bits[1]), O=magma.Out(T), ) # Wire data inputs to data mux. for i in range(self.num_inputs): self.wire(self.ports.I[i], self.data_mux.ports.I[i]) # Wire select input to select input of data_mux. Note that we only wire # the first clog2(num_inputs) bits of the select input. self.wire(self.ports.S[:self.data_mux.sel_bits], self.data_mux.ports.S[:self.data_mux.sel_bits]) # Wire default value to first input of default mux, and output of # data_mux to second input of default mux. default_mux_inputs = [ Const(magma.bits(self.default, self.width)), self.data_mux.ports.O, ] for i, mux_in in enumerate(default_mux_inputs): self.wire(mux_in, self.default_mux.ports.I[i]) # Generate select logic for default mux: # sel = (S < num_inputs) & EN self.wire(self.ports.S, self.lt.ports.I0) self.wire(Const(magma.bits(self.num_inputs, self.sel_bits)), self.lt.ports.I1) self.wire(self.lt.ports.O, self.and_gate.ports.I0) self.wire(self.ports.EN[0], self.and_gate.ports.I1) self.wire(self.and_gate.ports.O, self.default_mux.ports.S[0]) self.wire(self.default_mux.ports.O, self.ports.O)
def tile_to_feature(tile, tile_eq, feature, feature_idx): feature.add_ports( config=magma.In(ConfigurationType(8, 32)), config_en=magma.In(magma.Bit), ) tile.wire(tile.config.config_addr[24:], feature.config.config_addr) tile.wire(tile.config.config_data, feature.config.config_data) feature_eq = FromMagma(mantle.DefineEQ(8)) tile.wire(tile.config.config_addr[16:24], feature_eq.I0) tile.wire(Const(magma.bits(feature_idx, 8)), feature_eq.I1) feature_en = FromMagma(mantle.DefineAnd()) tile.wire(feature_eq.O, feature_en.I0) tile.wire(tile_eq.O, feature_en.I1) tile.wire(feature_en.O, feature.config_en)
def __wire_config_ce(self): if len(self.regs) == 0: return # fanout the stall signals to registers # invert the stall signal to clk_en invert = FromMagma(mantle.DefineInvert(1)) # FIXME: use the low bits of stall signal to stall self.wire(invert.ports.I[0], self.ports.stall[0]) for (reg_node, reg) in self.regs.values(): rmux: RegisterMuxNode = list(reg_node)[0] # get rmux address config_name = get_mux_sel_name(rmux) config_reg = self.registers[config_name] index_val = rmux.get_conn_in().index(reg_node) eq_gate = FromMagma(mantle.DefineEQ(config_reg.width)) self.wire(eq_gate.ports.I0, Const(index_val)) self.wire(eq_gate.ports.I1, config_reg.ports.O) and_gate = FromMagma(mantle.DefineAnd(2, 1)) self.wire(and_gate.ports.I0[0], eq_gate.ports.O) self.wire(and_gate.ports.I1, invert.ports.O) self.wire(reg.ports.CE, self.convert(and_gate.ports.O[0], magma.enable))
def wrap_lake_core(self): # Typedefs for ease if self.data_width: TData = magma.Bits[self.data_width] else: TData = magma.Bits[ 16] # This shouldn't be used if the data_width was None TBit = magma.Bits[1] # Enumerate input and output ports # (clk and reset are assumed) core_interface = get_interface(self.dut) cfgs = extract_top_config(self.dut) assert len(cfgs) > 0, "No configs?" # We basically add in the configuration bus differently # than the other ports... skip_names = [ "config_data_in", "config_write", "config_addr_in", "config_data_out", "config_read", "config_en", "clk_en" ] # Create a list of signals that will be able to be # hardwired to a constant at runtime... control_signals = [] # The rest of the signals to wire to the underlying representation... other_signals = [] # for port_name, port_size, port_width, is_ctrl, port_dir, explicit_array in core_interface: for io_info in core_interface: if io_info.port_name in skip_names: continue ind_ports = io_info.port_width intf_type = TBit # For our purposes, an explicit array means the inner data HAS to be 16 bits if io_info.expl_arr: ind_ports = io_info.port_size[0] intf_type = TData dir_type = magma.In app_list = self.__inputs if io_info.port_dir == "PortDirection.Out": dir_type = magma.Out app_list = self.__outputs if ind_ports > 1: for i in range(ind_ports): self.add_port(f"{io_info.port_name}_{i}", dir_type(intf_type)) app_list.append(self.ports[f"{io_info.port_name}_{i}"]) else: self.add_port(io_info.port_name, dir_type(intf_type)) app_list.append(self.ports[io_info.port_name]) # classify each signal for wiring to underlying representation... if io_info.is_ctrl: control_signals.append((io_info.port_name, io_info.port_width)) else: if ind_ports > 1: for i in range(ind_ports): other_signals.append( (f"{io_info.port_name}_{i}", io_info.port_dir, io_info.expl_arr, i, io_info.port_name)) else: other_signals.append( (io_info.port_name, io_info.port_dir, io_info.expl_arr, 0, io_info.port_name)) assert (len(self.__outputs) > 0) # We call clk_en stall at this level for legacy reasons???? self.add_ports(stall=magma.In(TBit), ) # put a 1-bit register and a mux to select the control signals for control_signal, width in control_signals: if width == 1: mux = MuxWrapper(2, 1, name=f"{control_signal}_sel") reg_value_name = f"{control_signal}_reg_value" reg_sel_name = f"{control_signal}_reg_sel" self.add_config(reg_value_name, 1) self.add_config(reg_sel_name, 1) self.wire(mux.ports.I[0], self.ports[control_signal]) self.wire(mux.ports.I[1], self.registers[reg_value_name].ports.O) self.wire(mux.ports.S, self.registers[reg_sel_name].ports.O) # 0 is the default wire, which takes from the routing network self.wire(mux.ports.O[0], self.underlying.ports[control_signal][0]) else: for i in range(width): mux = MuxWrapper(2, 1, name=f"{control_signal}_{i}_sel") reg_value_name = f"{control_signal}_{i}_reg_value" reg_sel_name = f"{control_signal}_{i}_reg_sel" self.add_config(reg_value_name, 1) self.add_config(reg_sel_name, 1) self.wire(mux.ports.I[0], self.ports[f"{control_signal}_{i}"]) self.wire(mux.ports.I[1], self.registers[reg_value_name].ports.O) self.wire(mux.ports.S, self.registers[reg_sel_name].ports.O) # 0 is the default wire, which takes from the routing network self.wire(mux.ports.O[0], self.underlying.ports[control_signal][i]) # Wire the other signals up... for pname, pdir, expl_arr, ind, uname in other_signals: # If we are in an explicit array moment, use the given wire name... if expl_arr is False: # And if not, use the index self.wire(self.ports[pname][0], self.underlying.ports[uname][ind]) else: self.wire(self.ports[pname], self.underlying.ports[pname]) # CLK, RESET, and STALL PER STANDARD PROCEDURE # Need to invert this self.resetInverter = FromMagma(mantle.DefineInvert(1)) self.wire(self.resetInverter.ports.I[0], self.ports.reset) self.wire( self.convert(self.resetInverter.ports.O[0], magma.asyncreset), self.underlying.ports.rst_n) self.wire(self.ports.clk, self.underlying.ports.clk) # Mem core uses clk_en (essentially active low stall) self.stallInverter = FromMagma(mantle.DefineInvert(1)) self.wire(self.stallInverter.ports.I, self.ports.stall) self.wire(self.stallInverter.ports.O[0], self.underlying.ports.clk_en[0]) # we have six? features in total # 0: TILE # 1: TILE # 1-4: SMEM # Feature 0: Tile self.__features: List[CoreFeature] = [self] # Features 1-4: SRAM self.num_sram_features = self.dut.total_sets for sram_index in range(self.num_sram_features): core_feature = CoreFeature(self, sram_index + 1) core_feature.skip_compression = True self.__features.append(core_feature) # Wire the config for idx, core_feature in enumerate(self.__features): if (idx > 0): self.add_port( f"config_{idx}", magma.In( ConfigurationType(self.config_addr_width, self.config_data_width))) # port aliasing core_feature.ports["config"] = self.ports[f"config_{idx}"] self.add_port( "config", magma.In( ConfigurationType(self.config_addr_width, self.config_data_width))) if self.num_sram_features > 0: # or the signal up t = ConfigurationType(self.config_addr_width, self.config_data_width) t_names = ["config_addr", "config_data"] or_gates = {} for t_name in t_names: port_type = t[t_name] or_gate = FromMagma( mantle.DefineOr(len(self.__features), len(port_type))) or_gate.instance_name = f"OR_{t_name}_FEATURE" for idx, core_feature in enumerate(self.__features): self.wire(or_gate.ports[f"I{idx}"], core_feature.ports.config[t_name]) or_gates[t_name] = or_gate self.wire( or_gates["config_addr"].ports.O, self.underlying.ports.config_addr_in[0:self.config_addr_width]) self.wire(or_gates["config_data"].ports.O, self.underlying.ports.config_data_in) # read data out for idx, core_feature in enumerate(self.__features): if (idx > 0): # self.add_port(f"read_config_data_{idx}", self.add_port(f"read_config_data_{idx}", magma.Out(magma.Bits[self.config_data_width])) # port aliasing core_feature.ports["read_config_data"] = \ self.ports[f"read_config_data_{idx}"] # MEM Config configurations = [] # merged_configs = [] skip_cfgs = [] for cfg_info in cfgs: if cfg_info.port_name in skip_cfgs: continue if cfg_info.expl_arr: if cfg_info.port_size[0] > 1: for i in range(cfg_info.port_size[0]): configurations.append( (f"{cfg_info.port_name}_{i}", cfg_info.port_width)) else: configurations.append( (cfg_info.port_name, cfg_info.port_width)) else: configurations.append( (cfg_info.port_name, cfg_info.port_width)) # Do all the stuff for the main config main_feature = self.__features[0] for config_reg_name, width in configurations: main_feature.add_config(config_reg_name, width) if (width == 1): self.wire(main_feature.registers[config_reg_name].ports.O[0], self.underlying.ports[config_reg_name][0]) else: self.wire(main_feature.registers[config_reg_name].ports.O, self.underlying.ports[config_reg_name]) # SRAM # These should also account for num features # or_all_cfg_rd = FromMagma(mantle.DefineOr(4, 1)) if self.num_sram_features > 0: or_all_cfg_rd = FromMagma( mantle.DefineOr(self.num_sram_features, 1)) or_all_cfg_rd.instance_name = f"OR_CONFIG_WR_SRAM" or_all_cfg_wr = FromMagma( mantle.DefineOr(self.num_sram_features, 1)) or_all_cfg_wr.instance_name = f"OR_CONFIG_RD_SRAM" for sram_index in range(self.num_sram_features): core_feature = self.__features[sram_index + 1] self.add_port(f"config_en_{sram_index}", magma.In(magma.Bit)) # port aliasing core_feature.ports["config_en"] = \ self.ports[f"config_en_{sram_index}"] # Sort of a temp hack - the name is just config_data_out if self.num_sram_features == 1: self.wire(core_feature.ports.read_config_data, self.underlying.ports["config_data_out"]) else: self.wire( core_feature.ports.read_config_data, self.underlying.ports[f"config_data_out_{sram_index}"]) and_gate_en = FromMagma(mantle.DefineAnd(2, 1)) and_gate_en.instance_name = f"AND_CONFIG_EN_SRAM_{sram_index}" # also need to wire the sram signal # the config enable is the OR of the rd+wr or_gate_en = FromMagma(mantle.DefineOr(2, 1)) or_gate_en.instance_name = f"OR_CONFIG_EN_SRAM_{sram_index}" self.wire(or_gate_en.ports.I0, core_feature.ports.config.write) self.wire(or_gate_en.ports.I1, core_feature.ports.config.read) self.wire(and_gate_en.ports.I0, or_gate_en.ports.O) self.wire(and_gate_en.ports.I1[0], core_feature.ports.config_en) self.wire(and_gate_en.ports.O[0], self.underlying.ports["config_en"][sram_index]) # Still connect to the OR of all the config rd/wr self.wire(core_feature.ports.config.write, or_all_cfg_wr.ports[f"I{sram_index}"]) self.wire(core_feature.ports.config.read, or_all_cfg_rd.ports[f"I{sram_index}"]) self.wire(or_all_cfg_rd.ports.O[0], self.underlying.ports.config_read[0]) self.wire(or_all_cfg_wr.ports.O[0], self.underlying.ports.config_write[0]) self._setup_config()
def finalize(self): if self.finalized: raise Exception("Circuit already finalized") self.finalized = True # add stall and reset signal self.__add_stall() self.__add_reset() # see if we really need to add config or not if not self.__should_add_config(): return self.add_ports(config=magma.In( ConfigurationType(self.full_config_addr_width, self.config_data_width)), clk=magma.In(magma.Clock), read_config_data=magma.Out( magma.Bits[self.config_data_width])) # double buffer ports if self.double_buffer: self.add_ports(config_db=magma.In(magma.Bit), use_db=magma.In(magma.Bit)) features = self.features() num_features = len(features) self.read_data_mux = MuxWithDefaultWrapper(num_features, self.config_data_width, self.config_addr_width, 0) self.read_data_mux.instance_name = "read_data_mux" # most of the logic copied from tile_magma.py # remove all hardcoded values for feature in self.features(): if "config" not in feature.ports: continue self.wire(self.ports.config.config_addr[self.feature_config_slice], feature.ports.config.config_addr) self.wire(self.ports.config.config_data, feature.ports.config.config_data) self.wire(self.ports.config.read, feature.ports.config.read) if self.double_buffer and "config_db" in feature.ports: self.wire(self.ports.config_db, feature.ports.config_db) self.wire(self.ports.use_db, feature.ports.use_db) # Connect S input to config_addr.feature. self.wire(self.ports.config.config_addr[self.feature_addr_slice], self.read_data_mux.ports.S) self.wire(self.read_data_mux.ports.O, self.ports.read_config_data) # Logic to generate EN input for read_data_mux read_and_tile = FromMagma(mantle.DefineAnd(2)) eq_tile = FromMagma(mantle.DefineEQ(self.tile_id_width)) # config_addr.tile_id == self.tile_id? self.wire(self.ports.tile_id, eq_tile.ports.I0) self.wire(self.ports.config.config_addr[self.tile_id_slice], eq_tile.ports.I1) # (config_addr.tile_id == self.tile_id) & READ self.wire(read_and_tile.ports.I0, eq_tile.ports.O) self.wire(read_and_tile.ports.I1, self.ports.config.read[0]) # read_data_mux.EN = (config_addr.tile_id == self.tile_id) & READ self.wire(read_and_tile.ports.O, self.read_data_mux.ports.EN[0]) # Logic for writing to config registers # Config_en_tile = (config_addr.tile_id == self.tile_id & WRITE) write_and_tile = FromMagma(mantle.DefineAnd(2)) self.wire(write_and_tile.ports.I0, eq_tile.ports.O) self.wire(write_and_tile.ports.I1, self.ports.config.write[0]) decode_feat = [] feat_and_config_en_tile = [] for i, feat in enumerate(self.features()): # wire each feature's read_data output to # read_data_mux inputs if "read_config_data" in feat.ports: self.wire(feat.ports.read_config_data, self.read_data_mux.ports.I[i]) else: # wire constant self.wire(Const(0), self.read_data_mux.ports.I[i]) # for each feature, # config_en = (config_addr.feature == feature_num) & config_en_tile decode_feat.append( FromMagma(mantle.DefineDecode(i, self.config_addr_width))) decode_feat[-1].instance_name = f"DECODE_FEATURE_{i}" feat_and_config_en_tile.append(FromMagma(mantle.DefineAnd(2))) feat_and_config_en_tile[-1].instance_name = f"FEATURE_AND_{i}" self.wire(decode_feat[i].ports.I, self.ports.config.config_addr[self.feature_addr_slice]) self.wire(decode_feat[i].ports.O, feat_and_config_en_tile[i].ports.I0) self.wire(write_and_tile.ports.O, feat_and_config_en_tile[i].ports.I1) if "config" in feat.ports: self.wire(feat_and_config_en_tile[i].ports.O, feat.ports.config.write[0]) if "config_en" in feat.ports: self.wire(decode_feat[i].ports.O, feat.ports["config_en"])
def __add_config(self): self.add_ports(config=magma.In( ConfigurationType(self.config_data_width, self.config_data_width)), tile_id=magma.In(magma.Bits(self.tile_id_width)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out( magma.Bits(self.config_data_width))) features = self.features() num_features = len(features) self.read_data_mux = MuxWithDefaultWrapper(num_features, self.config_data_width, self.config_addr_width, 0) # most of the logic copied from tile_magma.py # remove all hardcoded values for feature in self.features(): self.wire(self.ports.config.config_addr[self.feature_config_slice], feature.ports.config.config_addr) self.wire(self.ports.config.config_data, feature.ports.config.config_data) self.wire(self.ports.config.read, feature.ports.config.read) # Connect S input to config_addr.feature. self.wire(self.ports.config.config_addr[self.feature_addr_slice], self.read_data_mux.ports.S) self.wire(self.read_data_mux.ports.O, self.ports.read_config_data) # Logic to generate EN input for read_data_mux self.read_and_tile = FromMagma(mantle.DefineAnd(2)) self.eq_tile = FromMagma(mantle.DefineEQ(self.tile_id_width)) # config_addr.tile_id == self.tile_id? self.wire(self.ports.tile_id, self.eq_tile.ports.I0) self.wire(self.ports.config.config_addr[self.tile_id_slice], self.eq_tile.ports.I1) # (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.read_and_tile.ports.I1, self.ports.config.read[0]) # read_data_mux.EN = (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.O, self.read_data_mux.ports.EN[0]) # Logic for writing to config registers # Config_en_tile = (config_addr.tile_id == self.tile_id & WRITE) self.write_and_tile = FromMagma(mantle.DefineAnd(2)) self.wire(self.write_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.write_and_tile.ports.I1, self.ports.config.write[0]) self.decode_feat = [] self.feat_and_config_en_tile = [] for i, feat in enumerate(self.features()): # wire each feature's read_data output to # read_data_mux inputs self.wire(feat.ports.read_config_data, self.read_data_mux.ports.I[i]) # for each feature, # config_en = (config_addr.feature == feature_num) & config_en_tile self.decode_feat.append( FromMagma(mantle.DefineDecode(i, self.config_addr_width))) self.feat_and_config_en_tile.append(FromMagma(mantle.DefineAnd(2))) self.wire(self.decode_feat[i].ports.I, self.ports.config.config_addr[self.feature_addr_slice]) self.wire(self.decode_feat[i].ports.O, self.feat_and_config_en_tile[i].ports.I0) self.wire(self.write_and_tile.ports.O, self.feat_and_config_en_tile[i].ports.I1) self.wire(self.feat_and_config_en_tile[i].ports.O, feat.ports.config.write[0])
def __init__(self, core): super().__init__() self.core = core self.sb = SB(self.core.outputs()) widths = [get_width(i.type()) for i in self.core.inputs()] self.cbs = [CB(10, w) for w in widths] self.add_ports( north=SideType(5, (1, 16)), west=SideType(5, (1, 16)), south=SideType(5, (1, 16)), east=SideType(5, (1, 16)), config=magma.In(ConfigurationType(32, 32)), tile_id=magma.In(magma.Bits(16)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out(magma.Bits(32)), stall=magma.In(magma.Bits(4)) ) self.wire(self.ports.north, self.sb.ports.north) self.wire(self.ports.west, self.sb.ports.west) self.wire(self.ports.south, self.sb.ports.south) self.wire(self.ports.east, self.sb.ports.east) # this is hacky, but connect stall if the core has a stall input if "stall" in self.core.ports: self.wire(self.ports.stall, core.ports.stall) sides = (self.ports.north, self.ports.west) for i, cb in enumerate(self.cbs): side = sides[i % len(sides)] self.__wire_cb(side, cb) for i, input_ in enumerate(self.core.inputs()): self.wire(self.cbs[i].ports.O, input_) for i, out in enumerate(self.core.outputs()): self.wire(out, self.sb.ports[out._name]) for feature in self.features(): self.wire(self.ports.config.config_addr[24:32], feature.ports.config.config_addr) self.wire(self.ports.config.config_data, feature.ports.config.config_data) self.wire(self.ports.config.read, feature.ports.config.read) # read_data mux num_mux_inputs = len(self.features()) self.read_data_mux = MuxWithDefaultWrapper(num_mux_inputs, 32, 8, 0) # Connect S input to config_addr.feature. self.wire(self.ports.config.config_addr[16:24], self.read_data_mux.ports.S) self.wire(self.read_data_mux.ports.O, self.ports.read_config_data) # Logic to generate EN input for read_data_mux self.read_and_tile = FromMagma(mantle.DefineAnd(2)) self.eq_tile = FromMagma(mantle.DefineEQ(16)) # config_addr.tile_id == self.tile_id? self.wire(self.ports.tile_id, self.eq_tile.ports.I0) self.wire(self.ports.config.config_addr[0:16], self.eq_tile.ports.I1) # (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.read_and_tile.ports.I1, self.ports.config.read[0]) # read_data_mux.EN = (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.O, self.read_data_mux.ports.EN[0]) # Logic for writing to config registers # Config_en_tile = (config_addr.tile_id == self.tile_id & WRITE) self.write_and_tile = FromMagma(mantle.DefineAnd(2)) self.wire(self.write_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.write_and_tile.ports.I1, self.ports.config.write[0]) self.decode_feat = [] self.feat_and_config_en_tile = [] for i, feat in enumerate(self.features()): # wire each feature's read_data output to # read_data_mux inputs self.wire(feat.ports.read_config_data, self.read_data_mux.ports.I[i]) # for each feature, # config_en = (config_addr.feature == feature_num) & config_en_tile self.decode_feat.append(FromMagma(mantle.DefineDecode(i, 8))) self.feat_and_config_en_tile.append(FromMagma(mantle.DefineAnd(2))) self.wire(self.decode_feat[i].ports.I, self.ports.config.config_addr[16:24]) self.wire(self.decode_feat[i].ports.O, self.feat_and_config_en_tile[i].ports.I0) self.wire(self.write_and_tile.ports.O, self.feat_and_config_en_tile[i].ports.I1) self.wire(self.feat_and_config_en_tile[i].ports.O, feat.ports.config.write[0])