165 lines
5.7 KiB
Python
165 lines
5.7 KiB
Python
from migen import *
|
|
from migen.genlib.fsm import FSM
|
|
from migen.genlib.fifo import SyncFIFOBuffered
|
|
from migen_axi.interconnect import axi
|
|
from misoc.interconnect.csr import *
|
|
|
|
|
|
AXI_ADDRESS_WIDTH = 32
|
|
AXI_DATA_WIDTH = 64
|
|
AXI_BURST_LEN = 16
|
|
AXI_ALIGNMENT_BITS = log2_int(AXI_BURST_LEN*AXI_DATA_WIDTH//8)
|
|
AXI_ALIGNED_ADDRESS_WIDTH = AXI_ADDRESS_WIDTH - AXI_ALIGNMENT_BITS
|
|
|
|
|
|
class BlockAddressGenerator(Module):
|
|
def __init__(self, membus_stream, data_width):
|
|
self.base_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
|
self.length = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
|
self.start = Signal()
|
|
self.busy = Signal()
|
|
|
|
current_address = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
|
remaining = Signal(AXI_ALIGNED_ADDRESS_WIDTH)
|
|
|
|
self.comb += [
|
|
membus_stream.addr.eq(Cat(C(0, AXI_ALIGNMENT_BITS), current_address)),
|
|
membus_stream.id.eq(0), # Same ID for all transactions to forbid reordering.
|
|
membus_stream.burst.eq(axi.Burst.incr.value),
|
|
membus_stream.len.eq(AXI_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...).
|
|
membus_stream.size.eq(log2_int(AXI_DATA_WIDTH//8)), # Width of burst: 3 = 8 bytes = 64 bits.
|
|
membus_stream.cache.eq(0xf),
|
|
]
|
|
|
|
fsm = FSM()
|
|
self.submodules += fsm
|
|
fsm.act("IDLE",
|
|
If(self.start,
|
|
NextValue(current_address, self.base_address),
|
|
NextValue(remaining, self.length),
|
|
NextState("RUNNING")
|
|
)
|
|
)
|
|
fsm.act("RUNNING",
|
|
self.busy.eq(1),
|
|
membus_stream.valid.eq(1),
|
|
If(membus_stream.ready,
|
|
NextValue(current_address, current_address + 1),
|
|
NextValue(remaining, remaining - 1),
|
|
If(remaining == 1,
|
|
NextState("IDLE")
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
def convert_signal_endianness(signal):
|
|
assert len(signal) % 8 == 0
|
|
nbytes = len(signal)//8
|
|
signal_bytes = []
|
|
for i in range(nbytes):
|
|
signal_bytes.append(signal[8*i:8*(i+1)])
|
|
return Cat(*reversed(signal_bytes))
|
|
|
|
|
|
class ADCWriter(Module):
|
|
def __init__(self, membus_stream, pads):
|
|
self.length = Signal(AXI_ALIGNED_ADDRESS_WIDTH) # in AXI bursts
|
|
self.start = Signal()
|
|
self.overflow = Signal()
|
|
self.busy = Signal()
|
|
|
|
fifo = SyncFIFOBuffered(64, 512)
|
|
self.submodules += fifo
|
|
|
|
# FIFO write
|
|
adc_a = Signal(16)
|
|
adc_b = Signal(16)
|
|
self.sync += [
|
|
adc_a.eq(pads.data_a),
|
|
adc_b.eq(pads.data_b),
|
|
]
|
|
|
|
fifo_inbuf = Signal(64)
|
|
fifo_inbuf_sel = Signal()
|
|
self.sync += [
|
|
fifo_inbuf_sel.eq(~fifo_inbuf_sel),
|
|
If(fifo_inbuf_sel,
|
|
fifo_inbuf[32:].eq(Cat(adc_a, adc_b)),
|
|
).Else(
|
|
fifo_inbuf[:32].eq(Cat(adc_a, adc_b)),
|
|
)
|
|
]
|
|
self.comb += fifo.din.eq(fifo_inbuf),
|
|
|
|
assert AXI_DATA_WIDTH == len(fifo_inbuf)
|
|
remaining = Signal(AXI_ADDRESS_WIDTH - log2_int(AXI_DATA_WIDTH//8)) # in AXI_DATA_WIDTH words
|
|
self.sync += [
|
|
If(fifo.we & fifo.writable, remaining.eq(remaining - 1)),
|
|
If(self.start, remaining.eq(self.length << log2_int(AXI_BURST_LEN))),
|
|
]
|
|
self.comb += fifo.we.eq((remaining != 0) & fifo_inbuf_sel)
|
|
|
|
self.comb += self.overflow.eq(fifo.we & ~fifo.writable)
|
|
|
|
# FIFO read
|
|
self.comb += [
|
|
membus_stream.id.eq(0),
|
|
membus_stream.valid.eq(fifo.readable),
|
|
fifo.re.eq(membus_stream.ready),
|
|
membus_stream.data.eq(convert_signal_endianness(fifo.dout)),
|
|
membus_stream.strb.eq(2**(AXI_DATA_WIDTH//8)-1),
|
|
]
|
|
beat_count = Signal(max=AXI_BURST_LEN)
|
|
self.sync += [
|
|
If(membus_stream.valid & membus_stream.ready,
|
|
membus_stream.last.eq(0),
|
|
If(membus_stream.last,
|
|
beat_count.eq(0)
|
|
).Else(
|
|
If(beat_count == AXI_BURST_LEN-2, membus_stream.last.eq(1)),
|
|
beat_count.eq(beat_count + 1)
|
|
)
|
|
)
|
|
]
|
|
|
|
self.comb += self.busy.eq((remaining != 0) | fifo.readable)
|
|
|
|
|
|
class ADC(Module, AutoCSR):
|
|
def __init__(self, membus, pads):
|
|
self.base_address = CSRStorage(AXI_ADDRESS_WIDTH, alignment_bits=AXI_ALIGNMENT_BITS)
|
|
self.length = CSRStorage(AXI_ADDRESS_WIDTH, alignment_bits=AXI_ALIGNMENT_BITS)
|
|
self.start = CSR()
|
|
self.busy = CSRStatus()
|
|
self.bus_error = CSRStatus()
|
|
self.overflow = CSRStatus()
|
|
|
|
address_generator = BlockAddressGenerator(membus.aw, AXI_DATA_WIDTH)
|
|
self.submodules += address_generator
|
|
self.comb += [
|
|
address_generator.base_address.eq(self.base_address.storage),
|
|
address_generator.length.eq(self.length.storage),
|
|
address_generator.start.eq(self.start.re)
|
|
]
|
|
|
|
adc_writer = ADCWriter(membus.w, pads)
|
|
self.submodules += adc_writer
|
|
self.comb += [
|
|
adc_writer.length.eq(self.length.storage),
|
|
adc_writer.start.eq(self.start.re)
|
|
]
|
|
self.sync += [
|
|
If(self.start.re, self.overflow.status.eq(0)),
|
|
If(adc_writer.overflow, self.overflow.status.eq(1))
|
|
]
|
|
|
|
self.comb += self.busy.status.eq(address_generator.busy | adc_writer.busy)
|
|
|
|
self.comb += membus.b.ready.eq(1)
|
|
self.sync += [
|
|
If(self.start.re, self.bus_error.status.eq(0)),
|
|
If(membus.b.valid & membus.b.ready & (membus.b.resp != axi.Response.okay),
|
|
self.bus_error.status.eq(1))
|
|
]
|