def pipeline_config_signals(interconnect: Interconnect, interval): # Right now in canal, the width of config_addr and config_data # are hard-coded to be the same. This should be changed. config_data_width = interconnect.config_data_width config_addr_width = config_data_width for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if tile_core is None or "config" not in tile_core.ports or y == 0: continue else: if interval != 0 and y % interval == 0 and ( (x, y + 1) in interconnect.tile_circuits): tile_below = interconnect.tile_circuits[(x, y + 1)] pipe_stage = PipelineStage(config_addr_width, config_data_width) # remove existing config wire interconnect.remove_wire(tile.ports.config_out, tile_below.ports.config) # Now, wire config through the pipe stage interconnect.wire(tile.ports.config_out, pipe_stage.ports.config) interconnect.wire(pipe_stage.ports.config_out, tile_below.ports.config) # Wire up pipe stage clock input to output clock interconnect.wire(tile.ports.clk_out, pipe_stage.ports.clk)
def clk_physical(interconnect: Interconnect): for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core # We only want to do this on PE and memory tiles if tile_core is None or isinstance(tile_core, IOCoreBase): continue elif isinstance(tile_core, MemCore): if (x, y + 1) in interconnect.tile_circuits: tile_below = interconnect.tile_circuits[(x, y + 1)] if isinstance(tile_below.core, MemCore): interconnect.remove_wire(tile.ports.clk_out, tile_below.ports.clk) # Get the PE tile to the left of this mem tile tile_left = interconnect.tile_circuits[(x - 1, y)] # Connect the clk input of this mem tile to the right clk # output of the neighboring PE tile interconnect.wire(tile_left.ports.clk_pass_through_out_right, tile.ports.clk) else: orig_in_port = tile.ports.clk orig_out_port = tile.ports.clk_out # Remove the pass through connection that already exists tile.remove_wire(orig_in_port, orig_out_port) # Create a new pass through clock input tile.add_port("clk_pass_through", magma.In(magma.Bit)) pass_through_input = tile.ports.clk_pass_through pass_through_input_as_clk = tile.convert(pass_through_input, magma.clock) # Create 2 new clk pass through outputs (bottom and right) tile.add_port("clk_pass_through_out_bot", magma.Out(magma.Bit)) tile.add_port("clk_pass_through_out_right", magma.Out(magma.Clock)) tile.wire(tile.ports.clk_pass_through, tile.ports.clk_pass_through_out_bot) tile.wire(pass_through_input_as_clk, tile.ports.clk_pass_through_out_right) # Connect new clk pass through input to old pass through output tile.wire(pass_through_input_as_clk, orig_out_port) # For top row tiles, connect new clk input to global clock if y < 2: interconnect_clk_as_bit = interconnect.convert( interconnect.ports.clk, magma.bit) interconnect.wire(interconnect_clk_as_bit, pass_through_input) # For other tiles, connect new clk input to # pass through output of tile above. else: tile_above = interconnect.tile_circuits[(x, y - 1)] interconnect.wire(tile_above.ports.clk_pass_through_out_bot, pass_through_input)
def tile_id_physical(interconnect: Interconnect): tile_id_width = interconnect.tile_id_width tie_hi_width = (tile_id_width // 2) + 1 if (tile_id_width % 2) == 0: tie_lo_width = tile_id_width // 2 else: tie_lo_width = (tile_id_width // 2) + 1 for (x, y) in interconnect.tile_circuits: tile = interconnect.tile_circuits[(x, y)] tile_core = tile.core if isinstance(tile_core, IOCoreValid) or tile_core is None: continue tile.add_ports(hi=magma.Out(magma.Bits[tie_hi_width]), lo=magma.Out(magma.Bits[tie_lo_width])) # wire all hi bits high tile.wire(tile.ports.hi, Const((2**tie_hi_width) - 1)) # wire all lo bits low tile.wire(tile.ports.lo, Const(0)) # Get the correct tile_id value x_bv = BitVector[tile_id_width / 2](x) y_bv = BitVector[tile_id_width / 2](y) tile_id_bv = BitVector.concat(y_bv, x_bv) # Disconnect existing constant from tile_id port tile_id_port = tile.ports.tile_id for wire in interconnect.wires: if tile_id_port in wire: interconnect.remove_wire(wire[0], wire[1]) break # Actually connect hi/lo outputs to tile_id at top level for i in range(tile_id_width): lo_index = i // 2 if (i % 2) == 0: hi_index = i // 2 else: hi_index = (i // 2) + 1 hi_port = tile.ports.hi[hi_index] lo_port = tile.ports.lo[lo_index] tie_port = hi_port if (tile_id_bv[i] == 1) else lo_port # Connect tile_id ports to hi/lo outputs instead of constant interconnect.wire(tile.ports.tile_id[i], tie_port)