コード例 #1
0
ファイル: test_mux_wrapper.py プロジェクト: mfkiwl/ee272_cgra
def test_mux_wrapper(height, width):
    """
    Test that the mux wrapper circuit works as expected. Specifically, we
    initialize a mux with random height and width, and check that the output is
    as expected for select in range [0, height).

    Note that we do not check the behavior with sel >= height, because this is
    undefined behavior.
    """
    mux = MuxWrapper(height, width)
    assert mux.height == height
    assert mux.width == width
    assert mux.name() == f"MuxWrapper_{height}_{width}"

    mux_circuit = mux.circuit()
    tester = fault.Tester(mux_circuit)
    inputs = [fault.random.random_bv(width) for _ in range(height)]
    for i, input_ in enumerate(inputs):
        tester.poke(mux_circuit.I[i], input_)
    for i in range(height):
        tester.poke(mux_circuit.S, BitVector(i, mux.sel_bits))
        tester.eval()
        tester.expect(mux_circuit.O, inputs[i])
    with tempfile.TemporaryDirectory() as tempdir:
        tester.compile_and_run(directory=tempdir,
                               magma_output="coreir-verilog",
                               flags=["-Wno-fatal"])
コード例 #2
0
ファイル: simple_cb_magma.py プロジェクト: mfkiwl/ee272_cgra
    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])
コード例 #3
0
    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)

        # 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)
コード例 #4
0
ファイル: simple_sb_magma.py プロジェクト: mfkiwl/ee272_cgra
 def __make_muxs(self, sides):
     height_per_layer = {
         1: 3 + len(self.inputs[1]),
         16: 3 + len(self.inputs[16]),
     }
     muxs = {}
     for side in sides:
         for layer, height in height_per_layer.items():
             for track in range(5):
                 muxs[(side, layer, track)] = MuxWrapper(height, layer)
     return muxs
コード例 #5
0
ファイル: simple_sb_magma.py プロジェクト: mfkiwl/ee272_cgra
    def __make_register_buffer(self, unbuffered_mux):
        signal_in = unbuffered_mux.ports.O
        width = get_width(signal_in.type())

        # register = Register(width)
        RegisterCls = DefineRegister(width)
        register = FromMagma(RegisterCls)

        mux = MuxWrapper(2, width)
        self.wire(signal_in, mux.ports.I[0])
        self.wire(signal_in, register.ports.I)
        self.wire(register.ports.O, mux.ports.I[1])
        return mux
コード例 #6
0
ファイル: circuit.py プロジェクト: mfkiwl/ee272_cgra
    def _setup_config(self):
        # sort the registers by it's name. this will be the order of config
        # addr index
        config_names = list(self.registers.keys())
        config_names.sort()
        for idx, config_name in enumerate(config_names):
            reg = self.registers[config_name]
            # set the configuration registers
            reg.set_addr(idx)
            reg.set_addr_width(self.config_addr_width)
            reg.set_data_width(self.config_data_width)

            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(config_names)
        if num_config_reg > 1:
            self.read_config_data_mux = MuxWrapper(num_config_reg,
                                                   self.config_data_width)
            sel_bits = self.read_config_data_mux.sel_bits
            # Wire up config_addr to select input of read_data MUX
            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, config_name in enumerate(config_names):
                reg = self.registers[config_name]
                zext = ZextWrapper(reg.width, self.config_data_width)
                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])
        else:
            config_name = config_names[0]
            reg = self.registers[config_name]
            zext = ZextWrapper(reg.width, self.config_data_width)
            self.wire(reg.ports.O, zext.ports.I)
            zext_out = zext.ports.O
            self.wire(zext_out, self.ports.read_config_data)
コード例 #7
0
ファイル: circuit.py プロジェクト: mfkiwl/ee272_cgra
def create_mux(node: Node):
    conn_in = node.get_conn_in()
    height = len(conn_in)
    mux = MuxWrapper(height, node.width)
    return mux
コード例 #8
0
ファイル: simple_sb_magma.py プロジェクト: mfkiwl/ee272_cgra
    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)