class Arbiter(Module): def __init__(self, pe_id, config): self.network_interface_in = NetworkInterface( name="left_in", **config.addresslayout.get_params()) self.network_interface_out = NetworkInterface( name="right_out", **config.addresslayout.get_params()) self.local_interface_in = NetworkInterface( name="local_in", **config.addresslayout.get_params()) local_interface_out = NetworkInterface( name="local_out", **config.addresslayout.get_params()) self.apply_interface_out = ApplyInterface( **config.addresslayout.get_params()) self.start_message = ApplyInterface( **config.addresslayout.get_params()) self.start_message.select = Signal() self.network_round = Signal(config.addresslayout.channel_bits) self.round_accepting = Signal(config.addresslayout.channel_bits) mux_interface = NetworkInterface(**config.addresslayout.get_params()) inject = Signal() self.comb += [ inject.eq( self.local_interface_in.msg.roundpar == self.network_round), If( self.network_interface_in.valid & (self.network_interface_in.msg.roundpar == self.network_round), self.network_interface_in.connect(mux_interface)).Elif( inject, self.local_interface_in.connect(mux_interface)) ] self.comb += [ If(mux_interface.dest_pe == pe_id, mux_interface.connect(local_interface_out)).Else( mux_interface.connect(self.network_interface_out)) ] self.submodules.barriercounter = Barriercounter(config) self.comb += [ local_interface_out.msg.connect( self.barriercounter.apply_interface_in.msg), self.barriercounter.apply_interface_in.valid.eq( local_interface_out.valid), local_interface_out.ack.eq( self.barriercounter.apply_interface_in.ack), If(self.start_message.select, self.start_message.connect(self.apply_interface_out)).Else( self.barriercounter.apply_interface_out.connect( self.apply_interface_out)), self.round_accepting.eq(self.barriercounter.round_accepting) ] def gen_selfcheck(self, tb): yield
class Arbiter(Module): def __init__(self, pe_id, config): self.network_interface_in = NetworkInterface(name="left_in", **config.addresslayout.get_params()) self.network_interface_out = NetworkInterface(name="right_out", **config.addresslayout.get_params()) self.local_interface_in = NetworkInterface(name="local_in", **config.addresslayout.get_params()) local_interface_out = NetworkInterface(name="local_out", **config.addresslayout.get_params()) self.apply_interface_out = ApplyInterface(**config.addresslayout.get_params()) self.start_message = ApplyInterface(**config.addresslayout.get_params()) self.start_message.select = Signal() self.network_round = Signal(config.addresslayout.channel_bits) self.round_accepting = Signal(config.addresslayout.channel_bits) mux_interface = NetworkInterface(**config.addresslayout.get_params()) inject = Signal() self.comb += [ inject.eq(self.local_interface_in.msg.roundpar == self.network_round), If(self.network_interface_in.valid & (self.network_interface_in.msg.roundpar == self.network_round), self.network_interface_in.connect(mux_interface) ).Elif(inject, self.local_interface_in.connect(mux_interface) ) ] self.comb += [ If(mux_interface.dest_pe == pe_id, mux_interface.connect(local_interface_out) ).Else( mux_interface.connect(self.network_interface_out) ) ] self.submodules.barriercounter = Barriercounter(config) self.comb += [ local_interface_out.msg.connect(self.barriercounter.apply_interface_in.msg), self.barriercounter.apply_interface_in.valid.eq(local_interface_out.valid), local_interface_out.ack.eq(self.barriercounter.apply_interface_in.ack), If(self.start_message.select, self.start_message.connect(self.apply_interface_out) ).Else( self.barriercounter.apply_interface_out.connect(self.apply_interface_out) ), self.round_accepting.eq(self.barriercounter.round_accepting) ] def gen_selfcheck(self, tb): yield
def __init__(self, config): num_pe = config.addresslayout.num_pe num_nodes_per_pe = config.addresslayout.num_nodes_per_pe self.apply_interface = [ ApplyInterface(name="network_out", **config.addresslayout.get_params()) for _ in range(num_pe) ] self.network_interface = [ NetworkInterface(name="network_in", **config.addresslayout.get_params()) for _ in range(num_pe) ] fifos = [ InterfaceFIFO(layout=set_layout_parameters( _network_layout, **config.addresslayout.get_params()), depth=8) for i in range(num_pe) ] self.submodules.fifos = fifos self.submodules.arbiter = [ Arbiter(sink, config) for sink in range(num_pe) ] for i in range(num_pe): j = (i + 1) % num_pe self.comb += [ self.arbiter[i].network_interface_out.connect(fifos[i].din), fifos[i].dout.connect(self.arbiter[j].network_interface_in), self.network_interface[i].connect( self.arbiter[i].local_interface_in), self.arbiter[i].apply_interface_out.connect( self.apply_interface[i]) ] network_round = Signal(config.addresslayout.channel_bits) next_round = Signal(config.addresslayout.channel_bits) proceed = Signal() self.comb += [ proceed.eq( reduce(and_, [a.round_accepting == next_round for a in self.arbiter])), If(network_round < config.addresslayout.num_channels - 1, next_round.eq(network_round + 1)).Else(next_round.eq(0)), [ self.arbiter[i].network_round.eq(network_round) for i in range(num_pe) ] ] self.sync += If(proceed, network_round.eq(next_round))
def __init__(self, config): num_pe = config.addresslayout.num_pe num_nodes_per_pe = config.addresslayout.num_nodes_per_pe self.apply_interface = [ ApplyInterface(name="network_out", **config.addresslayout.get_params()) for _ in range(num_pe) ] self.network_interface = [ NetworkInterface(name="network_in", **config.addresslayout.get_params()) for _ in range(num_pe) ] self.submodules.arbiter = [ Arbiter(sink, config) for sink in range(num_pe) ] self.comb += [ a.apply_interface_out.connect(self.apply_interface[i]) for i, a in enumerate(self.arbiter) ]
def __init__(self, config): self.network_interface_in = NetworkInterface(name="barrierdistributor_in", **config.addresslayout.get_params()) self.network_interface_out = NetworkInterface(name="barrierdistributor_out", **config.addresslayout.get_params()) self.submodules.fifo = InterfaceFIFO(layout=self.network_interface_in.layout, depth=8) self.comb += [ self.network_interface_in.connect(self.fifo.din) ] self.total_num_messages = Signal(32) self.sync += [ If(self.network_interface_out.valid & self.network_interface_out.ack & ~self.network_interface_out.msg.barrier, self.total_num_messages.eq(self.total_num_messages + 1) ) ] num_pe = config.addresslayout.num_pe have_barrier = Signal() curr_barrier = Signal(config.addresslayout.peidsize) barrier_done = Signal() sink = Signal(config.addresslayout.peidsize) num_msgs_since_last_barrier = Array(Signal(config.addresslayout.nodeidsize) for _ in range(num_pe)) halt = Signal() self.comb += [ have_barrier.eq(self.fifo.dout.msg.barrier & self.fifo.dout.valid), barrier_done.eq(curr_barrier == (num_pe - 1)) ] self.sync += [ If(have_barrier & self.network_interface_out.ack, num_msgs_since_last_barrier[curr_barrier].eq(0), If(~barrier_done, curr_barrier.eq(curr_barrier + 1) ).Else( curr_barrier.eq(0), halt.eq(1) ) ) ] self.sync += [ If(~have_barrier & self.fifo.dout.valid & self.fifo.dout.ack, num_msgs_since_last_barrier[sink].eq(num_msgs_since_last_barrier[sink] + 1), halt.eq(0) ) ] self.comb += [ If(have_barrier, sink.eq(curr_barrier), self.network_interface_out.dest_pe.eq(curr_barrier), self.network_interface_out.msg.dest_id.eq(num_msgs_since_last_barrier[sink]), self.network_interface_out.msg.halt.eq(halt), self.fifo.dout.ack.eq(barrier_done & self.network_interface_out.ack) ).Else( sink.eq(self.fifo.dout.dest_pe), self.network_interface_out.dest_pe.eq(self.fifo.dout.dest_pe), self.network_interface_out.msg.dest_id.eq(self.fifo.dout.msg.dest_id), self.network_interface_out.msg.halt.eq(0), self.fifo.dout.ack.eq(self.network_interface_out.ack) ), self.fifo.dout.connect(self.network_interface_out, omit=["ack", "dest_id", "dest_pe", "halt"]) ]
def __init__(self, config): self.network_interface_in = NetworkInterface( name="barrierdistributor_in", **config.addresslayout.get_params()) self.network_interface_out = NetworkInterface( name="barrierdistributor_out", **config.addresslayout.get_params()) self.submodules.fifo = InterfaceFIFO( layout=self.network_interface_in.layout, depth=8) self.comb += [self.network_interface_in.connect(self.fifo.din)] self.total_num_messages = Signal(32) self.sync += [ If( self.network_interface_out.valid & self.network_interface_out.ack & ~self.network_interface_out.msg.barrier, self.total_num_messages.eq(self.total_num_messages + 1)) ] num_pe = config.addresslayout.num_pe have_barrier = Signal() curr_barrier = Signal(config.addresslayout.peidsize) barrier_done = Signal() sink = Signal(config.addresslayout.peidsize) num_msgs_since_last_barrier = Array( Signal(config.addresslayout.nodeidsize) for _ in range(num_pe)) halt = Signal() self.comb += [ have_barrier.eq(self.fifo.dout.msg.barrier & self.fifo.dout.valid), barrier_done.eq(curr_barrier == (num_pe - 1)) ] self.sync += [ If( have_barrier & self.network_interface_out.ack, num_msgs_since_last_barrier[curr_barrier].eq(0), If(~barrier_done, curr_barrier.eq(curr_barrier + 1)).Else( curr_barrier.eq(0), halt.eq(1))) ] self.sync += [ If( ~have_barrier & self.fifo.dout.valid & self.fifo.dout.ack, num_msgs_since_last_barrier[sink].eq( num_msgs_since_last_barrier[sink] + 1), halt.eq(0)) ] self.comb += [ If( have_barrier, sink.eq(curr_barrier), self.network_interface_out.dest_pe.eq(curr_barrier), self.network_interface_out.msg.dest_id.eq( num_msgs_since_last_barrier[sink]), self.network_interface_out.msg.halt.eq(halt), self.fifo.dout.ack.eq( barrier_done & self.network_interface_out.ack)).Else( sink.eq(self.fifo.dout.dest_pe), self.network_interface_out.dest_pe.eq( self.fifo.dout.dest_pe), self.network_interface_out.msg.dest_id.eq( self.fifo.dout.msg.dest_id), self.network_interface_out.msg.halt.eq(0), self.fifo.dout.ack.eq(self.network_interface_out.ack)), self.fifo.dout.connect(self.network_interface_out, omit=["ack", "dest_id", "dest_pe", "halt"]) ]
def __init__(self, config): num_pe = config.addresslayout.num_pe num_nodes_per_pe = config.addresslayout.num_nodes_per_pe self.apply_interface = [ ApplyInterface(**config.addresslayout.get_params()) for _ in range(num_pe) ] self.network_interface = [ NetworkInterface(**config.addresslayout.get_params()) for _ in range(num_pe) ] fifos = [[ RecordFIFO( layout=Message(**config.addresslayout.get_params()).layout, depth=8) for i in range(num_pe) ] for j in range(num_pe)] self.submodules.fifos = fifos self.submodules.arbiter = [ Arbiter(config, fifos[sink]) for sink in range(num_pe) ] self.comb += [ self.arbiter[i].apply_interface.connect(self.apply_interface[i]) for i in range(num_pe) ] # connect fifos across PEs for source in range(num_pe): array_dest_id = Array( fifo.din.dest_id for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_sender = Array( fifo.din.sender for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_payload = Array( fifo.din.payload for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_roundpar = Array( fifo.din.roundpar for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_barrier = Array( fifo.din.barrier for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_we = Array( fifo.we for fifo in [fifos[sink][source] for sink in range(num_pe)]) array_writable = Array( fifo.writable for fifo in [fifos[sink][source] for sink in range(num_pe)]) have_barrier = Signal() barrier_ack = Array(Signal() for _ in range(num_pe)) barrier_done = Signal() self.comb += barrier_done.eq(reduce( and_, barrier_ack)), have_barrier.eq( self.network_interface[source].msg.barrier & self.network_interface[source].valid) self.sync += If(have_barrier & ~barrier_done, [ barrier_ack[i].eq(barrier_ack[i] | array_writable[i]) for i in range(num_pe) ]).Else([barrier_ack[i].eq(0) for i in range(num_pe)]) sink = Signal(config.addresslayout.peidsize) self.comb += If( have_barrier, [array_barrier[i].eq(1) for i in range(num_pe)], [ array_roundpar[i].eq( self.network_interface[source].msg.roundpar) for i in range(num_pe) ], [array_we[i].eq(~barrier_ack[i]) for i in range(num_pe)], self.network_interface[source].ack.eq(barrier_done)).Else( sink.eq(self.network_interface[source].dest_pe), array_dest_id[sink].eq( self.network_interface[source].msg.dest_id), array_sender[sink].eq( self.network_interface[source].msg.sender), array_payload[sink].eq( self.network_interface[source].msg.payload), array_roundpar[sink].eq( self.network_interface[source].msg.roundpar), array_we[sink].eq(self.network_interface[source].valid), self.network_interface[source].ack.eq( array_writable[sink]))
def __init__(self, pe_id, config, port=None): self.pe_id = pe_id addresslayout = config.addresslayout nodeidsize = addresslayout.nodeidsize num_nodes_per_pe = addresslayout.num_nodes_per_pe num_pe = addresslayout.num_pe edgeidsize = addresslayout.edgeidsize max_edges_per_pe = addresslayout.max_edges_per_pe peidsize = addresslayout.peidsize # input self.scatter_interface = ScatterInterface(**addresslayout.get_params()) #output self.network_interface = NetworkInterface(**addresslayout.get_params()) ### # # memory layout (TODO: replace with an actual record) def _pack_adj_idx(adj_idx): return [b<<edgeidsize | a for a,b in adj_idx] # # adj_idx, adj_val = adj_mat # CSR edge storage: (idx, val) tuple of arrays # idx: array of (start_adr, num_neighbors) self.specials.mem_idx = Memory(edgeidsize*2, max(2, len(config.adj_idx[pe_id])), name="edge_csr_idx", init=_pack_adj_idx(config.adj_idx[pe_id])) self.specials.rd_port_idx = rd_port_idx = self.mem_idx.get_port(has_re=True) self.specials.wr_port_idx = wr_port_idx = self.mem_idx.get_port(write_capable=True) # val: array of nodeids # resides in submodule if config.memtype == "HMC": from core_neighbors_hmc import Neighbors elif config.memtype == "HMCO": from core_neighbors_hmc_ordered import Neighbors elif config.memtype == "AXI": from core_neighbors_ddr import Neighbors else: from core_neighbors import Neighbors self.submodules.get_neighbors = Neighbors(pe_id=pe_id, config=config, port=port) # flow control variables upstream_ack = Signal() ## stage 1 # address idx with incoming message self.comb += [ rd_port_idx.adr.eq(addresslayout.local_adr(self.scatter_interface.sender)), rd_port_idx.re.eq(upstream_ack), self.scatter_interface.ack.eq(upstream_ack) ] # keep input for next stage scatter_msg1 = Signal(addresslayout.updatepayloadsize) scatter_sender1 = Signal(addresslayout.nodeidsize) scatter_round1 = Signal(config.addresslayout.channel_bits) scatter_msg_valid1 = Signal() scatter_barrier1 = Signal() # valid1 requests get_neighbors, so don't set for barrier self.sync += [ If( upstream_ack, scatter_msg1.eq(self.scatter_interface.payload), scatter_sender1.eq(self.scatter_interface.sender), scatter_round1.eq(self.scatter_interface.roundpar), scatter_msg_valid1.eq(self.scatter_interface.valid & ~self.scatter_interface.barrier), scatter_barrier1.eq(self.scatter_interface.valid & self.scatter_interface.barrier) ) ] ## stage 2 # ask get_neighbors submodule for all neighbors of input node # upstream_ack will only go up again when all neighbors done self.comb +=[ self.get_neighbors.neighbor_in.start_idx.eq(rd_port_idx.dat_r[:edgeidsize]), self.get_neighbors.neighbor_in.num_neighbors.eq(rd_port_idx.dat_r[edgeidsize:]), self.get_neighbors.neighbor_in.valid.eq(scatter_msg_valid1), self.get_neighbors.neighbor_in.barrier.eq(scatter_barrier1), self.get_neighbors.neighbor_in.message.eq(scatter_msg1), self.get_neighbors.neighbor_in.sender.eq(scatter_sender1), self.get_neighbors.neighbor_in.round.eq(scatter_round1), upstream_ack.eq(self.get_neighbors.neighbor_in.ack) ] ## stage 3 # user modification based on edge data self.submodules.scatterkernel = config.scatterkernel(config) self.submodules.neighbor_out_fifo = InterfaceFIFO(layout=self.get_neighbors.neighbor_out.layout+([("edgedata", len(self.get_neighbors.edgedata_out), DIR_M_TO_S)] if config.has_edgedata else []), depth=8) self.comb += [ self.get_neighbors.neighbor_out.connect(self.neighbor_out_fifo.din, omit={"valid", "edgedata"}), self.neighbor_out_fifo.din.valid.eq(self.get_neighbors.neighbor_out.valid | self.get_neighbors.neighbor_out.barrier), self.scatterkernel.update_in.raw_bits().eq(self.neighbor_out_fifo.dout.message), self.scatterkernel.num_neighbors_in.eq(self.neighbor_out_fifo.dout.num_neighbors), self.scatterkernel.neighbor_in.eq(self.neighbor_out_fifo.dout.neighbor), self.scatterkernel.sender_in.eq(self.neighbor_out_fifo.dout.sender), self.scatterkernel.round_in.eq(self.neighbor_out_fifo.dout.round), self.scatterkernel.barrier_in.eq(self.neighbor_out_fifo.dout.valid & self.neighbor_out_fifo.dout.barrier), self.scatterkernel.valid_in.eq(self.neighbor_out_fifo.dout.valid & ~self.neighbor_out_fifo.dout.barrier), self.neighbor_out_fifo.dout.ack.eq(self.scatterkernel.ready) ] if config.has_edgedata: self.comb += [ self.neighbor_out_fifo.din.edgedata.eq(self.get_neighbors.edgedata_out), self.scatterkernel.edgedata_in.raw_bits().eq(self.neighbor_out_fifo.dout.edgedata) ] # scatterkernel output self.submodules.barrierdistributor = BarrierDistributor(config) self.submodules.scatterkerneloutfifo = InterfaceFIFO(layout=self.barrierdistributor.network_interface_in.layout, depth=8) self.comb += [ self.scatterkerneloutfifo.din.msg.dest_id.eq(self.scatterkernel.neighbor_out), self.scatterkerneloutfifo.din.msg.payload.eq(self.scatterkernel.message_out.raw_bits()), self.scatterkerneloutfifo.din.msg.sender.eq(self.scatterkernel.sender_out), self.scatterkerneloutfifo.din.msg.roundpar.eq(self.scatterkernel.round_out), self.scatterkerneloutfifo.din.msg.barrier.eq(self.scatterkernel.barrier_out), self.scatterkerneloutfifo.din.dest_pe.eq(addresslayout.pe_adr(self.scatterkernel.neighbor_out)), self.scatterkerneloutfifo.din.valid.eq(self.scatterkernel.valid_out | self.scatterkernel.barrier_out), self.scatterkernel.message_ack.eq(self.scatterkerneloutfifo.din.ack), self.scatterkerneloutfifo.dout.connect(self.barrierdistributor.network_interface_in) ] # buffer output self.submodules.outfifo = InterfaceFIFO(layout=self.network_interface.layout, depth=8) self.comb += [ self.barrierdistributor.network_interface_out.connect(self.outfifo.din), self.outfifo.dout.connect(self.network_interface) ] self.total_num_messages = self.barrierdistributor.total_num_messages