def generate_circuit(self): int_priority_encoder = PriorityEncoder(len(self.intrs) + 1) self.submodules += int_priority_encoder for i in range(len(self.intrs)): self.comb += int_priority_encoder.i[i + 1].eq(self.intrs[i]) self.comb += self.intr_number.eq(int_priority_encoder.o) self.comb += self.intr.eq(reduce(or_, [0] + self.intrs))
def __init__(self, config, ext_message_width, num_local_pe): self.send_barrier = Signal() self.send_barrier_ack = Signal() self.receive_barrier = Signal() self.receive_barrier_ack = Signal() self.message_in_data_inside = [Signal(ext_message_width) for _ in range(config.addresslayout.num_ext_ports)] self.message_in_valid_inside = [Signal() for _ in range(config.addresslayout.num_ext_ports)] self.message_in_ack_inside = [Signal() for _ in range(config.addresslayout.num_ext_ports)] self.message_in_data = [Signal(ext_message_width) for _ in range(config.addresslayout.num_ext_ports)] self.message_in_valid = [Signal() for _ in range(config.addresslayout.num_ext_ports)] self.message_in_ack = [Signal() for _ in range(config.addresslayout.num_ext_ports)] self.message_out_data_inside = Signal(ext_message_width * num_local_pe) self.message_out_valid_inside = Signal(num_local_pe) self.message_out_ack_inside = Signal(num_local_pe) self.message_out_data = Signal(ext_message_width * num_local_pe) self.message_out_valid = Signal(num_local_pe) self.message_out_ack = Signal(num_local_pe) barrier_message = NetworkInterface(**config.addresslayout.get_params()) self.comb += [ barrier_message.broadcast.eq(1), barrier_message.valid.eq(1), barrier_message.ack.eq(1) ] self.comb += [ If(self.send_barrier, self.message_out_data.eq(barrier_message.raw_bits()), self.message_out_valid.eq(1), self.send_barrier_ack.eq(self.message_out_ack[0]) ).Else( self.message_out_data.eq(self.message_out_data_inside), self.message_out_valid.eq(self.message_out_valid_inside), self.message_out_ack_inside.eq(self.message_out_ack) ) ] self.submodules.pe = PriorityEncoder(config.addresslayout.num_ext_ports) for port in range(config.addresslayout.num_ext_ports): self.comb += [ self.pe.i[port].eq((self.message_in_data[port] == barrier_message.raw_bits()) & self.message_in_valid[port]), If(self.pe.i[port], self.receive_barrier.eq((self.pe.o == port)), self.message_in_ack[port].eq(self.receive_barrier_ack & (self.pe.o == port)) ).Else( self.message_in_data_inside[port].eq(self.message_in_data[port]), self.message_in_valid_inside[port].eq(self.message_in_valid[port]), self.message_in_ack[port].eq(self.message_in_ack_inside[port]) ) ]
def __init__(self, serdes): serdes_width = len(serdes.o) assert len(serdes.i) == serdes_width self.rtlink = rtlink.Interface( rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)), rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width))) self.probes = [serdes.i[-1], serdes.oe] override_en = Signal() override_o = Signal() override_oe = Signal() self.overrides = [override_en, override_o, override_oe] # # # # Output self.submodules += _SerdesDriver(serdes_o=serdes.o, stb=self.rtlink.o.stb & (self.rtlink.o.address == 0), data=self.rtlink.o.data[0], fine_ts=self.rtlink.o.fine_ts, override_en=override_en, override_o=override_o) oe_k = Signal() self.sync.rio_phy += [ If(self.rtlink.o.stb & (self.rtlink.o.address == 1), oe_k.eq(self.rtlink.o.data[0])), If(override_en, serdes.oe.eq(override_oe)).Else(serdes.oe.eq(oe_k)) ] # Input sensitivity = Signal(2) sample = Signal() self.sync.rio += [ sample.eq(0), If(self.rtlink.o.stb & self.rtlink.o.address[1], sensitivity.eq(self.rtlink.o.data), If(self.rtlink.o.address[0], sample.eq(1))) ] i = serdes.i[-1] i_d = Signal() self.sync.rio_phy += [ i_d.eq(i), self.rtlink.i.stb.eq(sample | (sensitivity[0] & (i & ~i_d)) | (sensitivity[1] & (~i & i_d))), self.rtlink.i.data.eq(i), ] pe = PriorityEncoder(serdes_width) self.submodules += pe self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width)) self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o)
def __init__(self): self.latency = 50 self.dividend_i = Signal(32) self.divisor_i = Signal(32) self.valid_i = Signal() self.quotient_o = Signal(32) self.valid_o = Signal() ### dividend_sign = Signal() dividend_expn = Signal(8) dividend_mant = Signal(24) self.comb += [ dividend_sign.eq(self.dividend_i[31]), dividend_expn.eq(self.dividend_i[23:31]), dividend_mant.eq(Cat(self.dividend_i[0:23], 1)) ] # divide mantissa, add 24 bits of precision to be sure we have at least 24 left over w = 48 self.submodules.div = Divider(w) self.comb += [ self.div.dividend_i[:-24].eq(0), self.div.dividend_i[-24:].eq(dividend_mant), self.div.divisor_i.eq(self.divisor_i), self.div.valid_i.eq(self.valid_i) ] # keep exponent and sign for the duration of division (49 cycles...) expn = [Signal(8) for _ in range(w + 1)] sign = [Signal() for _ in range(w + 1)] self.sync += [expn[0].eq(dividend_expn), sign[0].eq(dividend_sign)] self.sync += [expn[i + 1].eq(expn[i]) for i in range(w)] self.sync += [sign[i + 1].eq(sign[i]) for i in range(w)] # shift mantissa and subtract shift from exponent pe = PriorityEncoder(w) self.submodules += pe self.comb += [pe.i.eq(self.div.quotient_o[::-1])] quotient_o_sign = Signal() quotient_o_expn = Signal(8) quotient_o_mant = Signal(48) self.sync += [ quotient_o_sign.eq(sign[-1]), If(expn[-1] != 0, quotient_o_expn.eq(expn[-1] - pe.o), quotient_o_mant.eq(self.div.quotient_o << pe.o)).Else( quotient_o_expn.eq(0), quotient_o_mant.eq(self.div.quotient_o)), self.valid_o.eq(self.div.valid_o) ] self.comb += [ self.quotient_o[31].eq(quotient_o_sign), self.quotient_o[23:31].eq(quotient_o_expn), self.quotient_o[0:23].eq(quotient_o_mant[-24:-1]) ]
def __init__(self, pads, pads_n=None, cdmap=None): super(HiresGpio, self).__init__() self.sys8_stb = Signal(4) ### n = flen(pads) i0 = Signal(n) i = Signal(n) o = Signal(n) b = Signal(n) o0 = Signal(n) oe = Signal(n) r = Signal(n) f = Signal(n) ti = Signal(3) to = Signal(3) j = Signal() k = Signal() sys2_stb = Signal() self.sync += j.eq(~j) self.sync.sys2 += k.eq(j), sys2_stb.eq(k == j) # dout edges = Array([0xff ^ ((1 << i) - 1) for i in range(8)]) edge_out = Signal(8) edge_out_n = Signal(8) rise_out = Signal(n) fall_out = Signal(n) self.comb += [ edge_out.eq(edges[to]), edge_out_n.eq(~edge_out), rise_out.eq(~o0 & o), fall_out.eq(o0 & ~o), ] ios = [] for j in range(n): io = IOSerdes(pads[j], pads_n[j] if pads_n else None) cdj = cdmap[j] if cdmap else 0 io = RenameClockDomains(io, {"sys8": "sys8%i" % cdj}) self.submodules += io ios.append(io) self.comb += io.sys8_stb.eq(self.sys8_stb[cdj]) self.comb += io.sys2_stb.eq(sys2_stb) self.comb += [ # 0 cycle io.oe.eq(Replicate(oe[j], 8)), If( rise_out[j], io.o.eq(edge_out), ).Elif( fall_out[j], io.o.eq(edge_out_n), ).Else(io.o.eq(Replicate(o[j], 8)), ) ] # din self.submodules.pe_ti = pe_ti = PriorityEncoder(8) self.submodules.pe_sel = pe_sel = PriorityEncoder(n) rise_in = Signal(n) fall_in = Signal(n) edge_in = Signal(8) bi = Signal() i0i = Signal() self.comb += [ i.eq(Cat(io.i[-1] for io in ios) ^ b), rise_in.eq((~i0 & r) & i), fall_in.eq((i0 & f) & ~i), pe_sel.i.eq(rise_in | fall_in), i0i.eq(Array(fiter(i0))[pe_sel.o]), bi.eq(Array(fiter(b))[pe_sel.o]), edge_in.eq(Array([io.i for io in ios])[pe_sel.o]), pe_ti.i.eq(edge_in ^ Replicate(i0i ^ bi, 8)), ti.eq(pe_ti.o), ] # ventilator bus self.comb += [ self.dout.ack.eq(1), self.busy.eq(self.din.stb & ~self.din.ack), ] self.sync += [ # 1 cycle each If( self.din.stb & self.din.ack, self.din.stb.eq(0), ), If( self.dout.stb, to.eq(self.dout.payload.addr[4:]), self.din.payload.addr.eq(0), Case( self.dout.payload.addr[:4], { 0x0: [self.din.stb.eq(1), self.din.payload.data.eq(i)], 0x1: [o.eq(self.dout.payload.data ^ b), o0.eq(o)], 0x2: oe.eq(self.dout.payload.data), 0x3: r.eq(self.dout.payload.data), 0x4: f.eq(self.dout.payload.data), 0x5: b.eq(self.dout.payload.data), }), ), If( ~(self.dout.stb & (self.dout.payload.addr[:4] == 0)) & ~(self.din.stb & ~self.din.ack), i0.eq(i), If( ~pe_sel.n, self.din.stb.eq(1), self.din.payload.addr[4:].eq(ti), self.din.payload.addr[:4].eq(Mux(~i0i, 0x6, 0x7)), self.din.payload.data.eq(Mux(~i0i, rise_in, fall_in)), ), ) ]
def do_finalize(self): assert len(self.event_sources) < 2**6 assert max(s.width for s in self.event_sources) <= 32 # Fill the event, event data, and delay FIFOs. throttle_on = Signal() throttle_off = Signal() throttle_edge = Signal() throttle_fifos = [] self.sync += [ If(~self.throttle & throttle_on, self.throttle.eq(1), throttle_edge.eq(1)).Elif(self.throttle & throttle_off, self.throttle.eq(0), throttle_edge.eq(1)).Else( throttle_edge.eq(0)) ] event_width = 1 + len(self.event_sources) if self.event_depth is None: event_depth = min(self._depth_for_width(event_width), self._depth_for_width(self.delay_width)) else: event_depth = self.event_depth self.submodules.event_fifo = event_fifo = \ SyncFIFOBuffered(width=event_width, depth=event_depth) throttle_fifos.append(self.event_fifo) self.comb += [ event_fifo.din.eq( Cat(self.throttle, [s.trigger for s in self.event_sources])), event_fifo.we.eq( reduce(lambda a, b: a | b, (s.trigger for s in self.event_sources)) | throttle_edge) ] self.submodules.delay_fifo = delay_fifo = \ SyncFIFOBuffered(width=self.delay_width, depth=event_depth) delay_timer = self._delay_timer = Signal(self.delay_width) self.sync += [ If(delay_fifo.we, delay_timer.eq(0)).Else(delay_timer.eq(delay_timer + 1)) ] self.comb += [ delay_fifo.din.eq(delay_timer), delay_fifo.we.eq(event_fifo.we | (delay_timer == ((1 << self.delay_width) - 1)) | self.done), ] for event_source in self.event_sources: if event_source.width > 0: event_source.submodules.data_fifo = event_data_fifo = \ SyncFIFOBuffered(event_source.width, event_source.depth) self.submodules += event_source throttle_fifos.append(event_data_fifo) self.comb += [ event_data_fifo.din.eq(event_source.data), event_data_fifo.we.eq(event_source.trigger), ] else: event_source.submodules.data_fifo = _FIFOInterface(1, 0) # Throttle applets based on FIFO levels with hysteresis. self.comb += [ throttle_on.eq( reduce(lambda a, b: a | b, (f.fifo.level >= f.depth - f.depth // (4 if f.depth > 4 else 2) for f in throttle_fifos))), throttle_off.eq( reduce(lambda a, b: a & b, (f.fifo.level < f.depth // (4 if f.depth > 4 else 2) for f in throttle_fifos))), ] # Dequeue events, and serialize events and event data. self.submodules.event_encoder = event_encoder = \ PriorityEncoder(width=len(self.event_sources)) self.submodules.event_decoder = event_decoder = \ PriorityDecoder(width=len(self.event_sources)) self.comb += event_decoder.i.eq(event_encoder.o) self.submodules.serializer = serializer = FSM(reset_state="WAIT-EVENT") rep_throttle_new = Signal() rep_throttle_cur = Signal() delay_septets = 5 delay_counter = Signal(7 * delay_septets) serializer.act( "WAIT-EVENT", If( delay_fifo.readable, delay_fifo.re.eq(1), NextValue(delay_counter, delay_counter + delay_fifo.dout + 1), ), If( event_fifo.readable, event_fifo.re.eq(1), NextValue(event_encoder.i, event_fifo.dout[1:]), NextValue(rep_throttle_new, event_fifo.dout[0]), If((event_fifo.dout != 0) | (rep_throttle_cur != event_fifo.dout[0]), NextState("REPORT-DELAY"))).Elif(self.done, NextState("REPORT-DELAY"))) serializer.act( "REPORT-DELAY", If(delay_counter >= 128**4, NextState("REPORT-DELAY-5")).Elif( delay_counter >= 128**3, NextState("REPORT-DELAY-4")).Elif( delay_counter >= 128**2, NextState("REPORT-DELAY-3")).Elif( delay_counter >= 128**1, NextState("REPORT-DELAY-2")).Else( NextState("REPORT-DELAY-1"))) for septet_no in range(delay_septets, 0, -1): if septet_no == 1: next_state = [ NextValue(delay_counter, 0), If(rep_throttle_cur != rep_throttle_new, NextState("REPORT-THROTTLE")).Elif( event_encoder.i, NextState("REPORT-EVENT")).Elif( self.done, NextState("REPORT-DONE")).Else( NextState("WAIT-EVENT")) ] else: next_state = [NextState("REPORT-DELAY-%d" % (septet_no - 1))] serializer.act( "REPORT-DELAY-%d" % septet_no, If( self.output_fifo.writable, self.output_fifo.din.eq(REPORT_DELAY | delay_counter.part( (septet_no - 1) * 7, 7)), self.output_fifo.we.eq(1), *next_state)) serializer.act( "REPORT-THROTTLE", If( self.output_fifo.writable, NextValue(rep_throttle_cur, rep_throttle_new), If( rep_throttle_new, self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_THROTTLE), ).Else( self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_DETHROTTLE), ), self.output_fifo.we.eq(1), If(event_encoder.n, NextState("WAIT-EVENT")).Else(NextState("REPORT-EVENT")))) event_source = self.event_sources[event_encoder.o] event_data = Signal(32) serializer.act( "REPORT-EVENT", If( self.output_fifo.writable, NextValue(event_encoder.i, event_encoder.i & ~event_decoder.o), self.output_fifo.din.eq(REPORT_EVENT | event_encoder.o), self.output_fifo.we.eq(1), NextValue(event_data, event_source.data_fifo.dout), event_source.data_fifo.re.eq(1), If(event_source.width > 24, NextState("REPORT-EVENT-DATA-4")).Elif( event_source.width > 16, NextState("REPORT-EVENT-DATA-3")).Elif( event_source.width > 8, NextState("REPORT-EVENT-DATA-2")).Elif( event_source.width > 0, NextState("REPORT-EVENT-DATA-1")).Else( If(event_encoder.i & ~event_decoder.o, NextState("REPORT-EVENT")).Else( NextState("WAIT-EVENT"))))) for octet_no in range(4, 0, -1): if octet_no == 1: next_state = [ If(event_encoder.n, NextState("WAIT-EVENT")).Else(NextState("REPORT-EVENT")) ] else: next_state = [ NextState("REPORT-EVENT-DATA-%d" % (octet_no - 1)) ] serializer.act( "REPORT-EVENT-DATA-%d" % octet_no, If( self.output_fifo.writable, self.output_fifo.din.eq( event_data.part((octet_no - 1) * 8, 8)), self.output_fifo.we.eq(1), *next_state)) serializer.act( "REPORT-DONE", If(self.output_fifo.writable, self.output_fifo.din.eq(REPORT_SPECIAL | SPECIAL_DONE), self.output_fifo.we.eq(1), NextState("DONE"))) serializer.act("DONE", If(~self.done, NextState("WAIT-EVENT")))
def __init__(self, config): self.config = config self.submodules.cores = [ Core( config, i * config.addresslayout.num_pe_per_fpga, min((i + 1) * config.addresslayout.num_pe_per_fpga, config.addresslayout.num_pe)) for i in range(config.addresslayout.num_fpga) ] self.global_inactive = Signal() self.comb += self.global_inactive.eq( reduce(and_, [core.global_inactive for core in self.cores])) self.submodules.adrlook_sender = AddressLookup(config) broadcast = Signal() broadcast_port = Signal(max=max(2, config.addresslayout.num_ext_ports)) got_ack = Signal(config.addresslayout.num_ext_ports * config.addresslayout.num_fpga) all_ack = Signal() self.submodules.fifo = [ InterfaceFIFO(layout=self.cores[0].network. external_network_interface_out[port].layout, depth=8) for port in range(config.addresslayout.num_ext_ports) ] for port in range(config.addresslayout.num_ext_ports): ext_msg_channel_out = Array( core.network.external_network_interface_out[port].msg.raw_bits( ) for core in self.cores) ext_dest_pe_channel_out = Array( core.network.external_network_interface_out[port].dest_pe for core in self.cores) ext_valid_channel_out = Array( core.network.external_network_interface_out[port].valid for core in self.cores) ext_ack_channel_out = Array( core.network.external_network_interface_out[port].ack for core in self.cores) ext_broadcast_channel_out = Array( core.network.external_network_interface_out[port].broadcast for core in self.cores) ext_ack_channel_in = Array( core.network.external_network_interface_in[port].ack for core in self.cores) roundrobin = RoundRobin(config.addresslayout.num_fpga, switch_policy=SP_CE) self.submodules += roundrobin adrlook = AddressLookup(config) self.submodules += adrlook self.comb += [ [ roundrobin.request[i].eq(ext_valid_channel_out[i]) for i in range(config.addresslayout.num_fpga) ], roundrobin.ce.eq(1), self.fifo[port].din.msg.raw_bits().eq( ext_msg_channel_out[roundrobin.grant]), self.fifo[port].din.dest_pe.eq( ext_dest_pe_channel_out[roundrobin.grant]), self.fifo[port].din.broadcast.eq( ext_broadcast_channel_out[roundrobin.grant]), self.fifo[port].din.valid.eq( ext_valid_channel_out[roundrobin.grant]), ext_ack_channel_out[roundrobin.grant].eq( self.fifo[port].din.ack), ] self.comb += [ adrlook.pe_adr_in.eq(self.fifo[port].dout.dest_pe), [ core.network.external_network_interface_in[port].msg. raw_bits().eq(self.fifo[port].dout.msg.raw_bits()) for core in self.cores ], [ core.network.external_network_interface_in[port].dest_pe. eq(self.fifo[port].dout.dest_pe) for core in self.cores ], [ core.network.external_network_interface_in[port].broadcast. eq(broadcast) for core in self.cores ], [ self.cores[i].network.external_network_interface_in[port]. valid.eq( (~broadcast & self.fifo[port].dout.valid & (adrlook.fpga_out == i)) | (broadcast & ~((self.adrlook_sender.fpga_out == i) & (broadcast_port == port)) & ~got_ack[i * config.addresslayout.num_ext_ports + port])) for i in range(config.addresslayout.num_fpga) ], self.fifo[port].dout.ack.eq( (~broadcast & ext_ack_channel_in[adrlook.fpga_out]) | (broadcast & (port == broadcast_port) & all_ack)) ] self.submodules.priorityencoder = PriorityEncoder( config.addresslayout.num_ext_ports) array_sender = Array( self.fifo[port].dout.msg.sender for port in range(config.addresslayout.num_ext_ports)) self.comb += [ self.priorityencoder.i[port].eq(self.fifo[port].dout.broadcast & self.fifo[port].dout.valid) for port in range(config.addresslayout.num_ext_ports) ] self.comb += [ self.adrlook_sender.pe_adr_in.eq(array_sender[broadcast_port]), broadcast.eq(~self.priorityencoder.n), broadcast_port.eq(self.priorityencoder.o) ] self.sync += [ If( broadcast, If(all_ack, got_ack.eq(0)).Else([ got_ack[i * config.addresslayout.num_ext_ports + port].eq( got_ack[i * config.addresslayout.num_ext_ports + port] | self.cores[i].network. external_network_interface_in[port].ack) for i in range(config.addresslayout.num_fpga) for port in range(config.addresslayout.num_ext_ports) ])) ] self.comb += [ all_ack.eq( reduce(and_, [ got_ack[i * config.addresslayout.num_ext_ports + port] | ((self.adrlook_sender.fpga_out == i) & (port == broadcast_port)) for i in range(config.addresslayout.num_fpga) for port in range(config.addresslayout.num_ext_ports) ])), ] self.start = Signal() self.done = Signal() self.cycle_count = Signal(64) self.comb += [[core.start.eq(self.start) for core in self.cores], self.done.eq( reduce(and_, [core.done for core in self.cores])), self.cycle_count.eq(self.cores[0].cycle_count)]
def __init__(self, serdes): serdes_width = len(serdes.o) assert len(serdes.i) == serdes_width self.rtlink = rtlink.Interface( rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)), rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width))) self.probes = [serdes.i[-1], serdes.oe] override_en = Signal() override_o = Signal() override_oe = Signal() self.overrides = [override_en, override_o, override_oe] # Output enable, for interfacing to external buffers. self.oe = Signal() # input state exposed for edge_counter: latest serdes sample # support for short pulses will need a more involved solution self.input_state = Signal() # # # # Output self.submodules += _SerdesDriver(serdes_o=serdes.o, stb=self.rtlink.o.stb & (self.rtlink.o.address == 0), data=self.rtlink.o.data[0], fine_ts=self.rtlink.o.fine_ts, override_en=override_en, override_o=override_o) oe_k = Signal() self.oe.attr.add("no_retiming") self.sync.rio_phy += [ If(self.rtlink.o.stb & (self.rtlink.o.address == 1), oe_k.eq(self.rtlink.o.data[0])), If(override_en, self.oe.eq(override_oe)).Else(self.oe.eq(oe_k)) ] self.comb += serdes.oe.eq(self.oe) # Input sensitivity = Signal(2) sample = Signal() self.sync.rio += [ sample.eq(0), If(self.rtlink.o.stb & self.rtlink.o.address[1], sensitivity.eq(self.rtlink.o.data), If(self.rtlink.o.address[0], sample.eq(1))) ] i = serdes.i[-1] self.comb += self.input_state.eq(i) i_d = Signal() self.sync.rio_phy += [ i_d.eq(i), self.rtlink.i.data.eq(i), ] pe = PriorityEncoder(serdes_width) self.submodules += pe self.comb += pe.i.eq((serdes.i ^ Cat(i_d, serdes.i)) & ( (serdes.i & Replicate(sensitivity[0], serdes_width)) | (~serdes.i & Replicate(sensitivity[1], serdes_width)))) self.sync.rio_phy += [ self.rtlink.i.fine_ts.eq(pe.o), self.rtlink.i.stb.eq(sample | ~pe.n), ]
def __init__(self, slaves, depth=256, bus=None, with_wishbone=True): time_width, addr_width, data_width = [_[1] for _ in ventilator_layout] self.submodules.ctrl = CycleControl() self.submodules.ev = ev = EventManager() ev.in_readable = EventSourceLevel() ev.out_overflow = EventSourceProcess() ev.in_overflow = EventSourceLevel() ev.out_readable = EventSourceProcess() ev.stopped = EventSourceProcess() ev.started = EventSourceProcess() ev.finalize() self._in_time = CSRStatus(time_width) self._in_addr = CSRStatus(addr_width) self._in_data = CSRStatus(data_width) self._in_next = CSR() self._in_flush = CSR() self._out_time = CSRStorage(time_width, write_from_dev=with_wishbone) self._out_addr = CSRStorage(addr_width, write_from_dev=with_wishbone) self._out_data = CSRStorage(data_width, write_from_dev=with_wishbone) self._out_next = CSR() self._out_flush = CSR() self.busy = Signal() ### if with_wishbone: if bus is None: bus = wishbone.Interface() self.bus = bus slaves = [(self.ctrl, 0x00000000, 0xffffff00)] + slaves self.submodules.in_fifo = in_fifo = SyncFIFOBuffered( ventilator_layout, depth) self.submodules.out_fifo = out_fifo = SyncFIFOBuffered( ventilator_layout, depth) self.submodules.enc = PriorityEncoder(len(slaves)) wb_in_next = Signal() wb_out_next = Signal() out_request = Signal() in_request = Signal() # CSRs and Events self.comb += [ ev.in_readable.trigger.eq(in_fifo.readable), ev.out_overflow.trigger.eq(~out_fifo.writable), ev.in_overflow.trigger.eq(~in_fifo.writable), ev.out_readable.trigger.eq(out_fifo.readable), ev.started.trigger.eq(~self.ctrl.run), ev.stopped.trigger.eq(self.ctrl.run), self.ctrl.have_in.eq(~self.enc.n), self.ctrl.have_out.eq(out_fifo.readable), self._in_time.status.eq(in_fifo.dout.time), self._in_addr.status.eq(in_fifo.dout.addr), self._in_data.status.eq(in_fifo.dout.data), in_fifo.re.eq(self._in_next.re | wb_in_next), in_fifo.flush.eq(self._in_flush.re), out_fifo.din.time.eq(self._out_time.storage), out_fifo.din.addr.eq(self._out_addr.storage), out_fifo.din.data.eq(self._out_data.storage), out_fifo.we.eq(self._out_next.re | wb_out_next), out_fifo.flush.eq(self._out_flush.re), ] # din dout strobing self.comb += [ # TODO: 0 <= diff <= plausibility range out_request.eq(out_fifo.readable & self.ctrl.run & (self.ctrl.cycle == out_fifo.dout.time)), # ignore in_fifo.writable in_request.eq(~self.enc.n & self.ctrl.run), self.busy.eq(out_request | in_request), ] # to slaves addrs = [] datas = [] stbs = [] acks = [] for i, (slave, prefix, mask) in enumerate(slaves): prefix &= mask source = Source(slave_layout) sink = Sink(slave_layout) self.comb += [ source.connect(slave.dout), sink.connect(slave.din), ] sel = Signal() acks.append(sel & source.ack) addrs.append(prefix | (sink.payload.addr & (~mask & 0xffffffff))) datas.append(sink.payload.data) stbs.append(sink.stb) self.comb += [ sel.eq(out_fifo.dout.addr & mask == prefix), source.payload.addr.eq(out_fifo.dout.addr), source.payload.data.eq(out_fifo.dout.data), source.stb.eq(sel & out_request), sink.ack.eq((self.enc.o == i) & in_request), ] self.comb += out_fifo.re.eq(out_request & optree("|", acks)) # from slaves self.comb += [ self.enc.i.eq(Cat(stbs)), in_fifo.din.time.eq(self.ctrl.cycle), in_fifo.din.addr.eq(Array(addrs)[self.enc.o]), in_fifo.din.data.eq(Array(datas)[self.enc.o]), in_fifo.we.eq(in_request), ] # optional high throughput wishbone access if with_wishbone: self.comb += [ self._out_time.dat_w.eq(bus.dat_w), self._out_addr.dat_w.eq(bus.dat_w), self._out_data.dat_w.eq(bus.dat_w), If( bus.cyc & bus.stb, If( bus.we, Case( bus.adr[:4], { 0x5: wb_in_next.eq(1), 0x6: self._out_time.we.eq(1), 0x7: self._out_addr.we.eq(1), 0x8: self._out_data.we.eq(1), 0x9: wb_out_next.eq(1), }), ), Case( bus.adr[:4], { 0x0: bus.dat_r.eq(self.ctrl.cycle), 0x1: bus.dat_r.eq(self.ev.status.w), 0x2: bus.dat_r.eq(in_fifo.dout.time), 0x3: bus.dat_r.eq(in_fifo.dout.addr), 0x4: bus.dat_r.eq(in_fifo.dout.data), }), ) ] self.sync += bus.ack.eq(bus.cyc & bus.stb & ~bus.ack)
def __init__(self, l0_trigger_generators, outputs, l0_num=16, l1_num=16, l1_extra=[], trigger_counter_len=4, module_identifier="trigger_controller", with_ila=False): self.module_identifier = module_identifier self.trigger_counter_len = trigger_counter_len self.trigger_id_len = len(Signal(max=max(l1_num, 2))) assert self.trigger_id_len + trigger_counter_len <= 8 # Trigger counter reset self.trigger_controller_reset = Signal() phy = Output(self.trigger_controller_reset) self.submodules.reset_phy = phy self.add_rtio_channels( channel=Channel.from_phy(phy), device_id=f"{module_identifier}_trigger_controller_reset", module="artiq.coredevice.ttl", class_name="TTLOut") # Output config CSR l1_extra_triggers_num = sum([len(m.triggers) for m in l1_extra]) l1_total_num = l1_num+l1_extra_triggers_num # FIXME: Add support for long RTIO output assert l1_total_num <= 32 regs = [ ("{}_l1_mask".format(output['label']), l1_total_num) for output in outputs ] output_config_phy = RtLinkCSR(regs, "output_config", f"{module_identifier}_output_config") self.submodules.output_config = output_config_phy # Layer 0 self.l0_coincidence_modules = l0_coincidence_modules = [] for idx in range(l0_num): l0_module = RtioCoincidenceTriggerGenerator( name=f"l0_{idx}", generators=l0_trigger_generators, reset_pulse_length=50, pulse_max_length=255) l0_coincidence_modules.append(l0_module) setattr(self.submodules, f"module_l0_{idx}", l0_module) self.add_rtio_channels( channel=Channel.from_phy(l0_module), device_id=f"{module_identifier}_l0_{idx}", module="mcord_daq.coredevice.wrappers", class_name="RtioCoincidenceTriggerGeneratorWrapper", arguments={ "mask_mapping": l0_module.get_mask_mapping(), "identifier": f"{module_identifier}_l0_{idx}" }) trigger_lines = [] trigger_counters = [] trigger_labels = [] self.l1_coincidence_modules = l1_coincidence_modules = [] for idx in range(l1_num): # L1 coincidence module l1_module = RtioCoincidenceTriggerGenerator( name=f"l1_{idx}", generators=l0_coincidence_modules, reset_pulse_length=50, pulse_max_length=255) l1_coincidence_modules.append(l1_module) setattr(self.submodules, f"module_l1_{idx}", l1_module) self.add_rtio_channels( channel=Channel.from_phy(l1_module), device_id=f"{module_identifier}_l1_{idx}", module="mcord_daq.coredevice.wrappers", class_name="RtioCoincidenceTriggerGeneratorWrapper", arguments={ "mask_mapping": l1_module.get_mask_mapping(), "identifier": f"{module_identifier}_l1_{idx}" }) trigger, trigger_counter = self._add_l1_output( l1_module.trigger, f"{module_identifier}_l1_{idx}") trigger_lines += [trigger] trigger_counters += [trigger_counter] trigger_labels += [f"l1_{idx}"] for module in l1_extra: for mod_trig in module.triggers: assert mod_trig['cd'] == "rio_phy" label = mod_trig['label'] trigger, trigger_counter = self._add_l1_output( mod_trig['signal'], f"{module_identifier}_l1_{label}") trigger_lines.append(trigger) trigger_counters.append(trigger_counter) trigger_labels += [label] # Output logic trigger_lines_array = Array(trigger_lines) trigger_counters_array = Array(trigger_counters) for output in outputs: l1_mask = getattr(output_config_phy, "{}_l1_mask".format(output['label'])) trigger_lines_vector = Cat(trigger_lines) trigger_lines_masked = Signal.like(trigger_lines_vector) self.comb += trigger_lines_masked.eq(l1_mask & trigger_lines_vector) output_select = Signal(max=max(len(trigger_lines), 2)) priority_encoder = PriorityEncoder(len(trigger_lines_masked)) self.submodules += priority_encoder self.comb += [ priority_encoder.i.eq(trigger_lines_masked), output_select.eq(priority_encoder.o), ] self.sync.rio_phy += [ output['trigger'].eq(0), If(trigger_lines_array[output_select] & ~priority_encoder.n, output['trigger'].eq(trigger_lines_array[output_select]), output['trigger_id'].eq(Cat(priority_encoder.o, trigger_counters_array[output_select])), ) ] # Register core device self.register_coredevice(module_identifier, "mcord_daq.coredevice.trigger_controller", "TriggerController", arguments={ "prefix": module_identifier, "l0_num": l0_num, "l1_num": l1_num, "output_config_csr": f"{module_identifier}_output_config", "l1_mask": trigger_labels, "reset_device": f"{module_identifier}_trigger_controller_reset" }) if with_ila: for t, l, p in zip(self.l0_coincidence_modules[0].trigger_in_signals, self.l0_coincidence_modules[0].trigger_in_labels, self.l0_coincidence_modules[0].pulses): self.submodules += [ ILAProbe(t, f"dbg_{l}_trig"), ILAProbe(p, f"dbg_{l}_pulse") ] self.submodules += [ILAProbe(self.l0_coincidence_modules[0].pulse_length, "l0_0_pulse_length")] for idx, mod in enumerate(l0_coincidence_modules): self.submodules += [ILAProbe(mod.trigger, f"l0_trigger_{idx}")] for idx, mod in enumerate(l1_coincidence_modules): self.submodules += [ILAProbe(mod.trigger, f"l1_trigger_{idx}")] for idx, mod in enumerate(l1_extra): self.submodules += [ILAProbe(t['signal'], "l1_extra_{}".format(t['label'])) for t in mod.triggers] for output in outputs: self.submodules += [ ILAProbe(output['trigger'], "output_trigger_{}".format(output['label'])), ILAProbe(output['trigger_id'], "output_trigger_id_{}".format(output['label'])) ]