Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stable avalon frontend #354

Merged
merged 8 commits into from
Mar 25, 2024
19 changes: 12 additions & 7 deletions litedram/frontend/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,28 @@ def __init__(self, port_from, port_to, reverse=False):

ratio = port_from.data_width//port_to.data_width
mode = port_from.mode
count = Signal(max=ratio)

cmd_count = Signal(max=ratio)
cmd_addr = Signal(len(port_from.cmd.addr))
cmd_we = Signal()

self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
NextValue(count, 0),
port_from.cmd.ready.eq(1),
If(port_from.cmd.valid,
NextValue(cmd_count, 0),
NextValue(cmd_addr, port_from.cmd.addr),
NextValue(cmd_we, port_from.cmd.we),
NextState("CONVERT")
)
)
fsm.act("CONVERT",
port_to.cmd.valid.eq(1),
port_to.cmd.we.eq(port_from.cmd.we),
port_to.cmd.addr.eq(port_from.cmd.addr*ratio + count),
port_to.cmd.we.eq(cmd_we),
port_to.cmd.addr.eq(cmd_addr*ratio + cmd_count),
If(port_to.cmd.ready,
NextValue(count, count + 1),
If(count == (ratio - 1),
port_from.cmd.ready.eq(1),
NextValue(cmd_count, cmd_count + 1),
If(cmd_count == (ratio - 1),
NextState("IDLE")
)
)
Expand Down
185 changes: 75 additions & 110 deletions litedram/frontend/avalon.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,25 @@

from migen import *

from litex.gen import *

from litex.soc.interconnect import stream

from litedram.common import LiteDRAMNativePort
from litedram.frontend.adapter import LiteDRAMNativePortConverter


# LiteDRAMAvalonMM2Native --------------------------------------------------------------------------

class LiteDRAMAvalonMM2Native(Module):
class LiteDRAMAvalonMM2Native(LiteXModule):
def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000, burst_increment=1):
# Parameters.
avalon_data_width = len(avalon.writedata)
port_data_width = 2**int(log2(len(port.wdata.data))) # Round to lowest power 2
ratio = avalon_data_width/port_data_width
downconvert = ratio > 1
upconvert = ratio < 1
port_data_width = 2**int(log2(len(port.wdata.data))) # Round to lowest power 2
ratio = avalon_data_width/port_data_width
downconvert = ratio > 1
upconvert = ratio < 1

# Data-Width Converter (Optional).
if avalon_data_width != port_data_width:
if avalon_data_width > port_data_width:
addr_shift = -log2_int(avalon_data_width//port_data_width)
Expand All @@ -35,76 +39,70 @@ def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000
address_width = port.address_width + addr_shift,
data_width = avalon_data_width
)
self.submodules += LiteDRAMNativePortConverter(new_port, port)
self.converter = LiteDRAMNativePortConverter(new_port, port)
port = new_port

# # #

offset = base_address >> log2_int(port.data_width//8)
# Internal Signals.
burst_count = Signal(9)
address = Signal(port.address_width)
address_offset = Signal(port.address_width)
byteenable = Signal(avalon_data_width//8)
writedata = Signal(avalon_data_width)
latch = Signal()
cmd_ready_seen = Signal()
cmd_ready_count = Signal(9)

burstcounter = Signal(9)
start_burst = Signal()
active_burst = Signal()
address = Signal.like(port.cmd.addr)
byteenable = Signal.like(avalon.byteenable)
writedata = Signal(avalon_data_width)
start_transaction = Signal()
cmd_ready_seen = Signal()
cmd_ready_counter = Signal.like(burstcounter)
self.comb += address_offset.eq(base_address >> log2_int(port.data_width//8))

cmd_layout = [("address", len(address))]
# Layouts.
cmd_layout = [("address", len(address))]
wdata_layout = [
("data", avalon_data_width),
("byteenable", len(avalon.byteenable))
("data", avalon_data_width),
("byteenable", avalon_data_width//8),
]

self.comb += [
start_burst .eq(2 <= avalon.burstcount),
active_burst.eq(1 <= burstcounter)
]
self.sync += [
If(start_transaction,
If(latch,
byteenable.eq(avalon.byteenable),
burstcounter.eq(avalon.burstcount),
address.eq(avalon.address - offset))
writedata.eq(avalon.writedata),
burst_count.eq(avalon.burstcount),
address.eq(avalon.address - address_offset),
)
]

start_condition = start_transaction if downconvert else (start_transaction & (start_burst | port.cmd.ready))

self.submodules.fsm = fsm = FSM(reset_state="START")
# FSM.
self.fsm = fsm = FSM(reset_state="START")
fsm.act("START",
avalon.waitrequest.eq(1),
If (~start_burst,
port.cmd.addr.eq(avalon.address - offset),
port.cmd.we.eq(avalon.write),
port.cmd.valid.eq(avalon.read | avalon.write)
),

start_transaction.eq(avalon.read | avalon.write),

If(start_condition,
[] if downconvert else [If (~start_burst, avalon.waitrequest.eq(0))],
If (avalon.write,
If (start_burst,
NextValue(cmd_ready_seen, 0),
# Start of Access.
If(avalon.read | avalon.write,
latch.eq(1),
# Burst Access.
If(avalon.burstcount > 1,
If(avalon.write,
NextState("BURST_WRITE")
).Else(
[
port.wdata.data.eq(avalon.writedata),
port.wdata.valid.eq(1),
port.wdata.we.eq(avalon.byteenable),
] if downconvert else [],
NextValue(writedata, avalon.writedata),
port.cmd.last.eq(1),
NextState("SINGLE_WRITE")
)
).Elif(avalon.read,
If (start_burst,
),
If(avalon.read,
avalon.waitrequest.eq(0),
NextValue(cmd_ready_counter, avalon.burstcount),
NextValue(cmd_ready_count, avalon.burstcount),
NextState("BURST_READ")
).Else(
port.cmd.last.eq(1),
NextState("SINGLE_READ")
)
# Single Access.
).Else(
port.cmd.addr.eq(avalon.address - address_offset),
port.cmd.we.eq(avalon.write),
port.cmd.valid.eq(1),
port.cmd.last.eq(1),
If(port.cmd.ready,
avalon.waitrequest.eq(0),
If(port.cmd.we,
NextState("SINGLE_WRITE")
).Else(
NextState("SINGLE_READ")
)
)
)
)
Expand All @@ -114,29 +112,11 @@ def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000
avalon.waitrequest.eq(1),
port.rdata.ready.eq(0),

[
port.cmd.addr.eq(address),
port.cmd.we.eq(1),
port.cmd.valid.eq(1),

If(port.cmd.ready, NextValue(cmd_ready_seen, 1)),
If(cmd_ready_seen,
port.cmd.valid.eq(0),
port.cmd.we.eq(0)
),
] if downconvert else [],

port.wdata.data.eq(writedata),
port.wdata.valid.eq(1),
port.wdata.we.eq(byteenable),

If(port.wdata.ready,
avalon.waitrequest.eq(0 if downconvert else 1),
NextValue(writedata, avalon.writedata),

port.flush.eq(1),
NextValue(cmd_ready_seen, 0) if downconvert else NextValue(port.cmd.last, 1),
NextValue(byteenable, 0),
NextState("START")
)
)
Expand All @@ -145,33 +125,16 @@ def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000
avalon.waitrequest.eq(1),
port.rdata.ready.eq(1),

[
port.cmd.addr.eq(address),
port.cmd.we.eq(0),
port.cmd.valid.eq(1),

If(port.cmd.ready, NextValue(cmd_ready_seen, 1)),
If(cmd_ready_seen,
port.cmd.valid.eq(0),
port.cmd.we.eq(0)
),
] if downconvert else [],

If(port.rdata.valid,
avalon.readdata.eq(port.rdata.data),
avalon.readdatavalid.eq(1),

[
port.cmd.valid.eq(0),
avalon.waitrequest.eq(0),
NextValue(cmd_ready_seen, 0),
] if downconvert else [],
NextState("START")
)
)

self.submodules.cmd_fifo = cmd_fifo = stream.SyncFIFO(cmd_layout, max_burst_length)
self.submodules.wdata_fifo = wdata_fifo = stream.SyncFIFO(wdata_layout, max_burst_length)
self.cmd_fifo = cmd_fifo = stream.SyncFIFO(cmd_layout, max_burst_length)
self.wdata_fifo = wdata_fifo = stream.SyncFIFO(wdata_layout, max_burst_length)

fsm.act("BURST_WRITE",
# FIFO producer
Expand All @@ -183,15 +146,15 @@ def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000
wdata_fifo.sink.payload.byteenable.eq(avalon.byteenable),
wdata_fifo.sink.valid.eq(avalon.write & ~avalon.waitrequest),

If (avalon.write & active_burst,
If (cmd_fifo.sink.ready & cmd_fifo.sink.valid,
NextValue(burstcounter, burstcounter - 1),
NextValue(address, address + burst_increment))
If(avalon.write & (burst_count > 0),
If(cmd_fifo.sink.ready & cmd_fifo.sink.valid,
NextValue(burst_count, burst_count - 1),
NextValue(address, address + burst_increment)
)
).Else(
avalon.waitrequest.eq(1),
# wait for the FIFO to be empty
If ((cmd_fifo .level == 0) &
(wdata_fifo.level == 1) & port.wdata.ready,
# Wait for the FIFO to be empty
If((cmd_fifo.level == 0) & (wdata_fifo.level == 1) & port.wdata.ready,
NextState("START")
)
),
Expand All @@ -218,16 +181,18 @@ def __init__(self, avalon, port, *, max_burst_length=16, base_address=0x00000000
avalon.readdata.eq(port.rdata.data),
avalon.readdatavalid.eq(port.rdata.valid),

If (port.cmd.ready,
If (cmd_ready_counter == 1, NextValue(cmd_ready_seen, 1)),
NextValue(cmd_ready_counter, cmd_ready_counter - 1),
If(port.cmd.ready,
If(cmd_ready_count == 1,
NextValue(cmd_ready_seen, 1)
),
NextValue(cmd_ready_count, cmd_ready_count - 1),
NextValue(address, address + burst_increment)
),

If (port.rdata.valid,
If (burstcounter == 1,
NextValue(cmd_ready_seen, 0),
NextState("START")),
NextValue(burstcounter, burstcounter - 1)
If(port.rdata.valid,
If(burst_count == 1,
NextState("START")
),
NextValue(burst_count, burst_count - 1)
)
)
Loading