def __init__(self, data_width, data_depth): super().__init__() 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), clk=magma.In(magma.Clock), config=magma.In(ConfigurationType(8, 32)), read_config_data=magma.Out(magma.Bits(32)), reset=magma.In(magma.AsyncReset), flush=magma.In(TBit), wen_in=magma.In(TBit), ren_in=magma.In(TBit), stall=magma.In(magma.Bits(4))) 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.config.config_addr, self.underlying.ports.config_addr[24:32]) self.wire(self.ports.config.config_data, self.underlying.ports.config_data) self.wire(self.ports.config.write[0], self.underlying.ports.config_en) self.wire(self.underlying.ports.read_data, self.ports.read_config_data) 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. signals = ( ("config_en_sram", 4), ("config_en_linebuf", 1), ("chain_wen_in", 1), ("config_read", 1), ("config_write", 1), ("chain_in", self.data_width), ) for name, width in signals: val = magma.bits(0, width) if width > 1 else magma.bit(0) self.wire(Const(val), self.underlying.ports[name]) self.wire(Const(magma.bits(0, 24)), self.underlying.ports.config_addr[0:24])
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)
def __init__(self): super().__init__() # TODO(rsetaluri): Currently we assume the default parameters into the # wrapper. Ideally we should take some arguments into this generator # and pass them to the genesis wrapper. wrapper = pe_core_genesis2.pe_core_wrapper generator = wrapper.generator(mode="declare") circ = generator() self.underlying = FromMagma(circ) TData = magma.Bits(16) TBit = magma.Bits(1) TFlag = magma.Bits(4) self.add_ports( data0=magma.In(TData), data1=magma.In(TData), bit0=magma.In(TBit), bit1=magma.In(TBit), bit2=magma.In(TBit), res=magma.Out(TData), res_p=magma.Out(TFlag), 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: Make number of stall domains paramaterizable stall=magma.In(magma.Bits(4)) ) self.wire(self.ports.data0, self.underlying.ports.data0) self.wire(self.ports.data1, self.underlying.ports.data1) self.wire(self.ports.bit0[0], self.underlying.ports.bit0) self.wire(self.ports.bit1[0], self.underlying.ports.bit1) self.wire(self.ports.bit2[0], self.underlying.ports.bit2) self.wire(self.ports.res, self.underlying.ports.res) self.wire(self.ports.res_p, self.underlying.ports.res_p) self.wire(self.ports.config.config_addr, self.underlying.ports.cfg_a) self.wire(self.ports.config.config_data, self.underlying.ports.cfg_d) self.wire(self.ports.config.write[0], self.underlying.ports.cfg_en) self.wire(self.underlying.ports.read_data, self.ports.read_config_data) # TODO: Make PE core use active high reset self.wire(self.ports.reset, self.underlying.ports.rst_n) # 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)
def __init__(self, height, width): super().__init__() self.height = height self.width = width T = magma.Bits(self.width) # In the case that @height <= 1, we make this circuit a simple # pass-through circuit. if self.height <= 1: self.add_ports( I=magma.In(magma.Array(1, T)), O=magma.Out(T), ) self.wire(self.ports.I[0], self.ports.O) self.sel_bits = 0 return MuxCls = mantle.DefineMux(self.height, self.width) self.mux = FromMagma(MuxCls) self.sel_bits = magma.bitutils.clog2(self.height) self.add_ports( I=magma.In(magma.Array(self.height, T)), S=magma.In(magma.Bits(self.sel_bits)), O=magma.Out(T), ) for i in range(self.height): self.wire(self.ports.I[i], self.mux.ports[f"I{i}"]) mux_in = self.ports.S if self.sel_bits > 1 else self.ports.S[0] self.wire(mux_in, self.mux.ports.S) self.wire(self.mux.ports.O, self.ports.O)
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
def read_data_reduction(self): pass_through = self.ports.read_config_data input_name = pass_through.qualified_name() + "_in" # Create input port for pass through read_data reduction self.add_port(input_name, magma.In(pass_through.base_type())) # Remove the current connection to the read_data output self.remove_wire(self.read_data_mux.ports.O, pass_through) self.read_data_reduce_or = FromMagma(mantle.DefineOr(2, 32)) # OR previous read_data output with read_data input to create NEW # read_data output self.wire(self.read_data_mux.ports.O, self.read_data_reduce_or.ports.I0) self.wire(self.ports[input_name], self.read_data_reduce_or.ports.I1) self.wire(self.read_data_reduce_or.ports.O, pass_through)
def __init__(self, columns): super().__init__() assert all([c.height == columns[0].height for c in columns]) self.width = len(columns) self.height = columns[0].height self.columns = columns self.side_type = SideType(5, (1, 16)) self.add_ports( north=magma.Array(self.width, self.side_type), south=magma.Array(self.width, self.side_type), west=magma.Array(self.height, self.side_type), east=magma.Array(self.height, self.side_type), config=magma.In(ConfigurationType(32, 32)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out(magma.Bits(32)), # TODO: make number of stall domains a param stall=magma.In(magma.Bits(4))) for column in self.columns: self.wire(self.ports.config, column.ports.config) self.wire(self.ports.reset, column.ports.reset) self.wire(self.ports.stall, column.ports.stall) self.wire(self.ports.west, self.columns[0].ports.west) self.wire(self.ports.east, self.columns[-1].ports.east) for i, column in enumerate(self.columns): self.wire(self.ports.north[i], column.ports.north) self.wire(self.ports.south[i], column.ports.south) for i in range(1, self.width): c0 = self.columns[i - 1] c1 = self.columns[i] for j in range(self.height): self.wire(c1.ports.west[j].O, c0.ports.east[j].I) self.wire(c0.ports.east[j].O, c1.ports.west[j].I) # OR together read_data outputs from each column # number of inputs = number of columns self.read_data_OR = FromMagma(mantle.DefineOr(len(self.columns), 32)) for i, col in enumerate(columns): self.wire(self.read_data_OR.ports[f"I{i}"], col.ports.read_config_data) # wire up column number input self.wire(col.ports.column_num, Const(magma.bits(i, 8))) self.wire(self.read_data_OR.ports.O, self.ports.read_config_data)
def __init__(self, addr_width, data_width): super().__init__() super().__init__() self.addr_width = addr_width self.data_width = data_width self.config_type = ConfigurationType(self.addr_width, self.data_width) self.add_ports( jtag=JTAGType, config=magma.Out(self.config_type), read_data_in=magma.In(magma.Bits(self.data_width)), clk_in=magma.In(magma.Clock), reset_in=magma.In(magma.AsyncReset), clk_out=magma.Out(magma.Clock), reset_out=magma.Out(magma.AsyncReset), # TODO: make number of stall domains a param stall=magma.Out(magma.Bits(4)) ) wrapper = global_controller_genesis2.gc_wrapper generator = wrapper.generator(mode="declare") self.underlying = FromMagma(generator()) self.wire(self.ports.jtag.tdi, self.underlying.ports.tdi) self.wire(self.ports.jtag.tdo, self.underlying.ports.tdo) self.wire(self.ports.jtag.tms, self.underlying.ports.tms) self.wire(self.ports.jtag.tck, self.underlying.ports.tck) self.wire(self.ports.jtag.trst_n, self.underlying.ports.trst_n) self.wire(self.ports.clk_in, self.underlying.ports.clk_in) self.wire(self.ports.reset_in, self.underlying.ports.reset_in) self.wire(self.underlying.ports.config_addr_out, self.ports.config.config_addr) self.wire(self.underlying.ports.config_data_out, self.ports.config.config_data) self.wire(self.underlying.ports.read, self.ports.config.read[0]) self.wire(self.underlying.ports.write, self.ports.config.write[0]) self.wire(self.underlying.ports.clk_out, self.ports.clk_out) self.wire(self.underlying.ports.reset_out, self.ports.reset_out) self.wire(self.underlying.ports.cgra_stalled, self.ports.stall) self.wire(self.ports.read_data_in, self.underlying.ports.config_data_in)
def __add_config(self): self.add_ports(config=magma.In( ConfigurationType(self.config_data_width, self.config_data_width)), tile_id=magma.In(magma.Bits(self.tile_id_width)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out( magma.Bits(self.config_data_width))) features = self.features() num_features = len(features) self.read_data_mux = MuxWithDefaultWrapper(num_features, self.config_data_width, self.config_addr_width, 0) # most of the logic copied from tile_magma.py # remove all hardcoded values for feature in self.features(): self.wire(self.ports.config.config_addr[self.feature_config_slice], feature.ports.config.config_addr) self.wire(self.ports.config.config_data, feature.ports.config.config_data) self.wire(self.ports.config.read, feature.ports.config.read) # Connect S input to config_addr.feature. self.wire(self.ports.config.config_addr[self.feature_addr_slice], self.read_data_mux.ports.S) self.wire(self.read_data_mux.ports.O, self.ports.read_config_data) # Logic to generate EN input for read_data_mux self.read_and_tile = FromMagma(mantle.DefineAnd(2)) self.eq_tile = FromMagma(mantle.DefineEQ(self.tile_id_width)) # config_addr.tile_id == self.tile_id? self.wire(self.ports.tile_id, self.eq_tile.ports.I0) self.wire(self.ports.config.config_addr[self.tile_id_slice], self.eq_tile.ports.I1) # (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.read_and_tile.ports.I1, self.ports.config.read[0]) # read_data_mux.EN = (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.O, self.read_data_mux.ports.EN[0]) # Logic for writing to config registers # Config_en_tile = (config_addr.tile_id == self.tile_id & WRITE) self.write_and_tile = FromMagma(mantle.DefineAnd(2)) self.wire(self.write_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.write_and_tile.ports.I1, self.ports.config.write[0]) self.decode_feat = [] self.feat_and_config_en_tile = [] for i, feat in enumerate(self.features()): # wire each feature's read_data output to # read_data_mux inputs self.wire(feat.ports.read_config_data, self.read_data_mux.ports.I[i]) # for each feature, # config_en = (config_addr.feature == feature_num) & config_en_tile self.decode_feat.append( FromMagma(mantle.DefineDecode(i, self.config_addr_width))) self.feat_and_config_en_tile.append(FromMagma(mantle.DefineAnd(2))) self.wire(self.decode_feat[i].ports.I, self.ports.config.config_addr[self.feature_addr_slice]) self.wire(self.decode_feat[i].ports.O, self.feat_and_config_en_tile[i].ports.I0) self.wire(self.write_and_tile.ports.O, self.feat_and_config_en_tile[i].ports.I1) self.wire(self.feat_and_config_en_tile[i].ports.O, feat.ports.config.write[0])
def combine_read_data_outputs(self): self.read_data_OR = FromMagma(mantle.DefineOr(self.height, 32)) self.wire(self.read_data_OR.ports.O, self.ports.read_config_data) for i, tile in enumerate(self.tiles): self.wire(tile.ports.read_config_data, self.read_data_OR.ports[f"I{i}"])
def __init__(self, core): super().__init__() self.core = core self.sb = SB(self.core.outputs()) widths = [get_width(i.type()) for i in self.core.inputs()] self.cbs = [CB(10, w) for w in widths] self.add_ports( north=SideType(5, (1, 16)), west=SideType(5, (1, 16)), south=SideType(5, (1, 16)), east=SideType(5, (1, 16)), config=magma.In(ConfigurationType(32, 32)), tile_id=magma.In(magma.Bits(16)), clk=magma.In(magma.Clock), reset=magma.In(magma.AsyncReset), read_config_data=magma.Out(magma.Bits(32)), stall=magma.In(magma.Bits(4)) ) self.wire(self.ports.north, self.sb.ports.north) self.wire(self.ports.west, self.sb.ports.west) self.wire(self.ports.south, self.sb.ports.south) self.wire(self.ports.east, self.sb.ports.east) # this is hacky, but connect stall if the core has a stall input if "stall" in self.core.ports: self.wire(self.ports.stall, core.ports.stall) sides = (self.ports.north, self.ports.west) for i, cb in enumerate(self.cbs): side = sides[i % len(sides)] self.__wire_cb(side, cb) for i, input_ in enumerate(self.core.inputs()): self.wire(self.cbs[i].ports.O, input_) for i, out in enumerate(self.core.outputs()): self.wire(out, self.sb.ports[out._name]) for feature in self.features(): self.wire(self.ports.config.config_addr[24:32], feature.ports.config.config_addr) self.wire(self.ports.config.config_data, feature.ports.config.config_data) self.wire(self.ports.config.read, feature.ports.config.read) # read_data mux num_mux_inputs = len(self.features()) self.read_data_mux = MuxWithDefaultWrapper(num_mux_inputs, 32, 8, 0) # Connect S input to config_addr.feature. self.wire(self.ports.config.config_addr[16:24], self.read_data_mux.ports.S) self.wire(self.read_data_mux.ports.O, self.ports.read_config_data) # Logic to generate EN input for read_data_mux self.read_and_tile = FromMagma(mantle.DefineAnd(2)) self.eq_tile = FromMagma(mantle.DefineEQ(16)) # config_addr.tile_id == self.tile_id? self.wire(self.ports.tile_id, self.eq_tile.ports.I0) self.wire(self.ports.config.config_addr[0:16], self.eq_tile.ports.I1) # (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.read_and_tile.ports.I1, self.ports.config.read[0]) # read_data_mux.EN = (config_addr.tile_id == self.tile_id) & READ self.wire(self.read_and_tile.ports.O, self.read_data_mux.ports.EN[0]) # Logic for writing to config registers # Config_en_tile = (config_addr.tile_id == self.tile_id & WRITE) self.write_and_tile = FromMagma(mantle.DefineAnd(2)) self.wire(self.write_and_tile.ports.I0, self.eq_tile.ports.O) self.wire(self.write_and_tile.ports.I1, self.ports.config.write[0]) self.decode_feat = [] self.feat_and_config_en_tile = [] for i, feat in enumerate(self.features()): # wire each feature's read_data output to # read_data_mux inputs self.wire(feat.ports.read_config_data, self.read_data_mux.ports.I[i]) # for each feature, # config_en = (config_addr.feature == feature_num) & config_en_tile self.decode_feat.append(FromMagma(mantle.DefineDecode(i, 8))) self.feat_and_config_en_tile.append(FromMagma(mantle.DefineAnd(2))) self.wire(self.decode_feat[i].ports.I, self.ports.config.config_addr[16:24]) self.wire(self.decode_feat[i].ports.O, self.feat_and_config_en_tile[i].ports.I0) self.wire(self.write_and_tile.ports.O, self.feat_and_config_en_tile[i].ports.I1) self.wire(self.feat_and_config_en_tile[i].ports.O, feat.ports.config.write[0])