Example #1
0
    def __init__(self, data_width, data_depth):
        super().__init__()

        self.data_width = data_width
        self.data_depth = data_depth
        TData = magma.Bits(self.data_width)
        TBit = magma.Bits(1)

        self.add_ports(data_in=magma.In(TData),
                       addr_in=magma.In(TData),
                       data_out=magma.Out(TData),
                       clk=magma.In(magma.Clock),
                       config=magma.In(ConfigurationType(8, 32)),
                       read_config_data=magma.Out(magma.Bits(32)),
                       reset=magma.In(magma.AsyncReset),
                       flush=magma.In(TBit),
                       wen_in=magma.In(TBit),
                       ren_in=magma.In(TBit),
                       stall=magma.In(magma.Bits(4)))

        wrapper = memory_core_genesis2.memory_core_wrapper
        param_mapping = memory_core_genesis2.param_mapping
        generator = wrapper.generator(param_mapping, mode="declare")
        circ = generator(data_width=self.data_width,
                         data_depth=self.data_depth)
        self.underlying = FromMagma(circ)

        self.wire(self.ports.data_in, self.underlying.ports.data_in)
        self.wire(self.ports.addr_in, self.underlying.ports.addr_in)
        self.wire(self.ports.data_out, self.underlying.ports.data_out)
        self.wire(self.ports.config.config_addr,
                  self.underlying.ports.config_addr[24:32])
        self.wire(self.ports.config.config_data,
                  self.underlying.ports.config_data)
        self.wire(self.ports.config.write[0], self.underlying.ports.config_en)
        self.wire(self.underlying.ports.read_data, self.ports.read_config_data)
        self.wire(self.ports.reset, self.underlying.ports.reset)
        self.wire(self.ports.flush[0], self.underlying.ports.flush)
        self.wire(self.ports.wen_in[0], self.underlying.ports.wen_in)
        self.wire(self.ports.ren_in[0], self.underlying.ports.ren_in)

        # PE core uses clk_en (essentially active low stall)
        self.stallInverter = FromMagma(mantle.DefineInvert(1))
        self.wire(self.stallInverter.ports.I, self.ports.stall[0:1])
        self.wire(self.stallInverter.ports.O[0], self.underlying.ports.clk_en)

        # TODO(rsetaluri): Actually wire these inputs.
        signals = (
            ("config_en_sram", 4),
            ("config_en_linebuf", 1),
            ("chain_wen_in", 1),
            ("config_read", 1),
            ("config_write", 1),
            ("chain_in", self.data_width),
        )
        for name, width in signals:
            val = magma.bits(0, width) if width > 1 else magma.bit(0)
            self.wire(Const(val), self.underlying.ports[name])
        self.wire(Const(magma.bits(0, 24)),
                  self.underlying.ports.config_addr[0:24])
Example #2
0
    def __init__(self, node: PortNode, config_addr_width: int,
                 config_data_width: int):
        if not isinstance(node, PortNode):
            raise ValueError(node, PortNode.__name__)
        super().__init__(config_addr_width, config_data_width)

        self.node: PortNode = node
        self.mux = create_mux(self.node)

        # lift the port to the top level
        self.add_ports(I=self.mux.ports.I.base_type(),
                       O=self.mux.ports.O.base_type())

        self.wire(self.ports.I, self.mux.ports.I)
        self.wire(self.ports.O, self.mux.ports.O)

        if self.mux.height > 1:
            self.add_ports(
                config=magma.In(
                    ConfigurationType(config_addr_width, config_data_width)),
                read_config_data=magma.Out(magma.Bits(config_data_width)),
            )
            config_name = get_mux_sel_name(self.node)
            self.add_config(config_name, self.mux.sel_bits)
            self.wire(self.registers[config_name].ports.O, self.mux.ports.S)

        self._setup_config()
Example #3
0
    def __fan_out_config(self):
        self.add_ports(config=magma.In(
            ConfigurationType(self.data_width, self.data_width)),
                       clk=magma.In(magma.Clock),
                       reset=magma.In(magma.AsyncReset))

        # fan out wires
        for _, tile_circuit in self.tile_circuits.items():
            self.wire(self.ports.config, tile_circuit.ports.config)
            self.wire(self.ports.reset, tile_circuit.ports.reset)
Example #4
0
    def __init__(self, num_tracks, width):
        super().__init__()

        if num_tracks <= 1:
            raise ValueError("num_tracks must be > 1")
        self.num_tracks = num_tracks
        self.width = width
        sel_bits = magma.bitutils.clog2(self.num_tracks)

        self.mux = MuxWrapper(self.num_tracks, self.width)

        T = magma.Bits(self.width)

        self.add_ports(
            I=magma.In(magma.Array(self.num_tracks, T)),
            O=magma.Out(T),
            clk=magma.In(magma.Clock),
            reset=magma.In(magma.AsyncReset),
            config=magma.In(ConfigurationType(8, 32)),
            read_config_data=magma.Out(magma.Bits(32)),
        )
        self.add_configs(S=sel_bits)
        # read_config_data output
        num_config_reg = len(self.registers)
        if (num_config_reg > 1):
            self.read_config_data_mux = MuxWrapper(num_config_reg, 32)
            self.wire(self.ports.config.config_addr,
                      self.read_config_data_mux.ports.S)
            self.wire(self.read_config_data_mux.ports.O,
                      self.ports.read_config_data)
            for idx, reg in enumerate(self.registers.values()):
                self.wire(reg.ports.O, self.read_config_data_mux.ports.I[idx])
                # Wire up config register resets
                self.wire(reg.ports.reset, self.ports.reset)
        # If we only have 1 config register, we don't need a mux
        # Wire sole config register directly to read_config_data_output
        else:
            reg = list(self.registers.values())[0]
            zext = ZextWrapper(reg.width, 32)
            self.wire(reg.ports.O, zext.ports.I)
            zext_out = zext.ports.O
            self.wire(zext_out, self.ports.read_config_data)

        self.wire(self.ports.I, self.mux.ports.I)
        self.wire(self.registers.S.ports.O, self.mux.ports.S)
        self.wire(self.mux.ports.O, self.ports.O)

        for idx, reg in enumerate(self.registers.values()):
            reg.set_addr(idx)
            reg.set_addr_width(8)
            reg.set_data_width(32)
            self.wire(self.ports.config.config_addr, reg.ports.config_addr)
            self.wire(self.ports.config.config_data, reg.ports.config_data)
            # Connect config_en for each config reg
            self.wire(reg.ports.config_en, self.ports.config.write[0])
Example #5
0
    def __init__(self):
        super().__init__()

        # TODO(rsetaluri): Currently we assume the default parameters into the
        # wrapper. Ideally we should take some arguments into this generator
        # and pass them to the genesis wrapper.
        wrapper = pe_core_genesis2.pe_core_wrapper
        generator = wrapper.generator(mode="declare")
        circ = generator()
        self.underlying = FromMagma(circ)

        TData = magma.Bits(16)
        TBit = magma.Bits(1)
        TFlag = magma.Bits(4)

        self.add_ports(
            data0=magma.In(TData),
            data1=magma.In(TData),
            bit0=magma.In(TBit),
            bit1=magma.In(TBit),
            bit2=magma.In(TBit),
            res=magma.Out(TData),
            res_p=magma.Out(TFlag),
            clk=magma.In(magma.Clock),
            reset=magma.In(magma.AsyncReset),
            config=magma.In(ConfigurationType(8, 32)),
            read_config_data=magma.Out(magma.Bits(32)),
            # TODO: Make number of stall domains paramaterizable
            stall=magma.In(magma.Bits(4))
        )

        self.wire(self.ports.data0, self.underlying.ports.data0)
        self.wire(self.ports.data1, self.underlying.ports.data1)
        self.wire(self.ports.bit0[0], self.underlying.ports.bit0)
        self.wire(self.ports.bit1[0], self.underlying.ports.bit1)
        self.wire(self.ports.bit2[0], self.underlying.ports.bit2)
        self.wire(self.ports.res, self.underlying.ports.res)
        self.wire(self.ports.res_p, self.underlying.ports.res_p)
        self.wire(self.ports.config.config_addr, self.underlying.ports.cfg_a)
        self.wire(self.ports.config.config_data,
                  self.underlying.ports.cfg_d)
        self.wire(self.ports.config.write[0], self.underlying.ports.cfg_en)
        self.wire(self.underlying.ports.read_data, self.ports.read_config_data)

        # TODO: Make PE core use active high reset
        self.wire(self.ports.reset, self.underlying.ports.rst_n)

        # PE core uses clk_en (essentially active low stall)
        self.stallInverter = FromMagma(mantle.DefineInvert(1))
        self.wire(self.stallInverter.ports.I, self.ports.stall[0:1])
        self.wire(self.stallInverter.ports.O[0], self.underlying.ports.clk_en)
Example #6
0
    def __init__(self, columns):
        super().__init__()

        assert all([c.height == columns[0].height for c in columns])
        self.width = len(columns)
        self.height = columns[0].height
        self.columns = columns
        self.side_type = SideType(5, (1, 16))

        self.add_ports(
            north=magma.Array(self.width, self.side_type),
            south=magma.Array(self.width, self.side_type),
            west=magma.Array(self.height, self.side_type),
            east=magma.Array(self.height, self.side_type),
            config=magma.In(ConfigurationType(32, 32)),
            clk=magma.In(magma.Clock),
            reset=magma.In(magma.AsyncReset),
            read_config_data=magma.Out(magma.Bits(32)),
            # TODO: make number of stall domains a param
            stall=magma.In(magma.Bits(4)))

        for column in self.columns:
            self.wire(self.ports.config, column.ports.config)
            self.wire(self.ports.reset, column.ports.reset)
            self.wire(self.ports.stall, column.ports.stall)
        self.wire(self.ports.west, self.columns[0].ports.west)
        self.wire(self.ports.east, self.columns[-1].ports.east)
        for i, column in enumerate(self.columns):
            self.wire(self.ports.north[i], column.ports.north)
            self.wire(self.ports.south[i], column.ports.south)
        for i in range(1, self.width):
            c0 = self.columns[i - 1]
            c1 = self.columns[i]
            for j in range(self.height):
                self.wire(c1.ports.west[j].O, c0.ports.east[j].I)
                self.wire(c0.ports.east[j].O, c1.ports.west[j].I)

        # OR together read_data outputs from each column
        # number of inputs = number of columns
        self.read_data_OR = FromMagma(mantle.DefineOr(len(self.columns), 32))
        for i, col in enumerate(columns):
            self.wire(self.read_data_OR.ports[f"I{i}"],
                      col.ports.read_config_data)
            # wire up column number input
            self.wire(col.ports.column_num, Const(magma.bits(i, 8)))
        self.wire(self.read_data_OR.ports.O, self.ports.read_config_data)
    def __init__(self, addr_width, data_width):
        super().__init__()
        super().__init__()

        self.addr_width = addr_width
        self.data_width = data_width
        self.config_type = ConfigurationType(self.addr_width, self.data_width)

        self.add_ports(
            jtag=JTAGType,
            config=magma.Out(self.config_type),
            read_data_in=magma.In(magma.Bits(self.data_width)),
            clk_in=magma.In(magma.Clock),
            reset_in=magma.In(magma.AsyncReset),
            clk_out=magma.Out(magma.Clock),
            reset_out=magma.Out(magma.AsyncReset),
            # TODO: make number of stall domains a param
            stall=magma.Out(magma.Bits(4))
        )

        wrapper = global_controller_genesis2.gc_wrapper
        generator = wrapper.generator(mode="declare")
        self.underlying = FromMagma(generator())

        self.wire(self.ports.jtag.tdi, self.underlying.ports.tdi)
        self.wire(self.ports.jtag.tdo, self.underlying.ports.tdo)
        self.wire(self.ports.jtag.tms, self.underlying.ports.tms)
        self.wire(self.ports.jtag.tck, self.underlying.ports.tck)
        self.wire(self.ports.jtag.trst_n, self.underlying.ports.trst_n)
        self.wire(self.ports.clk_in, self.underlying.ports.clk_in)
        self.wire(self.ports.reset_in, self.underlying.ports.reset_in)

        self.wire(self.underlying.ports.config_addr_out,
                  self.ports.config.config_addr)
        self.wire(self.underlying.ports.config_data_out,
                  self.ports.config.config_data)
        self.wire(self.underlying.ports.read, self.ports.config.read[0])
        self.wire(self.underlying.ports.write, self.ports.config.write[0])
        self.wire(self.underlying.ports.clk_out, self.ports.clk_out)
        self.wire(self.underlying.ports.reset_out, self.ports.reset_out)
        self.wire(self.underlying.ports.cgra_stalled, self.ports.stall)

        self.wire(self.ports.read_data_in, self.underlying.ports.config_data_in)
Example #8
0
    def __init__(self, switchbox: SwitchBox, config_addr_width: int,
                 config_data_width: int):
        super().__init__(config_addr_width, config_data_width)
        self.switchbox = switchbox

        # lift the ports up
        sbs = self.switchbox.get_all_sbs()
        self.sb_muxs: Dict[str, Tuple[SwitchBoxNode, MuxWrapper]] = {}
        # first pass to create the mux circuit
        for sb in sbs:
            sb_name = str(sb)
            self.sb_muxs[sb_name] = (sb, create_mux(sb))
        # second pass to lift the ports and wire them

        for sb_name, (sb, mux) in self.sb_muxs.items():
            # only lift them if the ports are connect to the outside world
            port_name = create_name(sb_name)
            if sb.io == SwitchBoxIO.SB_IN:
                self.add_port(port_name, magma.In(mux.ports.I.base_type()))
                self.wire(self.ports[port_name], mux.ports.I)

            else:
                self.add_port(port_name, magma.Out(mux.ports.O.base_type()))
                self.wire(self.ports[port_name], mux.ports.O)

        # connect internal sbs
        self.__connect_sbs()

        # set up the configuration registers
        self.add_ports(
            config=magma.In(
                ConfigurationType(config_addr_width, config_data_width)),
            read_config_data=magma.Out(magma.Bits(config_data_width)),
        )
        for _, (sb, mux) in self.sb_muxs.items():
            config_name = get_mux_sel_name(sb)
            if mux.height > 1:
                assert mux.sel_bits > 0
                self.add_config(config_name, mux.sel_bits)
                self.wire(self.registers[config_name].ports.O, mux.ports.S)

        self._setup_config()
Example #9
0
    def __init__(self, tiles):
        super().__init__()

        self.tiles = tiles
        self.height = len(tiles)

        self.add_ports(
            north=SideType(5, (1, 16)),
            south=SideType(5, (1, 16)),
            west=magma.Array(self.height, SideType(5, (1, 16))),
            east=magma.Array(self.height, SideType(5, (1, 16))),
            config=magma.In(ConfigurationType(32, 32)),
            clk=magma.In(magma.Clock),
            reset=magma.In(magma.AsyncReset),
            read_config_data=magma.Out(magma.Bits(32)),
            column_num=magma.In(magma.Bits(8)),
            # TODO (alexcarsello): make number of stall domains a param
            stall=magma.In(magma.Bits(4)))

        self.wire(self.ports.north, self.tiles[0].ports.north)
        self.wire(self.ports.south, self.tiles[-1].ports.south)
        for i, tile in enumerate(self.tiles):
            self.wire(self.ports.west[i], tile.ports.west)
            self.wire(self.ports.east[i], tile.ports.east)
            # Wire upper 8 bits of tile ID to row number
            self.wire(tile.ports.tile_id[8:16], Const(magma.bits(i, 8)))
            # Wire lower 8 bits of tile ID to col number
            self.wire(tile.ports.tile_id[0:8], self.ports.column_num)
        for i in range(1, self.height):
            t0 = self.tiles[i - 1]
            t1 = self.tiles[i]
            self.wire(t1.ports.north.O, t0.ports.south.I)
            self.wire(t0.ports.south.O, t1.ports.north.I)

        # Call abstract functions
        # distribute global inputs to all tiles in column
        self.wire_global_signals()
        # OR-combine each tile's read_data to form column read_data
        self.combine_read_data_outputs()
Example #10
0
    def __init__(self):
        super().__init__()
        self.add_ports(data_in_16b=magma.In(magma.Bits(16)),
                       data_out_16b=magma.Out(magma.Bits(16)),
                       data_in_1b=magma.In(magma.Bits(1)),
                       data_out_1b=magma.Out(magma.Bits(1)),
                       clk=magma.In(magma.Clock),
                       reset=magma.In(magma.AsyncReset),
                       config=magma.In(ConfigurationType(8, 32)),
                       read_config_data=magma.Out(magma.Bits(32)))

        # Dummy core just passes inputs through to outputs
        self.wire(self.ports.data_in_16b, self.ports.data_out_16b)
        self.wire(self.ports.data_in_1b, self.ports.data_out_1b)

        # Add some config registers
        self.add_configs(dummy_1=32, dummy_2=32)

        # Create mux allow for reading of config regs
        num_mux_inputs = len(self.registers.values())
        self.read_data_mux = MuxWithDefaultWrapper(num_mux_inputs, 32, 8, 0)
        # Connect config_addr to mux select
        self.wire(self.read_data_mux.ports.S, self.ports.config.config_addr)
        # Connect config_read to mux enable
        self.wire(self.read_data_mux.ports.EN[0], self.ports.config.read[0])
        self.wire(self.read_data_mux.ports.O, self.ports.read_config_data)
        for i, reg in enumerate(self.registers.values()):
            reg.set_addr(i)
            reg.set_addr_width(8)
            reg.set_data_width(32)
            # wire output to read_data_mux inputs
            self.wire(reg.ports.O, self.read_data_mux.ports.I[i])
            # Wire config addr and data to each register
            self.wire(self.ports.config.config_addr, reg.ports.config_addr)
            self.wire(self.ports.config.config_data, reg.ports.config_data)
            # Wire config write to each reg's write port
            self.wire(self.ports.config.write[0], reg.ports.config_en)
            self.wire(self.ports.reset, reg.ports.reset)
Example #11
0
    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])
Example #12
0
    def __init__(self, inputs):
        super().__init__()

        self.all_inputs = inputs
        self.inputs = self.__organize_inputs(inputs)

        self.add_ports(
            north=SideType(5, (1, 16)),
            west=SideType(5, (1, 16)),
            south=SideType(5, (1, 16)),
            east=SideType(5, (1, 16)),
            clk=magma.In(magma.Clock),
            reset=magma.In(magma.AsyncReset),
            config=magma.In(ConfigurationType(8, 32)),
            read_config_data=magma.Out(magma.Bits(32)),
        )

        # TODO(rsetaluri): Clean up this logic.
        for i, input_ in enumerate(self.all_inputs):
            assert input_.type().isoutput()
            port_name = f"{input_._name}"
            self.add_port(port_name, magma.In(input_.type()))

        sides = (self.ports.north, self.ports.west,
                 self.ports.south, self.ports.east)
        self.muxs = self.__make_muxs(sides)
        for (side, layer, track), mux in self.muxs.items():
            idx = 0
            for side_in in sides:
                if side_in == side:
                    continue
                mux_in = getattr(side_in.I, f"layer{layer}")[track]
                self.wire(mux_in, mux.ports.I[idx])
                idx += 1
            for input_ in self.inputs[layer]:
                port_name = input_._name
                self.wire(self.ports[port_name], mux.ports.I[idx])
                idx += 1
            buffered_mux = self.__make_register_buffer(mux)
            mux_out = getattr(side.O, f"layer{layer}")[track]
            self.wire(buffered_mux.ports.O, mux_out)

            # Add corresponding config register.
            config_name = f"mux_{side._name}_{layer}_{track}"
            config_name_mux = config_name + '_sel'
            config_name_buffer = config_name + '_buffer_sel'
            self.add_config(config_name_mux, mux.sel_bits)
            self.wire(self.registers[config_name_mux].ports.O, mux.ports.S)
            self.add_config(config_name_buffer, buffered_mux.sel_bits)
            self.wire(self.registers[config_name_buffer].ports.O,
                      buffered_mux.ports.S)

        # NOTE(rsetaluri): We set the config register addresses explicitly and
        # in a well-defined order. This ordering can be considered a part of
        # the functional spec of this module.
        idx = 0
        for side in sides:
            for layer in (1, 16):
                for track in range(5):
                    reg_name = f"mux_{side._name}_{layer}_{track}"
                    reg_name_mux = reg_name + '_sel'
                    reg_name_buffer = reg_name + '_buffer_sel'
                    self.registers[reg_name_mux].set_addr(idx)
                    idx += 1
                    self.registers[reg_name_buffer].set_addr(idx)
                    idx += 1

        for idx, reg in enumerate(self.registers.values()):
            reg.set_addr_width(8)
            reg.set_data_width(32)
            self.wire(self.ports.config.config_addr, reg.ports.config_addr)
            self.wire(self.ports.config.config_data, reg.ports.config_data)
            self.wire(self.ports.config.write[0], reg.ports.config_en)
            self.wire(self.ports.reset, reg.ports.reset)

        # read_config_data output
        num_config_reg = len(self.registers)
        if(num_config_reg > 1):
            self.read_config_data_mux = MuxWrapper(num_config_reg, 32)
            sel_bits = self.read_config_data_mux.sel_bits
            # Wire up config_addr to select input of read_data MUX
            # TODO(rsetaluri): Make this a mux with default.
            self.wire(self.ports.config.config_addr[:sel_bits],
                      self.read_config_data_mux.ports.S)
            self.wire(self.read_config_data_mux.ports.O,
                      self.ports.read_config_data)
            for idx, reg in enumerate(self.registers.values()):
                zext = ZextWrapper(reg.width, 32)
                self.wire(reg.ports.O, zext.ports.I)
                zext_out = zext.ports.O
                self.wire(zext_out, self.read_config_data_mux.ports.I[idx])
        # If we only have 1 config register, we don't need a mux
        # Wire sole config register directly to read_config_data_output
        else:
            self.wire(self.registers[0].ports.O, self.ports.read_config_data)
Example #13
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])