"""Auxiliary controller, common to satellite and master""" from migen import * from migen.fhdl.simplify import FullMemoryWE from migen.genlib.cdc import MultiReg, PulseSynchronizer from misoc.interconnect.csr import * from misoc.interconnect import stream from misoc.interconnect import wishbone max_packet = 1024 class Transmitter(Module, AutoCSR): def __init__(self, link_layer, min_mem_dw): ll_dw = len(link_layer.tx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.aux_tx_length = CSRStorage(bits_for(max_packet), alignment_bits=log2_int(mem_dw//8)) self.aux_tx = CSR() self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = stream.Converter(mem_dw, ll_dw) self.submodules += converter # when continuously fed, the Converter outputs data continuously self.comb += [ converter.source.ack.eq(link_layer.tx_aux_ack), link_layer.tx_aux_frame.eq(converter.source.stb), link_layer.tx_aux_data.eq(converter.source.data) ] seen_eop_rst = Signal() frame_r = Signal() seen_eop = Signal() self.sync += [ If(link_layer.tx_aux_ack, frame_r.eq(link_layer.tx_aux_frame), If(frame_r & ~link_layer.tx_aux_frame, seen_eop.eq(1)) ), If(seen_eop_rst, seen_eop.eq(0)) ] mem_port = self.mem.get_port() self.specials += mem_port frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) frame_counter_next = Signal(frame_counter_nbits) frame_counter_ce = Signal() frame_counter_rst = Signal() self.comb += [ frame_counter_next.eq(frame_counter), If(frame_counter_rst, frame_counter_next.eq(0) ).Elif(frame_counter_ce, frame_counter_next.eq(frame_counter + 1) ), mem_port.adr.eq(frame_counter_next), converter.sink.data.eq(mem_port.dat_r) ] tx_done = Signal() self.sync += [ frame_counter.eq(frame_counter_next), If(self.aux_tx.re, self.aux_tx.w.eq(1)), If(tx_done, self.aux_tx.w.eq(0)) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", frame_counter_rst.eq(1), seen_eop_rst.eq(1), If(self.aux_tx.re, NextState("TRANSMIT")) ) fsm.act("TRANSMIT", converter.sink.stb.eq(1), If(converter.sink.ack, frame_counter_ce.eq(1) ), If(frame_counter_next == self.aux_tx_length.storage, NextState("WAIT_INTERFRAME")) ) fsm.act("WAIT_INTERFRAME", If(seen_eop, tx_done.eq(1), NextState("IDLE") ) ) class Receiver(Module, AutoCSR): def __init__(self, link_layer, min_mem_dw): self.aux_rx_length = CSRStatus(bits_for(max_packet)) self.aux_rx_present = CSR() self.aux_rx_error = CSR() ll_dw = len(link_layer.rx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = ClockDomainsRenamer("rtio_rx")( stream.Converter(ll_dw, mem_dw)) self.submodules += converter # when continuously drained, the Converter accepts data continuously frame_r = Signal() self.sync.rtio_rx += [ If(link_layer.rx_aux_stb, frame_r.eq(link_layer.rx_aux_frame), converter.sink.data.eq(link_layer.rx_aux_data) ) ] self.comb += [ converter.sink.stb.eq(link_layer.rx_aux_stb & frame_r), converter.sink.eop.eq(converter.sink.stb & ~link_layer.rx_aux_frame) ] mem_port = self.mem.get_port(write_capable=True, clock_domain="rtio_rx") self.specials += mem_port frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) self.comb += [ mem_port.adr.eq(frame_counter), mem_port.dat_w.eq(converter.source.data), converter.source.ack.eq(1) ] frame_counter.attr.add("no_retiming") frame_counter_sys = Signal(frame_counter_nbits) self.specials += MultiReg(frame_counter, frame_counter_sys) self.comb += self.aux_rx_length.status.eq(frame_counter_sys << log2_int(mem_dw//8)) signal_frame = PulseSynchronizer("rtio_rx", "sys") frame_ack = PulseSynchronizer("sys", "rtio_rx") signal_error = PulseSynchronizer("rtio_rx", "sys") self.submodules += signal_frame, frame_ack, signal_error self.sync += [ If(self.aux_rx_present.re, self.aux_rx_present.w.eq(0)), If(signal_frame.o, self.aux_rx_present.w.eq(1)), If(self.aux_rx_error.re, self.aux_rx_error.w.eq(0)), If(signal_error.o, self.aux_rx_error.w.eq(1)) ] self.comb += frame_ack.i.eq(self.aux_rx_present.re) fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="IDLE")) self.submodules += fsm sop = Signal(reset=1) self.sync.rtio_rx += \ If(converter.source.stb, If(converter.source.eop, sop.eq(1) ).Else( sop.eq(0) ) ) fsm.act("IDLE", If(converter.source.stb & sop, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(converter.source.eop, NextState("SIGNAL_FRAME") ).Else( NextState("FRAME") ) ).Else( NextValue(frame_counter, 0) ) ) fsm.act("FRAME", If(converter.source.stb, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(frame_counter == max_packet, mem_port.we.eq(0), signal_error.i.eq(1), NextState("IDLE") # discard the rest of the frame ), If(converter.source.eop, NextState("SIGNAL_FRAME") ) ) ) fsm.act("SIGNAL_FRAME", signal_frame.i.eq(1), NextState("WAIT_ACK"), If(converter.source.stb, signal_error.i.eq(1)) ) fsm.act("WAIT_ACK", If(frame_ack.o, NextValue(frame_counter, 0), NextState("IDLE") ), If(converter.source.stb, signal_error.i.eq(1)) ) # TODO: FullMemoryWE should be applied by migen.build @FullMemoryWE() class DRTIOAuxController(Module): def __init__(self, link_layer, dw=32): wsb = log2_int(dw//8) self.bus = wishbone.Interface(data_width=dw, adr_width=32-wsb) self.submodules.transmitter = Transmitter(link_layer, len(self.bus.dat_w)) self.submodules.receiver = Receiver(link_layer, len(self.bus.dat_w)) tx_sdram_if = wishbone.SRAM(self.transmitter.mem, read_only=False, data_width=dw) rx_sdram_if = wishbone.SRAM(self.receiver.mem, read_only=True, data_width=dw) decoder = wishbone.Decoder(self.bus, [(lambda a: a[log2_int(max_packet)-wsb] == 0, tx_sdram_if.bus), (lambda a: a[log2_int(max_packet)-wsb] == 1, rx_sdram_if.bus)], register=True) self.submodules += tx_sdram_if, rx_sdram_if, decoder def get_csrs(self): return self.transmitter.get_csrs() + self.receiver.get_csrs()