Пример #1
0
 def __get_config_bits(self, lo: int, hi: int):
     assert hi > lo
     assert lo >= 0
     assert hi <= (len(self.__config) * CONFIG_DATA_WIDTH)
     start = math.floor(lo / 32)
     end = math.floor((hi - 1) / 32)
     lo_int = lo % CONFIG_DATA_WIDTH
     hi_int = hi % CONFIG_DATA_WIDTH
     if start == end:
         return self.__config[start][lo_int:hi_int]
     ret = self.__config[start][lo_int:CONFIG_DATA_WIDTH]
     for i in range(start + 1, end):
         ret = BitVector.concat(ret, self.__config[i])
     ret = BitVector.concat(ret, self.__config[i][0:hi_int])
     assert ret.num_bits == (hi - lo)
     return ret
Пример #2
0
def test_concat():
    a = BitVector(4, 4)
    b = BitVector(1, 4)
    c = BitVector.concat(a, b)
    expected = BitVector([1, 0, 0, 0, 0, 0, 1, 0])
    assert expected == c
Пример #3
0
def test_tile():
    core = DummyCore()
    tile = Tile(core)
    tile_circ = tile.circuit()
    # No functional model for tile yet, so we have to use the
    # standard fault tester for now
    tester = BasicTester(tile_circ, tile_circ.clk, tile_circ.reset)
    # assign the tile a random ID for configuration
    tile_id = random_bv(16)
    tester.poke(tile_circ.tile_id, tile_id)
    tester.reset()

    # Connect random vals to all tile inputs
    inputs_applied = {}
    for side_in in (tile_circ.north.I, tile_circ.south.I, tile_circ.east.I,
                    tile_circ.west.I):
        for i in range(len(side_in.layer1)):
            port = side_in.layer1[i]
            rand_input = random_bv(1)
            inputs_applied[port] = rand_input
            tester.poke(port, rand_input)
        for j in range(len(side_in.layer16)):
            port = side_in.layer16[j]
            rand_input = random_bv(16)
            inputs_applied[port] = rand_input
            tester.poke(port, rand_input)

    # Write to all configuration registers in the tile
    # This test should be applicapable to any tile, regardless
    # of the core it's using
    data_written = {}
    for i, feat in enumerate(tile.features()):
        feat_addr = BitVector(i, 8)
        for reg in feat.registers.values():
            reg_addr = BitVector(reg.addr, 8)
            upper_config_addr = BitVector.concat(reg_addr, feat_addr)
            config_addr = BitVector.concat(upper_config_addr, tile_id)
            # Ensure the register is wide enough to contain the random value
            rand_data = random_bv(reg.width)
            # Further restrict random config data values based on feature
            # Only 0-3 valid for SB config_data
            if (feat == tile.sb):
                if ((reg_addr % 2) == 0):
                    rand_data = rand_data % 4
                # Only 0-1 valid for SB regs
                else:
                    rand_data = rand_data % 2
            # Only 0-9 valid for CB config_data
            elif (feat in tile.cbs):
                rand_data = rand_data % 10
            # Make sure we pass 32 bits of config data to configure
            config_data = BitVector(rand_data, 32)
            tester.configure(config_addr, config_data)
            # Keep track of data written so we know what to expect to read back
            data_written[config_addr] = config_data

    # Now, read back all the configuration we just wrote
    for addr in data_written:
        tester.config_read(addr)
        expected_data = data_written[addr]
        tester.expect(tile_circ.read_config_data, expected_data)
        feat_addr = addr[16:24]
        reg_addr = addr[24:32]

    check_all_config(tester, tile_circ, tile, data_written, inputs_applied)

    # Try writing to tile with wrong tile id
    for config_addr in data_written:
        new_tile_id = config_addr[0:16] + 1
        upper_config_addr = config_addr[16:32]
        new_config_addr = BitVector.concat(upper_config_addr, new_tile_id)
        random_data = random_bv(32)
        tester.configure(new_config_addr, random_data)

    # Read all the config back again to make sure nothing changed
    check_all_config(tester, tile_circ, tile, data_written, inputs_applied)

    with tempfile.TemporaryDirectory() as tempdir:
        tester.compile_and_run(target="verilator",
                               magma_output="coreir-verilog",
                               directory=tempdir,
                               flags=["-Wno-fatal"])
Пример #4
0
def gen_cb(width: int,
           num_tracks: int,
           feedthrough_outputs: str,
           has_constant: bool,
           default_value: int):
    CONFIG_ADDR_WIDTH = 32
    CONFIG_DATA_WIDTH = 32
    # The names of the inputs to the module are given by @feedthrough_outputs.
    inputs = ["in_" + str(i)
              for i, c in enumerate(feedthrough_outputs) if c == "1"]
    # The number of total config bits needed is the number of bits needed to
    # select between all the inputs (including the constant if it is included),
    # as well as a constant value if @has_constant is True. Consequently, the
    # number of config registers needed is the total number of config bits
    # needed, divided by the size of a single config data element (e.g. 32
    # bits).
    mux_height = len(inputs)
    if has_constant:
        mux_height += 1
    mux_sel_bits = math.ceil(math.log(mux_height, 2))
    config_bits_needed = mux_sel_bits
    if has_constant:
        config_bits_needed += width
    num_config_regs = math.ceil(config_bits_needed / CONFIG_DATA_WIDTH)

    reset_val = num_tracks - feedthrough_outputs.count("0") + has_constant - 1
    reset_val = BitVector(reset_val, mux_sel_bits)
    if has_constant:
        reset_val = BitVector.concat(BitVector(default_value, width),
                                     reset_val)
    reset_val = BitVector(reset_val, CONFIG_DATA_WIDTH)

    class _CB:
        def __init__(self):
            self.__config = [BitVector(0, CONFIG_DATA_WIDTH)
                             for _ in range(num_config_regs)]
            self.reset()

        def reset(self):
            self.configure(BitVector(0, CONFIG_ADDR_WIDTH), reset_val)

            self.out = fault.UnknownValue
            self.read_data = fault.UnknownValue

        def configure(self, addr: BitVector, data: BitVector):
            assert addr.num_bits == CONFIG_ADDR_WIDTH
            assert data.num_bits == CONFIG_ADDR_WIDTH
            addr_high_bits = addr[24:32]
            config_reg_select = addr_high_bits.as_uint()
            if config_reg_select in range(num_config_regs):
                self.__config[config_reg_select] = data

        # Function to slice the global config bit space. Returns bits in the
        # range [lo, hi).
        def __get_config_bits(self, lo: int, hi: int):
            assert hi > lo
            assert lo >= 0
            assert hi <= (len(self.__config) * CONFIG_DATA_WIDTH)
            start = math.floor(lo / 32)
            end = math.floor((hi - 1) / 32)
            lo_int = lo % CONFIG_DATA_WIDTH
            hi_int = hi % CONFIG_DATA_WIDTH
            if start == end:
                return self.__config[start][lo_int:hi_int]
            ret = self.__config[start][lo_int:CONFIG_DATA_WIDTH]
            for i in range(start + 1, end):
                ret = BitVector.concat(ret, self.__config[i])
            ret = BitVector.concat(ret, self.__config[i][0:hi_int])
            assert ret.num_bits == (hi - lo)
            return ret

        def __call__(self, *args):
            assert len(args) == len(inputs)
            select = self.__get_config_bits(0, mux_sel_bits)
            select_as_uint = select.as_uint()
            # TODO: read_data logic
            if select_as_uint in range(len(inputs)):
                self.out = args[select_as_uint]
                return self.out
            if has_constant:
                return self.__get_config_bits(mux_sel_bits,
                                              mux_sel_bits + width)
            else:
                return BitVector(0, width)

        # Debug method to read config data.
        @property
        def config(self):
            return self.__config

    return _CB