forked from M-Labs/artiq
aux_controller: multiple receiver buffers
This commit is contained in:
parent
76d704ac33
commit
b6ac052e9f
|
@ -10,6 +10,7 @@ from misoc.interconnect import wishbone
|
||||||
|
|
||||||
|
|
||||||
max_packet = 1024
|
max_packet = 1024
|
||||||
|
aux_buffer_count = 8
|
||||||
|
|
||||||
|
|
||||||
class Transmitter(Module, AutoCSR):
|
class Transmitter(Module, AutoCSR):
|
||||||
|
@ -95,13 +96,13 @@ class Transmitter(Module, AutoCSR):
|
||||||
|
|
||||||
class Receiver(Module, AutoCSR):
|
class Receiver(Module, AutoCSR):
|
||||||
def __init__(self, link_layer, min_mem_dw):
|
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_present = CSR()
|
||||||
self.aux_rx_error = CSR()
|
self.aux_rx_error = CSR()
|
||||||
|
self.aux_read_pointer = CSR(log2_int(aux_buffer_count))
|
||||||
|
|
||||||
ll_dw = len(link_layer.rx_aux_data)
|
ll_dw = len(link_layer.rx_aux_data)
|
||||||
mem_dw = max(min_mem_dw, ll_dw)
|
mem_dw = max(min_mem_dw, ll_dw)
|
||||||
self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8))
|
self.specials.mem = Memory(mem_dw, aux_buffer_count*max_packet//(mem_dw//8))
|
||||||
|
|
||||||
converter = ClockDomainsRenamer("rtio_rx")(
|
converter = ClockDomainsRenamer("rtio_rx")(
|
||||||
stream.Converter(ll_dw, mem_dw))
|
stream.Converter(ll_dw, mem_dw))
|
||||||
|
@ -123,30 +124,45 @@ class Receiver(Module, AutoCSR):
|
||||||
mem_port = self.mem.get_port(write_capable=True, clock_domain="rtio_rx")
|
mem_port = self.mem.get_port(write_capable=True, clock_domain="rtio_rx")
|
||||||
self.specials += mem_port
|
self.specials += mem_port
|
||||||
|
|
||||||
|
# write pointer represents where the gateware is
|
||||||
|
write_pointer = Signal(log2_int(aux_buffer_count))
|
||||||
|
write_pointer_sys = Signal.like(write_pointer)
|
||||||
|
# read pointer represents where CPU is
|
||||||
|
# write reaching read is an error, read reaching write is buffer clear
|
||||||
|
read_pointer = Signal.like(write_pointer)
|
||||||
|
read_pointer_rx = Signal.like(write_pointer)
|
||||||
|
|
||||||
|
read_pointer.attr.add("no_retiming")
|
||||||
|
write_pointer.attr.add("no_retiming")
|
||||||
|
signal_error = PulseSynchronizer("rtio_rx", "sys")
|
||||||
|
|
||||||
|
self.specials += [
|
||||||
|
MultiReg(read_pointer, read_pointer_rx, "rtio_rx"),
|
||||||
|
MultiReg(write_pointer, write_pointer_sys)
|
||||||
|
]
|
||||||
|
|
||||||
frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8)
|
frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8)
|
||||||
frame_counter = Signal(frame_counter_nbits)
|
frame_counter = Signal(frame_counter_nbits)
|
||||||
|
# frame counter requires one more bit to represent overflow (bits_for)
|
||||||
|
# actual valid packet will be addressed with one bit less
|
||||||
|
packet_nbits = frame_counter_nbits - 1
|
||||||
self.comb += [
|
self.comb += [
|
||||||
mem_port.adr.eq(frame_counter),
|
mem_port.adr[:packet_nbits].eq(frame_counter),
|
||||||
|
# bits above the frame counter point to current frame
|
||||||
|
mem_port.adr[packet_nbits:].eq(write_pointer),
|
||||||
mem_port.dat_w.eq(converter.source.data),
|
mem_port.dat_w.eq(converter.source.data),
|
||||||
converter.source.ack.eq(1)
|
converter.source.ack.eq(1),
|
||||||
|
self.aux_read_pointer.w.eq(read_pointer)
|
||||||
]
|
]
|
||||||
|
|
||||||
frame_counter.attr.add("no_retiming")
|
self.submodules += signal_error
|
||||||
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 += [
|
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(self.aux_rx_error.re, self.aux_rx_error.w.eq(0)),
|
||||||
If(signal_error.o, self.aux_rx_error.w.eq(1))
|
If(signal_error.o, self.aux_rx_error.w.eq(1)),
|
||||||
|
self.aux_rx_present.w.eq(~(read_pointer == write_pointer_sys)),
|
||||||
|
If(self.aux_rx_present.re & self.aux_rx_present.w,
|
||||||
|
read_pointer.eq(read_pointer + 1)),
|
||||||
]
|
]
|
||||||
self.comb += frame_ack.i.eq(self.aux_rx_present.re)
|
|
||||||
|
|
||||||
fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="IDLE"))
|
fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="IDLE"))
|
||||||
self.submodules += fsm
|
self.submodules += fsm
|
||||||
|
@ -171,7 +187,7 @@ class Receiver(Module, AutoCSR):
|
||||||
NextState("FRAME")
|
NextState("FRAME")
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
NextValue(frame_counter, 0)
|
NextValue(frame_counter, 0),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("FRAME",
|
fsm.act("FRAME",
|
||||||
|
@ -189,14 +205,12 @@ class Receiver(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("SIGNAL_FRAME",
|
fsm.act("SIGNAL_FRAME",
|
||||||
signal_frame.i.eq(1),
|
NextState("IDLE"),
|
||||||
NextState("WAIT_ACK"),
|
If((write_pointer + 1) == read_pointer_rx,
|
||||||
If(converter.source.stb, signal_error.i.eq(1))
|
# on full buffer, overwrite only current frame
|
||||||
)
|
signal_error.i.eq(1)
|
||||||
fsm.act("WAIT_ACK",
|
).Else(
|
||||||
If(frame_ack.o,
|
NextValue(write_pointer, write_pointer + 1)
|
||||||
NextValue(frame_counter, 0),
|
|
||||||
NextState("IDLE")
|
|
||||||
),
|
),
|
||||||
If(converter.source.stb, signal_error.i.eq(1))
|
If(converter.source.stb, signal_error.i.eq(1))
|
||||||
)
|
)
|
||||||
|
@ -215,8 +229,8 @@ class DRTIOAuxController(Module):
|
||||||
tx_sdram_if = wishbone.SRAM(self.transmitter.mem, read_only=False, data_width=dw)
|
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)
|
rx_sdram_if = wishbone.SRAM(self.receiver.mem, read_only=True, data_width=dw)
|
||||||
decoder = wishbone.Decoder(self.bus,
|
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*aux_buffer_count)-wsb] == 0, tx_sdram_if.bus),
|
||||||
(lambda a: a[log2_int(max_packet)-wsb] == 1, rx_sdram_if.bus)],
|
(lambda a: a[log2_int(max_packet*aux_buffer_count)-wsb] == 1, rx_sdram_if.bus)],
|
||||||
register=True)
|
register=True)
|
||||||
self.submodules += tx_sdram_if, rx_sdram_if, decoder
|
self.submodules += tx_sdram_if, rx_sdram_if, decoder
|
||||||
|
|
||||||
|
|
|
@ -82,9 +82,10 @@ class Satellite(BaseSoC, AMPSoC):
|
||||||
core.link_layer, self.cpu_dw))
|
core.link_layer, self.cpu_dw))
|
||||||
self.csr_devices.append("drtioaux0")
|
self.csr_devices.append("drtioaux0")
|
||||||
|
|
||||||
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
memory_address = self.mem_map["drtioaux"]
|
memory_address = self.mem_map["drtioaux"]
|
||||||
self.add_wb_slave(memory_address, 0x800, self.drtioaux0.bus)
|
self.add_wb_slave(memory_address, drtio_aux_mem_size, self.drtioaux0.bus)
|
||||||
self.add_memory_region("drtioaux0_mem", memory_address | self.shadow_base, 0x800)
|
self.add_memory_region("drtioaux0_mem", memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
|
|
||||||
self.config["HAS_DRTIO"] = None
|
self.config["HAS_DRTIO"] = None
|
||||||
self.add_csr_group("drtioaux", ["drtioaux0"])
|
self.add_csr_group("drtioaux", ["drtioaux0"])
|
||||||
|
|
|
@ -236,10 +236,11 @@ class MasterBase(MiniSoC, AMPSoC):
|
||||||
setattr(self.submodules, coreaux_name, coreaux)
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
self.csr_devices.append(coreaux_name)
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
self.add_wb_slave(memory_address, 0x800,
|
memory_address = self.mem_map["drtioaux"] + drtio_aux_mem_size*i
|
||||||
|
self.add_wb_slave(memory_address, drtio_aux_mem_size,
|
||||||
coreaux.bus)
|
coreaux.bus)
|
||||||
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
self.config["HAS_DRTIO"] = None
|
self.config["HAS_DRTIO"] = None
|
||||||
self.config["HAS_DRTIO_ROUTING"] = None
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
self.config["DRTIO_ROLE"] = "master"
|
self.config["DRTIO_ROLE"] = "master"
|
||||||
|
@ -318,10 +319,11 @@ class MasterBase(MiniSoC, AMPSoC):
|
||||||
setattr(self.submodules, coreaux_name, coreaux)
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
self.csr_devices.append(coreaux_name)
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
memory_address = self.mem_map["drtioaux"] + 0x800*channel
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
self.add_wb_slave(memory_address, 0x800,
|
memory_address = self.mem_map["drtioaux"] + drtio_aux_mem_size*channel
|
||||||
|
self.add_wb_slave(memory_address, drtio_aux_mem_size,
|
||||||
coreaux.bus)
|
coreaux.bus)
|
||||||
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
|
|
||||||
def add_drtio_cpuif_groups(self):
|
def add_drtio_cpuif_groups(self):
|
||||||
self.add_csr_group("drtio", self.drtio_csr_group)
|
self.add_csr_group("drtio", self.drtio_csr_group)
|
||||||
|
@ -486,10 +488,11 @@ class SatelliteBase(BaseSoC, AMPSoC):
|
||||||
setattr(self.submodules, coreaux_name, coreaux)
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
self.csr_devices.append(coreaux_name)
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
self.add_wb_slave(memory_address, 0x800,
|
memory_address = self.mem_map["drtioaux"] + drtio_aux_mem_size * i
|
||||||
|
self.add_wb_slave(memory_address, drtio_aux_mem_size,
|
||||||
coreaux.bus)
|
coreaux.bus)
|
||||||
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
self.config["HAS_DRTIO"] = None
|
self.config["HAS_DRTIO"] = None
|
||||||
self.config["HAS_DRTIO_ROUTING"] = None
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
self.config["DRTIO_ROLE"] = "satellite"
|
self.config["DRTIO_ROLE"] = "satellite"
|
||||||
|
|
|
@ -247,10 +247,11 @@ class _MasterBase(MiniSoC, AMPSoC):
|
||||||
setattr(self.submodules, coreaux_name, coreaux)
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
self.csr_devices.append(coreaux_name)
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
self.add_wb_slave(memory_address, 0x800,
|
memory_address = self.mem_map["drtioaux"] + drtio_aux_mem_size*i
|
||||||
|
self.add_wb_slave(memory_address, drtio_aux_mem_size,
|
||||||
coreaux.bus)
|
coreaux.bus)
|
||||||
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
self.config["HAS_DRTIO"] = None
|
self.config["HAS_DRTIO"] = None
|
||||||
self.config["HAS_DRTIO_ROUTING"] = None
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
self.add_csr_group("drtio", drtio_csr_group)
|
self.add_csr_group("drtio", drtio_csr_group)
|
||||||
|
@ -405,10 +406,11 @@ class _SatelliteBase(BaseSoC, AMPSoC):
|
||||||
setattr(self.submodules, coreaux_name, coreaux)
|
setattr(self.submodules, coreaux_name, coreaux)
|
||||||
self.csr_devices.append(coreaux_name)
|
self.csr_devices.append(coreaux_name)
|
||||||
|
|
||||||
memory_address = self.mem_map["drtioaux"] + 0x800*i
|
drtio_aux_mem_size = 1024 * 16 # max_packet * 8 buffers * 2 (tx, rx halves)
|
||||||
self.add_wb_slave(memory_address, 0x800,
|
memory_address = self.mem_map["drtioaux"] + drtio_aux_mem_size*i
|
||||||
|
self.add_wb_slave(memory_address, drtio_aux_mem_size,
|
||||||
coreaux.bus)
|
coreaux.bus)
|
||||||
self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800)
|
self.add_memory_region(memory_name, memory_address | self.shadow_base, drtio_aux_mem_size)
|
||||||
self.config["HAS_DRTIO"] = None
|
self.config["HAS_DRTIO"] = None
|
||||||
self.config["HAS_DRTIO_ROUTING"] = None
|
self.config["HAS_DRTIO_ROUTING"] = None
|
||||||
self.add_csr_group("drtioaux", drtioaux_csr_group)
|
self.add_csr_group("drtioaux", drtioaux_csr_group)
|
||||||
|
|
|
@ -60,28 +60,36 @@ class TestAuxController(unittest.TestCase):
|
||||||
while (yield from dut[dw].aux_controller.transmitter.aux_tx.read()):
|
while (yield from dut[dw].aux_controller.transmitter.aux_tx.read()):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
def receive_packet(dw):
|
def receive_packet(pkt_no, len, dw):
|
||||||
while not (yield from dut[dw].aux_controller.receiver.aux_rx_present.read()):
|
while not (yield from dut[dw].aux_controller.receiver.aux_rx_present.read()):
|
||||||
yield
|
yield
|
||||||
length = yield from dut[dw].aux_controller.receiver.aux_rx_length.read()
|
p = yield from dut[dw].aux_controller.receiver.aux_read_pointer.read()
|
||||||
|
self.assertEqual(pkt_no, p)
|
||||||
r = []
|
r = []
|
||||||
for i in range(length//(dw//8)):
|
# packet length is derived by software now, so we pass it for the test
|
||||||
|
for i in range(len):
|
||||||
|
if dw == 64:
|
||||||
|
offset = 2048
|
||||||
|
if dw == 32:
|
||||||
|
offset = 1024
|
||||||
|
print(dw)
|
||||||
|
max_packet = 1024
|
||||||
r.append((yield from dut[dw].aux_controller.bus.read(256+i)))
|
r.append((yield from dut[dw].aux_controller.bus.read(256+i)))
|
||||||
yield from dut[dw].aux_controller.receiver.aux_rx_present.write(1)
|
yield from dut[dw].aux_controller.receiver.aux_rx_present.write(1)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
prng = random.Random(0)
|
prng = random.Random(0)
|
||||||
|
|
||||||
def send_and_check_packet(dw):
|
def send_and_check_packet(i, dw):
|
||||||
data = [prng.randrange(2**dw-1) for _ in range(prng.randrange(1, 16))]
|
data = [prng.randrange(2**dw-1) for _ in range(prng.randrange(1, 16))]
|
||||||
yield from send_packet(data, dw)
|
yield from send_packet(data, dw)
|
||||||
received = yield from receive_packet(dw)
|
received = yield from receive_packet(i, len(data), dw)
|
||||||
self.assertEqual(data, received)
|
self.assertEqual(data, received)
|
||||||
|
|
||||||
def sim(dw):
|
def sim(dw):
|
||||||
yield from link_init(dw)
|
yield from link_init(dw)
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
yield from send_and_check_packet(dw)
|
yield from send_and_check_packet(i, dw)
|
||||||
|
|
||||||
@passive
|
@passive
|
||||||
def rt_traffic(dw):
|
def rt_traffic(dw):
|
||||||
|
@ -95,5 +103,5 @@ class TestAuxController(unittest.TestCase):
|
||||||
yield dut[dw].link_layer.tx_rt_frame.eq(0)
|
yield dut[dw].link_layer.tx_rt_frame.eq(0)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
run_simulation(dut[32], [sim(32), rt_traffic(32)])
|
run_simulation(dut[32], [sim(32), rt_traffic(32)], vcd_name="32bit.vcd")
|
||||||
run_simulation(dut[64], [sim(64), rt_traffic(64)])
|
run_simulation(dut[64], [sim(64), rt_traffic(64)], vcd_name="64bit.vcd")
|
||||||
|
|
Loading…
Reference in New Issue