def __init__(self, config_addr_width: int, config_data_width: int): super().__init__() self.config_addr_width = config_addr_width self.config_data_width = config_data_width config_type = ConfigurationType(config_addr_width, config_data_width) self.add_ports(clk=magma.In(magma.Clock), config=magma.In(config_type), config_out=magma.Out(config_type)) # Pipeline registers config_addr_reg = FromMagma(DefineRegister(config_addr_width)) config_data_reg = FromMagma(DefineRegister(config_data_width)) config_read_reg = FromMagma(DefineRegister(1)) config_write_reg = FromMagma(DefineRegister(1)) # Wire pipeline reg inputs self.wire(self.ports.config.config_addr, config_addr_reg.ports.I) self.wire(self.ports.config.config_data, config_data_reg.ports.I) self.wire(self.ports.config.read, config_read_reg.ports.I) self.wire(self.ports.config.write, config_write_reg.ports.I) # Wire pipeline reg outputs self.wire(config_addr_reg.ports.O, self.ports.config_out.config_addr) self.wire(config_data_reg.ports.O, self.ports.config_out.config_data) self.wire(config_read_reg.ports.O, self.ports.config_out.read) self.wire(config_write_reg.ports.O, self.ports.config_out.write)
def __init__(self, config_addr_width: int, config_data_width: int): super().__init__(config_addr_width, config_data_width) self.config = PDCGRAConfig() # ps self.add_config(self.config.ps_config_name, config_data_width) self.add_ports(config=magma.In( ConfigurationType(config_addr_width, config_data_width)), ) self._setup_config()
def _lift_interconnect_ports(self, config_data_width): for name in self.interconnect.interface(): self.add_port(name, self.interconnect.ports[name].type()) self.wire(self.ports[name], self.interconnect.ports[name]) self.add_ports( clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), config=magma.In( ConfigurationType(self.interconnect.config_data_width, self.interconnect.config_data_width)), stall=magma.In(magma.Bits[self.interconnect.stall_signal_width]), read_config_data=magma.Out(magma.Bits[config_data_width])) self.wire(self.ports.clk, self.interconnect.ports.clk) self.wire(self.ports.reset, self.interconnect.ports.reset) self.wire(self.ports.config, self.interconnect.ports.config) self.wire(self.ports.stall, self.interconnect.ports.stall) self.wire(self.interconnect.ports.read_config_data, self.ports.read_config_data)
def __init__(self, peak_generator): super().__init__(8, 32) self.wrapper = _PeakWrapper(peak_generator) # Generate core RTL (as magma). self.peak_circuit = FromMagma(self.wrapper.rtl()) # Add input/output ports and wire them. inputs = self.wrapper.inputs() outputs = self.wrapper.outputs() for ports, dir_ in ( (inputs, magma.In), (outputs, magma.Out), ): for i, (name, typ) in enumerate(ports.items()): magma_type = _convert_type(typ) self.add_port(name, dir_(magma_type)) my_port = self.ports[name] if magma_type is magma.Bits[1]: my_port = my_port[0] magma_name = name if dir_ is magma.In else f"O{i}" self.wire(my_port, self.peak_circuit.ports[magma_name]) self.add_ports(config=magma.In(ConfigurationType(8, 32)), ) # TODO(rsetaluri): Figure out stall signals. # Set up configuration for PE instruction. Currently, we perform a naive # partitioning of the large instruction into 32-bit config registers. config_width = self.wrapper.instruction_width() num_config = math.ceil(config_width / 32) instr_name = self.wrapper.instruction_name() for i in range(num_config): name = f"{instr_name}_{i}" self.add_config(name, 32) lb = i * 32 ub = min(i * 32 + 32, config_width) len_ = ub - lb self.wire(self.registers[name].ports.O[:len_], self.peak_circuit.ports[instr_name][lb:ub]) self._setup_config()
def __add_global_ports(self, stall_signal_width: int): self.add_ports(config=magma.In( ConfigurationType(self.config_data_width, self.config_data_width)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), stall=magma.In(magma.Bits[stall_signal_width])) if self.double_buffer: self.add_ports(config_db=magma.In(magma.Bit), use_db=magma.In(magma.Bit)) return (self.ports.config.qualified_name(), self.ports.clk.qualified_name(), self.ports.reset.qualified_name(), self.ports.stall.qualified_name(), self.ports.config_db.qualified_name(), self.ports.use_db.qualified_name()) return (self.ports.config.qualified_name(), self.ports.clk.qualified_name(), self.ports.reset.qualified_name(), self.ports.stall.qualified_name())
def __init__(self, data_width, word_width, data_depth, num_banks, use_sram_stub): super().__init__(8, 32) self.data_width = data_width self.data_depth = data_depth self.num_banks = num_banks self.word_width = word_width if use_sram_stub: self.use_sram_stub = 1 else: self.use_sram_stub = 0 TData = magma.Bits[self.word_width] TBit = magma.Bits[1] self.add_ports( data_in=magma.In(TData), addr_in=magma.In(TData), data_out=magma.Out(TData), flush=magma.In(TBit), wen_in=magma.In(TBit), ren_in=magma.In(TBit), stall=magma.In(magma.Bits[4]), valid_out=magma.Out(TBit), switch_db=magma.In(TBit) ) # Instead of a single read_config_data, we have multiple for each # "sub"-feature of this core. # self.ports.pop("read_config_data") if (data_width, word_width, data_depth, num_banks, use_sram_stub) not in \ MemCore.__circuit_cache: 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, word_width=self.word_width, num_banks=self.num_banks, use_sram_stub=self.use_sram_stub) MemCore.__circuit_cache[(data_width, word_width, data_depth, num_banks, use_sram_stub)] = circ else: circ = MemCore.__circuit_cache[(data_width, word_width, data_depth, num_banks, use_sram_stub)] self.underlying = FromMagma(circ) # put a 1-bit register and a mux to select the control signals control_signals = ["wen_in", "ren_in", "flush", "switch_db"] for control_signal in control_signals: # TODO: consult with Ankita to see if we can use the normal # mux here mux = MuxWrapper(2, 1, name=f"{control_signal}_sel") reg_value_name = f"{control_signal}_reg_value" reg_sel_name = f"{control_signal}_reg_sel" self.add_config(reg_value_name, 1) self.add_config(reg_sel_name, 1) self.wire(mux.ports.I[0], self.ports[control_signal]) self.wire(mux.ports.I[1], self.registers[reg_value_name].ports.O) self.wire(mux.ports.S, self.registers[reg_sel_name].ports.O) # 0 is the default wire, which takes from the routing network self.wire(mux.ports.O[0], self.underlying.ports[control_signal]) 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.reset, self.underlying.ports.reset) self.wire(self.ports.clk, self.underlying.ports.clk) self.wire(self.ports.valid_out[0], self.underlying.ports.valid_out) # 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) zero_signals = ( ("chain_wen_in", 1), ("chain_in", self.word_width), ) one_signals = ( ("config_read", 1), ("config_write", 1) ) # enable read and write by default for name, width in zero_signals: val = magma.bits(0, width) if width > 1 else magma.bit(0) self.wire(Const(val), self.underlying.ports[name]) for name, width in one_signals: val = magma.bits(1, width) if width > 1 else magma.bit(1) self.wire(Const(val), self.underlying.ports[name]) self.wire(Const(magma.bits(0, 24)), self.underlying.ports.config_addr[0:24]) # we have five features in total # 0: TILE # 1-4: SMEM # Feature 0: Tile self.__features: List[CoreFeature] = [self] # Features 1-4: SRAM for sram_index in range(4): core_feature = CoreFeature(self, sram_index + 1) self.__features.append(core_feature) # Wire the config for idx, core_feature in enumerate(self.__features): if(idx > 0): self.add_port(f"config_{idx}", magma.In(ConfigurationType(8, 32))) # port aliasing core_feature.ports["config"] = self.ports[f"config_{idx}"] self.add_port("config", magma.In(ConfigurationType(8, 32))) # or the signal up t = ConfigurationType(8, 32) t_names = ["config_addr", "config_data"] or_gates = {} for t_name in t_names: port_type = t[t_name] or_gate = FromMagma(mantle.DefineOr(len(self.__features), len(port_type))) or_gate.instance_name = f"OR_{t_name}_FEATURE" for idx, core_feature in enumerate(self.__features): self.wire(or_gate.ports[f"I{idx}"], core_feature.ports.config[t_name]) or_gates[t_name] = or_gate self.wire(or_gates["config_addr"].ports.O, self.underlying.ports.config_addr[24:32]) self.wire(or_gates["config_data"].ports.O, self.underlying.ports.config_data) # only the first one has config_en # self.wire(self.__features[0].ports.config.write[0], # self.underlying.ports.config_en) # read data out for idx, core_feature in enumerate(self.__features): if(idx > 0): self.add_port(f"read_config_data_{idx}", magma.Out(magma.Bits[32])) # port aliasing core_feature.ports["read_config_data"] = \ self.ports[f"read_config_data_{idx}"] # MEM config # self.wire(self.ports.read_config_data, # self.underlying.ports.read_config_data) configurations = [ ("stencil_width", 32), ("read_mode", 1), ("arbitrary_addr", 1), ("starting_addr", 32), ("iter_cnt", 32), ("dimensionality", 32), ("circular_en", 1), ("almost_count", 4), ("enable_chain", 1), ("mode", 2), ("tile_en", 1), ("chain_idx", 4), ("depth", 13) ] # Do all the stuff for the main config main_feature = self.__features[0] for config_reg_name, width in configurations: main_feature.add_config(config_reg_name, width) if(width == 1): self.wire(main_feature.registers[config_reg_name].ports.O[0], self.underlying.ports[config_reg_name]) else: self.wire(main_feature.registers[config_reg_name].ports.O, self.underlying.ports[config_reg_name]) for idx in range(8): main_feature.add_config(f"stride_{idx}", 32) main_feature.add_config(f"range_{idx}", 32) self.wire(main_feature.registers[f"stride_{idx}"].ports.O, self.underlying.ports[f"stride_{idx}"]) self.wire(main_feature.registers[f"range_{idx}"].ports.O, self.underlying.ports[f"range_{idx}"]) # SRAM for sram_index in range(4): core_feature = self.__features[sram_index + 1] self.wire(core_feature.ports.read_config_data, self.underlying.ports[f"read_data_sram_{sram_index}"]) # also need to wire the sram signal self.wire(core_feature.ports.config.write[0], self.underlying.ports["config_en_sram"][sram_index]) self._setup_config() conf_names = list(self.registers.keys()) conf_names.sort() with open("mem_cfg.txt", "w+") as cfg_dump: for idx, reg in enumerate(conf_names): write_line = f"|{reg}|{idx}|{self.registers[reg].width}||\n" cfg_dump.write(write_line)
def __init__(self, width, height, add_pd, interconnect_only: bool = False, use_sram_stub: bool = True, standalone: bool = False, add_pond: bool = True, use_io_valid: bool = False, pipeline_config_interval: int = 8, glb_params: GlobalBufferParams = GlobalBufferParams(), pe_fc=lassen_fc): super().__init__() # Check consistency of @standalone and @interconnect_only parameters. If # @standalone is True, then interconnect_only must also be True. if standalone: assert interconnect_only # configuration parameters self.glb_params = glb_params config_addr_width = 32 config_data_width = 32 self.config_addr_width = config_addr_width self.config_data_width = config_data_width axi_addr_width = 13 axi_data_width = 32 # axi_data_width must be same as cgra config_data_width assert axi_data_width == config_data_width tile_id_width = 16 config_addr_reg_width = 8 num_tracks = 5 # size self.width = width self.height = height # only north side has IO if standalone: io_side = IOSide.None_ else: io_side = IOSide.North self.pe_fc = pe_fc if not interconnect_only: # width must be even number assert (self.width % 2) == 0 # Bank should be larger than or equal to 1KB assert glb_params.bank_addr_width >= 10 glb_tile_mem_size = 2 ** (glb_params.bank_addr_width - 10) + \ math.ceil(math.log(glb_params.banks_per_tile, 2)) wiring = GlobalSignalWiring.ParallelMeso self.global_controller = GlobalController(addr_width=config_addr_width, data_width=config_data_width, axi_addr_width=axi_addr_width, axi_data_width=axi_data_width, num_glb_tiles=glb_params.num_glb_tiles, glb_addr_width=glb_params.glb_addr_width, glb_tile_mem_size=glb_tile_mem_size, block_axi_addr_width=glb_params.axi_addr_width) self.global_buffer = GlobalBufferMagma(glb_params) else: wiring = GlobalSignalWiring.Meso interconnect = create_cgra(width, height, io_side, reg_addr_width=config_addr_reg_width, config_data_width=config_data_width, tile_id_width=tile_id_width, num_tracks=num_tracks, add_pd=add_pd, add_pond=add_pond, use_io_valid=use_io_valid, use_sram_stub=use_sram_stub, global_signal_wiring=wiring, pipeline_config_interval=pipeline_config_interval, mem_ratio=(1, 4), standalone=standalone, pe_fc=pe_fc) self.interconnect = interconnect # make multiple stall ports stall_port_pass(self.interconnect) # make multiple configuration ports config_port_pass(self.interconnect) if not interconnect_only: self.add_ports( jtag=JTAGType, clk_in=magma.In(magma.Clock), reset_in=magma.In(magma.AsyncReset), proc_packet=ProcPacketIfc( glb_params.glb_addr_width, glb_params.bank_data_width).slave, axi4_slave=AXI4LiteIfc(axi_addr_width, axi_data_width).slave, interrupt=magma.Out(magma.Bit), cgra_running_clk_out=magma.Out(magma.Clock), ) # top <-> global controller ports connection self.wire(self.ports.clk_in, self.global_controller.ports.clk_in) self.wire(self.ports.reset_in, self.global_controller.ports.reset_in) self.wire(self.ports.jtag, self.global_controller.ports.jtag) self.wire(self.ports.axi4_slave, self.global_controller.ports.axi4_slave) self.wire(self.ports.interrupt, self.global_controller.ports.interrupt) self.wire(self.ports.cgra_running_clk_out, self.global_controller.ports.clk_out) # top <-> global buffer ports connection self.wire(self.ports.clk_in, self.global_buffer.ports.clk) self.wire(self.ports.proc_packet.wr_en, self.global_buffer.ports.proc_wr_en[0]) self.wire(self.ports.proc_packet.wr_strb, self.global_buffer.ports.proc_wr_strb) self.wire(self.ports.proc_packet.wr_addr, self.global_buffer.ports.proc_wr_addr) self.wire(self.ports.proc_packet.wr_data, self.global_buffer.ports.proc_wr_data) self.wire(self.ports.proc_packet.rd_en, self.global_buffer.ports.proc_rd_en[0]) self.wire(self.ports.proc_packet.rd_addr, self.global_buffer.ports.proc_rd_addr) self.wire(self.ports.proc_packet.rd_data, self.global_buffer.ports.proc_rd_data) self.wire(self.ports.proc_packet.rd_data_valid, self.global_buffer.ports.proc_rd_data_valid[0]) # Top -> Interconnect clock port connection self.wire(self.ports.clk_in, self.interconnect.ports.clk) glb_glc_wiring(self) glb_interconnect_wiring(self) glc_interconnect_wiring(self) else: # lift all the interconnect ports up for name in self.interconnect.interface(): self.add_port(name, self.interconnect.ports[name].type()) self.wire(self.ports[name], self.interconnect.ports[name]) self.add_ports( clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), config=magma.In(magma.Array[width, ConfigurationType(config_data_width, config_data_width)]), stall=magma.In( magma.Bits[self.width * self.interconnect.stall_signal_width]), read_config_data=magma.Out(magma.Bits[config_data_width]) ) self.wire(self.ports.clk, self.interconnect.ports.clk) self.wire(self.ports.reset, self.interconnect.ports.reset) self.wire(self.ports.config, self.interconnect.ports.config) self.wire(self.ports.stall, self.interconnect.ports.stall) self.wire(self.interconnect.ports.read_config_data, self.ports.read_config_data)
def __init__(self, data_width, data_depth): super().__init__(8, 32) 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), flush=magma.In(TBit), wen_in=magma.In(TBit), ren_in=magma.In(TBit), stall=magma.In(magma.Bits[4])) # Instead of a single read_config_data, we have multiple for each # "sub"-feature of this core. self.ports.pop("read_config_data") 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.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. zero_signals = ( ("config_en_linebuf", 1), ("chain_wen_in", 1), ("chain_in", self.data_width), ) one_signals = ( ("config_read", 1), ("config_write", 1), ) # enable read and write by default for name, width in zero_signals: val = magma.bits(0, width) if width > 1 else magma.bit(0) self.wire(Const(val), self.underlying.ports[name]) for name, width in one_signals: val = magma.bits(1, width) if width > 1 else magma.bit(1) self.wire(Const(val), self.underlying.ports[name]) self.wire(Const(magma.bits(0, 24)), self.underlying.ports.config_addr[0:24]) # we have five features in total # 0: LINEBUF # 1-4: SMEM # current setup is already in line buffer mode, so we pass self in # notice that config_en_linebuf is to change the address in the # line buffer mode, which is not used in practice self.__features: List[CoreFeature] = [CoreFeature(self, 0)] for sram_index in range(4): core_feature = CoreFeature(self, sram_index + 1) self.__features.append(core_feature) for idx, core_feature in enumerate(self.__features): self.add_port(f"config_{idx}", magma.In(ConfigurationType(8, 32))) # port aliasing core_feature.ports["config"] = self.ports[f"config_{idx}"] # or the signal up t = ConfigurationType(8, 32) t_names = ["config_addr", "config_data"] or_gates = {} for t_name in t_names: port_type = t[t_name] or_gate = FromMagma( mantle.DefineOr(len(self.__features), len(port_type))) or_gate.instance_name = f"OR_{t_name}_FEATURE" for idx, core_feature in enumerate(self.__features): self.wire(or_gate.ports[f"I{idx}"], core_feature.ports.config[t_name]) or_gates[t_name] = or_gate self.wire(or_gates["config_addr"].ports.O, self.underlying.ports.config_addr[24:32]) self.wire(or_gates["config_data"].ports.O, self.underlying.ports.config_data) # only the first one has config_en self.wire(self.__features[0].ports.config.write[0], self.underlying.ports.config_en) # read data out for idx, core_feature in enumerate(self.__features): self.add_port(f"read_config_data_{idx}", magma.Out(magma.Bits[32])) # port aliasing core_feature.ports["read_config_data"] = \ self.ports[f"read_config_data_{idx}"] # MEM config self.wire(self.ports.read_config_data_0, self.underlying.ports.read_data) # SRAM for sram_index in range(4): core_feature = self.__features[sram_index + 1] self.wire(core_feature.ports.read_config_data, self.underlying.ports[f"read_data_sram_{sram_index}"]) # also need to wire the sram signal self.add_port(f"config_en_{sram_index}", magma.In(magma.Bit)) # port aliasing core_feature.ports["config_en"] = \ self.ports[f"config_en_{sram_index}"] self.wire(self.underlying.ports["config_en_sram"][sram_index], self.ports[f"config_en_{sram_index}"])