def test_dump_pnr(): num_tracks = 2 addr_width = 8 data_width = 32 bit_widths = [1, 16] tile_id_width = 16 chip_size = 2 track_length = 1 # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs cores = {} for x in range(chip_size): for y in range(chip_size): cores[(x, y)] = DummyCore() def create_core(xx: int, yy: int): return cores[(xx, yy)] in_conn = [] out_conn = [] for side in SwitchBoxSide: in_conn.append((side, SwitchBoxIO.SB_IN)) out_conn.append((side, SwitchBoxIO.SB_OUT)) pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) ics = {} for bit_width in bit_widths: ic = create_uniform_interconnect(chip_size, chip_size, bit_width, create_core, { f"data_in_{bit_width}b": in_conn, f"data_out_{bit_width}b": out_conn }, {track_length: num_tracks}, SwitchBoxType.Disjoint, pipeline_reg=pipeline_regs) ics[bit_width] = ic interconnect = Interconnect(ics, addr_width, data_width, tile_id_width, lift_ports=True) design_name = "test" with tempfile.TemporaryDirectory() as tempdir: interconnect.dump_pnr(tempdir, design_name) assert os.path.isfile(os.path.join(tempdir, f"{design_name}.info")) assert os.path.isfile(os.path.join(tempdir, "1.graph")) assert os.path.isfile(os.path.join(tempdir, "16.graph")) assert os.path.isfile(os.path.join(tempdir, f"{design_name}.layout"))
def create_dummy_cgra(chip_size, num_tracks, reg_mode, wiring, num_cfg=1): addr_width = 8 data_width = 32 bit_widths = [1, 16] tile_id_width = 16 track_length = 1 # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs cores = {} for x in range(chip_size): for y in range(chip_size): cores[(x, y)] = DummyCore() def create_core(xx: int, yy: int): return cores[(xx, yy)] in_conn = [] out_conn = [] for side in SwitchBoxSide: in_conn.append((side, SwitchBoxIO.SB_IN)) out_conn.append((side, SwitchBoxIO.SB_OUT)) pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) # if reg mode is off, reset to empty if not reg_mode: pipeline_regs = [] ics = {} for bit_width in bit_widths: ic = create_uniform_interconnect(chip_size, chip_size, bit_width, create_core, { f"data_in_{bit_width}b": in_conn, f"data_out_{bit_width}b": out_conn }, {track_length: num_tracks}, SwitchBoxType.Disjoint, pipeline_regs) ics[bit_width] = ic interconnect = Interconnect(ics, addr_width, data_width, tile_id_width, lift_ports=True) # finalize the design interconnect.finalize() # wiring if wiring == GlobalSignalWiring.Fanout: apply_global_fanout_wiring(interconnect, IOSide.None_) elif wiring == GlobalSignalWiring.Meso: apply_global_meso_wiring(interconnect, IOSide.None_) else: assert wiring == GlobalSignalWiring.ParallelMeso apply_global_parallel_meso_wiring(interconnect, IOSide.None_, num_cfg) return bit_widths, data_width, ics, interconnect
def test_1x1(double_buffer): ics = {} in_conn = [] out_conn = [] addr_width = 8 data_width = 32 for side in SwitchBoxSide: in_conn.append((side, SwitchBoxIO.SB_IN)) out_conn.append((side, SwitchBoxIO.SB_OUT)) core = DummyCore() for bit_width in {1, 16}: ic = create_uniform_interconnect(1, 1, bit_width, lambda _, __: core, {f"data_in_{bit_width}b": in_conn, f"data_out_{bit_width}b": out_conn}, {1: 2}, SwitchBoxType.Disjoint) ics[bit_width] = ic interconnect = Interconnect(ics, addr_width, data_width, 16, lift_ports=True, double_buffer=double_buffer) interconnect.finalize() apply_global_fanout_wiring(interconnect) circuit = interconnect.circuit() with tempfile.TemporaryDirectory() as tempdir: filename = os.path.join(tempdir, "test1x1") magma.compile(filename, circuit, output="coreir-verilog") # test routing for 1x1 compares = {} for seed in {0, 1}: routing_result, _ = route_one_tile(interconnect, 0, 0, ports=["data_in_16b", "data_out_16b"], seed=seed) # routing result ordering is the same as ports assert len(routing_result) == 2 bs = interconnect.get_route_bitstream(routing_result) assert len(bs) > 0 compares[seed] = bs for i in range(2): assert compares[0][i] != compares[1][i]
def create_cgra(width: int, height: int, io_sides: IOSide, add_reg: bool = True, mem_ratio: Tuple[int, int] = (1, 4), reg_addr_width: int = 8, config_data_width: int = 32, tile_id_width: int = 16, num_tracks: int = 5, add_pd: bool = True, use_sram_stub: bool = True, hi_lo_tile_id: bool = True, pass_through_clk: bool = True, global_signal_wiring: GlobalSignalWiring = GlobalSignalWiring.Meso, standalone: bool = False, switchbox_type: SwitchBoxType = SwitchBoxType.Imran, port_conn_override: Dict[str, List[Tuple[SwitchBoxSide, SwitchBoxIO]]] = None): # currently only add 16bit io cores bit_widths = [1, 16] track_length = 1 # compute the actual size width, height = get_actual_size(width, height, io_sides) # these values are inclusive x_min, x_max, y_min, y_max = get_array_size(width, height, io_sides) # compute ratio tile_max = mem_ratio[-1] mem_tile_ratio = tile_max - mem_ratio[0] # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs cores = {} for x in range(width): for y in range(height): # empty corner if x in range(x_min) and y in range(y_min): core = None elif x in range(x_min) and y in range(y_max + 1, height): core = None elif x in range(x_max + 1, width) and y in range(y_min): core = None elif x in range(x_max + 1, width) and y in range(y_max + 1, height): core = None elif x in range(x_min) \ or x in range(x_max + 1, width) \ or y in range(y_min) \ or y in range(y_max + 1, height): core = IOCore() else: core = MemCore(use_sram_stub=use_sram_stub) if \ ((x - x_min) % tile_max >= mem_tile_ratio) else \ PeakCore(PE_fc) cores[(x, y)] = core def create_core(xx: int, yy: int): return cores[(xx, yy)] # Specify input and output port connections. inputs = set() outputs = set() for core in cores.values(): # Skip IO cores. if core is None or isinstance(core, IOCore): continue inputs |= {i.qualified_name() for i in core.inputs()} outputs |= {o.qualified_name() for o in core.outputs()} # This is slightly different from the original CGRA. Here we connect # input to every SB_IN and output to every SB_OUT. port_conns = {} in_conn = [(side, SwitchBoxIO.SB_IN) for side in SwitchBoxSide] out_conn = [(side, SwitchBoxIO.SB_OUT) for side in SwitchBoxSide] port_conns.update({input_: in_conn for input_ in inputs}) port_conns.update({output: out_conn for output in outputs}) if port_conn_override is not None: port_conns.update(port_conn_override) pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) # if reg mode is off, reset to empty if not add_reg: pipeline_regs = [] ics = {} track_list = list(range(num_tracks)) io_in = {"f2io_1": [0], "f2io_16": [0]} io_out = {"io2f_1": track_list, "io2f_16": track_list} for bit_width in bit_widths: if io_sides & IOSide.None_: io_conn = None else: io_conn = {"in": io_in, "out": io_out} ic = create_uniform_interconnect(width, height, bit_width, create_core, port_conns, {track_length: num_tracks}, switchbox_type, pipeline_regs, io_sides=io_sides, io_conn=io_conn) ics[bit_width] = ic interconnect = Interconnect(ics, reg_addr_width, config_data_width, tile_id_width, lift_ports=standalone, stall_signal_width=1) if hi_lo_tile_id: tile_id_physical(interconnect) if add_pd: add_power_domain(interconnect) interconnect.finalize() if global_signal_wiring == GlobalSignalWiring.Meso: apply_global_meso_wiring(interconnect, io_sides=io_sides) elif global_signal_wiring == GlobalSignalWiring.Fanout: apply_global_fanout_wiring(interconnect, io_sides=io_sides) elif global_signal_wiring == GlobalSignalWiring.ParallelMeso: apply_global_meso_wiring(interconnect, io_sides=io_sides) if add_pd: add_aon_read_config_data(interconnect) if pass_through_clk: clk_physical(interconnect) return interconnect
def test_uniform(chip_size: int, num_track: int, track_width): # USAGE track_length = 1 def dummy_col(_: int, __: int): return DummyCore() in_conn = [(SwitchBoxSide.WEST, SwitchBoxIO.SB_IN), (SwitchBoxSide.WEST, SwitchBoxIO.SB_OUT)] out_conn = [(SwitchBoxSide.EAST, SwitchBoxIO.SB_OUT), (SwitchBoxSide.WEST, SwitchBoxIO.SB_OUT)] ic = create_uniform_interconnect(chip_size, chip_size, track_width, dummy_col, { "data_in": in_conn, "data_out": out_conn }, {track_length: num_track}, SwitchBoxType.Disjoint) # TESTS for x in range(chip_size): for y in range(chip_size): assert_tile_coordinate(ic[x, y], x, y) # since we already covered the tests on individual tiles # we will focus on the interconnect between each tiles here # we first test horizontal connections for x in range(0, chip_size - 1): for y in range(chip_size): tile_from = ic[x, y] tile_to = ic[x + track_length, y] assert tile_from in ic assert tile_to in ic for track in range(num_track): # get individual sb mux tile_from_sb = tile_from.get_sb(SwitchBoxSide.EAST, track, SwitchBoxIO.SB_OUT) tile_to_sb = tile_to.get_sb(SwitchBoxSide.WEST, track, SwitchBoxIO.SB_IN) assert tile_from_sb in ic and tile_to_sb in ic assert tile_to_sb in tile_from_sb # reverse direction tile_from_sb = tile_to.get_sb(SwitchBoxSide.WEST, track, SwitchBoxIO.SB_OUT) tile_to_sb = tile_from.get_sb(SwitchBoxSide.EAST, track, SwitchBoxIO.SB_IN) assert tile_from_sb in ic and tile_to_sb in ic assert tile_to_sb in tile_from_sb # now for the vertical connections for x in range(chip_size): for y in range(0, chip_size - 1): tile_from = ic[x, y] tile_to = ic[x, y + track_length] assert tile_from in ic assert tile_to in ic for track in range(num_track): # get individual sb mux tile_from_sb = tile_from.get_sb(SwitchBoxSide.SOUTH, track, SwitchBoxIO.SB_OUT) tile_to_sb = tile_to.get_sb(SwitchBoxSide.NORTH, track, SwitchBoxIO.SB_IN) assert tile_from_sb in ic and tile_to_sb in ic assert tile_to_sb in tile_from_sb # reverse direction tile_from_sb = tile_to.get_sb(SwitchBoxSide.NORTH, track, SwitchBoxIO.SB_OUT) tile_to_sb = tile_from.get_sb(SwitchBoxSide.SOUTH, track, SwitchBoxIO.SB_IN) assert tile_from_sb in ic and tile_to_sb in ic assert tile_to_sb in tile_from_sb
def create_cgra(chip_size: int, add_io: bool = False, cores_input=None): # currently only add 16bit io cores num_tracks = 2 reg_mode = True addr_width = 8 data_width = 32 bit_widths = [1, 16] tile_id_width = 16 track_length = 1 margin = 0 if not add_io else 1 chip_size += 2 * margin # recalculate the margin # creates all the cores here # we don't want duplicated cores when snapping into different interconnect # graphs if cores_input is None: cores_input = {} cores = {} for x in range(chip_size): for y in range(chip_size): if (x, y) in cores_input: # allow it to override cores[(x, y)] = cores_input[(x, y)] continue # empty corner if x in range(margin) and y in range(margin): core = None elif x in range(margin) and y in range(chip_size - margin, chip_size): core = None elif x in range(chip_size - margin, chip_size) and y in range(margin): core = None elif x in range(chip_size - margin, chip_size) and y in range(chip_size - margin, chip_size): core = None elif x in range(margin) \ or x in range(chip_size - margin, chip_size) \ or y in range(margin) \ or y in range(chip_size - margin, chip_size): if x == margin or y == margin: core = IO16bit() else: core = IO1bit() else: core = MemoryCore(1024) if ((x - margin) % 2 == 1) else \ PeCore() cores[(x, y)] = core def create_core(xx: int, yy: int): return cores[(xx, yy)] # specify input and output port connections inputs = ["data0", "data1", "bit0", "bit1", "bit2", "data_in", "addr_in", "flush", "ren_in", "wen_in", "data_in_16b", "wen", "ren", "addr"] outputs = ["out", "outb", "data_out", "data_out_16b"] # this is slightly different from the chip we tape out # here we connect input to every SB_IN and output to every SB_OUT port_conns = {} in_conn = [] out_conn = [] for side in SwitchBoxSide: in_conn.append((side, SwitchBoxIO.SB_IN)) out_conn.append((side, SwitchBoxIO.SB_OUT)) for input_port in inputs: port_conns[input_port] = in_conn for output_port in outputs: port_conns[output_port] = out_conn pipeline_regs = [] for track in range(num_tracks): for side in SwitchBoxSide: pipeline_regs.append((track, side)) # if reg mode is off, reset to empty if not reg_mode: pipeline_regs = [] ics = {} sides = IOSide.North | IOSide.East | IOSide.South | IOSide.West io_in = {"f2io_1": [1], "f2io_16": [0]} io_out = {"io2f_1": [1], "io2f_16": [0]} for bit_width in bit_widths: if add_io: io_conn = {"in": io_in, "out": io_out} else: io_conn = None ic = create_uniform_interconnect(chip_size, chip_size, bit_width, create_core, port_conns, {track_length: num_tracks}, SwitchBoxType.Disjoint, pipeline_regs, io_sides=sides, io_conn=io_conn) ics[bit_width] = ic interconnect = Interconnect(ics, addr_width, data_width, tile_id_width) return interconnect