frontend: move port adaptation modules to adaptation.py and do adaptation manually (and not in get_port)

This commit is contained in:
Florent Kermarrec 2016-05-26 11:03:55 +02:00
parent 3fe3a843e0
commit b3a11fb669
5 changed files with 251 additions and 230 deletions

View file

@ -0,0 +1,213 @@
from litex.gen import *
from litex.soc.interconnect import stream
from litedram.common import *
class LiteDRAMPortCDC(Module):
# TODO: check cmd/wdata/rdata fifo depths
def __init__(self, port_from, port_to):
assert port_from.aw == port_to.aw
assert port_from.dw == port_to.dw
aw = port_from.aw
dw = port_from.dw
cd_from = port_from.cd
cd_to = port_to.cd
# # #
cmd_fifo = stream.AsyncFIFO([("we", 1), ("adr", aw)], 8)
cmd_fifo = ClockDomainsRenamer({"write": cd_from,
"read": cd_to})(cmd_fifo)
self.submodules += cmd_fifo
self.comb += [
port_from.cmd.connect(cmd_fifo.sink),
cmd_fifo.source.connect(port_to.cmd)
]
wdata_fifo = stream.AsyncFIFO([("data", dw), ("we", dw//8)], 8)
wdata_fifo = ClockDomainsRenamer({"write": cd_from,
"read": cd_to})(wdata_fifo)
self.submodules += wdata_fifo
self.comb += [
port_from.wdata.connect(wdata_fifo.sink),
wdata_fifo.source.connect(port_to.wdata)
]
rdata_fifo = stream.AsyncFIFO([("data", dw)], 8)
rdata_fifo = ClockDomainsRenamer({"write": cd_to,
"read": cd_from})(rdata_fifo)
self.submodules += rdata_fifo
self.comb += [
port_to.rdata.connect(rdata_fifo.sink),
rdata_fifo.source.connect(port_from.rdata)
]
class _LiteDRAMPortDownConverter(Module):
"""LiteDRAM port DownConverter
This module reduces user port data width to fit controller data width.
With N = port_from.dw/port_to.dw:
- Address is adapted (multiplied by N + internal increments)
- A single write from the user is splitted and generate N writes to the
controller.
- Reads generates N reads on the controller and returned datas are regroup
into a single data presented to the user.
"""
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
assert port_from.dw > port_to.dw
if port_from.dw % port_to.dw:
raise ValueError("Ratio must be an int")
# # #
ratio = port_from.dw//port_to.dw
counter = Signal(max=ratio)
counter_reset = Signal()
counter_ce = Signal()
self.sync += \
If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
counter_reset.eq(1),
If(port_from.cmd.valid,
NextState("CONVERT")
)
)
fsm.act("CONVERT",
port_to.cmd.valid.eq(1),
port_to.cmd.we.eq(port_from.cmd.we),
port_to.cmd.adr.eq(port_from.cmd.adr*ratio + counter),
If(port_to.cmd.ready,
counter_ce.eq(1),
If(counter == ratio - 1,
port_from.cmd.ready.eq(1),
NextState("IDLE")
)
)
)
wdata_converter = stream.StrideConverter(port_from.wdata.description,
port_to.wdata.description)
self.submodules += wdata_converter
self.comb += [
port_from.wdata.connect(wdata_converter.sink),
wdata_converter.source.connect(port_to.wdata)
]
rdata_converter = stream.StrideConverter(port_to.rdata.description,
port_from.rdata.description)
self.submodules += rdata_converter
self.comb += [
port_to.rdata.connect(rdata_converter.sink),
rdata_converter.source.connect(port_from.rdata)
]
class _LiteDRAMPortUpConverter(Module):
# TODO:
# - handle all specials cases (incomplete / non aligned bursts)
# - add exceptions on datapath for such cases
"""LiteDRAM port UpConverter
This module increase user port data width to fit controller data width.
With N = port_to.dw/port_from.dw:
- Address is adapted (divided by N)
- N writes and read from user are regrouped in a single one to the controller
(when possible, ie when consecutive and bursting)
"""
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
assert port_from.dw < port_to.dw
if port_to.dw % port_from.dw:
raise ValueError("Ratio must be an int")
# # #
ratio = port_to.dw//port_from.dw
we = Signal()
address = Signal(port_to.aw)
counter = Signal(max=ratio)
counter_reset = Signal()
counter_ce = Signal()
self.sync += \
If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
counter_reset.eq(1),
If(port_from.cmd.valid,
NextValue(we, port_from.cmd.we),
NextValue(address, port_from.cmd.adr),
NextState("RECEIVE")
)
)
fsm.act("RECEIVE",
port_from.cmd.ready.eq(1),
If(port_from.cmd.valid,
counter_ce.eq(1),
If(counter == ratio-1,
NextState("GENERATE")
)
)
)
fsm.act("GENERATE",
port_to.cmd.valid.eq(1),
port_to.cmd.we.eq(we),
port_to.cmd.adr.eq(address[log2_int(ratio):]),
If(port_to.cmd.ready,
NextState("IDLE")
)
)
wdata_converter = stream.StrideConverter(port_from.wdata.description,
port_to.wdata.description)
self.submodules += wdata_converter
self.comb += [
port_from.wdata.connect(wdata_converter.sink),
wdata_converter.source.connect(port_to.wdata)
]
rdata_converter = stream.StrideConverter(port_to.rdata.description,
port_from.rdata.description)
self.submodules += rdata_converter
self.comb += [
port_to.rdata.connect(rdata_converter.sink),
rdata_converter.source.connect(port_from.rdata)
]
class LiteDRAMPortConverter(Module):
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
# # #
if port_from.dw > port_to.dw:
converter = _LiteDRAMPortDownConverter(port_from, port_to)
self.submodules += converter
elif port_from.dw < port_to.dw:
converter = _LiteDRAMPortUpConverter(port_from, port_to)
self.submodules += converter
else:
self.comb += [
port_from.cmd.connect(port_to.cmd),
port_from.wdata.connect(port_to.wdata),
port_to.rdata.connect(port_from.rdata)
]

View file

@ -9,213 +9,6 @@ from litex.soc.interconnect import stream
from litedram.common import *
class LiteDRAMAsyncAdapter(Module):
# TODO: check cmd/wdata/rdata fifo depths
def __init__(self, port_from, port_to):
assert port_from.aw == port_to.aw
assert port_from.dw == port.to.dw
aw = port_from.aw
dw = port_from.dw
cd_from = port_from.cd
cd_to = port_to.cd
# # #
cmd_fifo = stream.AsyncFIFO([("we", 1), ("adr", aw)], 8)
cmd_fifo = ClockDomainsRenamer({"write": cd_from,
"read": cd_to})(cmd_fifo)
self.submodules += cmd_fifo
self.comb += [
port_from.cmd.connect(cmd_fifo.sink),
cmd_fifo.source.connect(port_to.cmd)
]
wdata_fifo = stream.AsyncFIFO([("data", dw), ("we", dw//8)], 8)
wdata_fifo = ClockDomainsRenamer({"write": cd_from,
"read": cd_to})(wdata_fifo)
self.submodules += wdata_fifo
self.comb += [
port_from.wdata.connect(wdata_fifo.sink),
wdata_fifo.source.connect(port_to.wdata)
]
rdata_fifo = stream.AsyncFIFO([("data", dw)], 8)
rdata_fifo = ClockDomainsRenamer({"write": cd_to,
"read": cd_from})(rdata_fifo)
self.submodules += rdata_fifo
self.comb += [
port_to.rdata.connect(rdata_fifo.sink),
rdata_fifo.source.connect(port_from.rdata)
]
class _LiteDRAMDownConverter(Module):
"""LiteDRAM port DownConverter
This module reduces user port data width to fit controller data width.
With N = port_from.dw/port_to.dw:
- Address is adapted (multiplied by N + internal increments)
- A single write from the user is splitted and generate N writes to the
controller.
- Reads generates N reads on the controller and returned datas are regroup
into a single data presented to the user.
"""
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
assert port_from.dw > port_to.dw
if port_from.dw % port_to.dw:
raise ValueError("Ratio must be an int")
# # #
ratio = port_from.dw//port_to.dw
counter = Signal(max=ratio)
counter_reset = Signal()
counter_ce = Signal()
self.sync += \
If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
counter_reset.eq(1),
If(port_from.cmd.valid,
NextState("CONVERT")
)
)
fsm.act("CONVERT",
port_to.cmd.valid.eq(1),
port_to.cmd.we.eq(port_from.cmd.we),
port_to.cmd.adr.eq(port_from.cmd.adr*ratio + counter),
If(port_to.cmd.ready,
counter_ce.eq(1),
If(counter == ratio - 1,
port_from.cmd.ready.eq(1),
NextState("IDLE")
)
)
)
wdata_converter = stream.StrideConverter(port_from.wdata.description,
port_to.wdata.description)
self.submodules += wdata_converter
self.comb += [
port_from.wdata.connect(wdata_converter.sink),
wdata_converter.source.connect(port_to.wdata)
]
rdata_converter = stream.StrideConverter(port_to.rdata.description,
port_from.rdata.description)
self.submodules += rdata_converter
self.comb += [
port_to.rdata.connect(rdata_converter.sink),
rdata_converter.source.connect(port_from.rdata)
]
class _LiteDRAMUpConverter(Module):
# TODO:
# - handle all specials cases (incomplete / non aligned bursts)
# - add exceptions on datapath for such cases
"""LiteDRAM port UpConverter
This module increase user port data width to fit controller data width.
With N = port_to.dw/port_from.dw:
- Address is adapted (divided by N)
- N writes and read from user are regrouped in a single one to the controller
(when possible, ie when consecutive and bursting)
"""
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
assert port_from.dw < port_to.dw
if port_to.dw % port_from.dw:
raise ValueError("Ratio must be an int")
# # #
ratio = port_to.dw//port_from.dw
we = Signal()
address = Signal(port_to.aw)
counter = Signal(max=ratio)
counter_reset = Signal()
counter_ce = Signal()
self.sync += \
If(counter_reset,
counter.eq(0)
).Elif(counter_ce,
counter.eq(counter + 1)
)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
counter_reset.eq(1),
If(port_from.cmd.valid,
NextValue(we, port_from.cmd.we),
NextValue(address, port_from.cmd.adr),
NextState("RECEIVE")
)
)
fsm.act("RECEIVE",
port_from.cmd.ready.eq(1),
If(port_from.cmd.valid,
counter_ce.eq(1),
If(counter == ratio-1,
NextState("GENERATE")
)
)
)
fsm.act("GENERATE",
port_to.cmd.valid.eq(1),
port_to.cmd.we.eq(we),
port_to.cmd.adr.eq(address[log2_int(ratio):]),
If(port_to.cmd.ready,
NextState("IDLE")
)
)
wdata_converter = stream.StrideConverter(port_from.wdata.description,
port_to.wdata.description)
self.submodules += wdata_converter
self.comb += [
port_from.wdata.connect(wdata_converter.sink),
wdata_converter.source.connect(port_to.wdata)
]
rdata_converter = stream.StrideConverter(port_to.rdata.description,
port_from.rdata.description)
self.submodules += rdata_converter
self.comb += [
port_to.rdata.connect(rdata_converter.sink),
rdata_converter.source.connect(port_from.rdata)
]
class LiteDRAMConverter(Module):
def __init__(self, port_from, port_to):
assert port_from.cd == port_to.cd
# # #
if port_from.dw > port_to.dw:
converter = _LiteDRAMDownConverter(port_from, port_to)
self.submodules += converter
elif port_from.dw < port_to.dw:
converter = _LiteDRAMUpConverter(port_from, port_to)
self.submodules += converter
else:
self.comb += [
port_from.cmd.connect(port_to.cmd),
port_from.wdata.connect(port_to.wdata),
port_to.rdata.connect(port_from.rdata)
]
class LiteDRAMCrossbar(Module):
def __init__(self, controller, cba_shift):
self.controller = controller
@ -232,17 +25,12 @@ class LiteDRAMCrossbar(Module):
self.masters = []
def get_port(self, cd="sys"):
def get_port(self):
if self.finalized:
raise FinalizeError
port_to = LiteDRAMPort(self.rca_bits + self.bank_bits, self.dw, "sys")
self.masters.append(port_to)
if cd != "sys":
port_from = LiteDRAMPort(self.rca_bits + self.bank_bits, self.dw, cd)
self.submodules += LiteDRAMAsyncAdapter(port_from, port_to)
return port_from
else:
return port_to
port = LiteDRAMPort(self.rca_bits + self.bank_bits, self.dw)
self.masters.append(port)
return port
def do_finalize(self):
nmasters = len(self.masters)

View file

@ -8,6 +8,8 @@ from litedram.modules import SDRAMModule
from litedram.frontend.crossbar import LiteDRAMCrossbar
from litedram.frontend.bist import LiteDRAMBISTGenerator
from litedram.frontend.bist import LiteDRAMBISTChecker
from litedram.frontend.adaptation import LiteDRAMPortCDC
from litedram.phy.model import SDRAMPHYModel
@ -27,6 +29,7 @@ class SimModule(SDRAMModule):
class TB(Module):
def __init__(self):
# phy
sdram_module = SimModule(1000, "1:1")
phy_settings = PhySettings(
memtype="SDR",
@ -41,6 +44,7 @@ class TB(Module):
write_latency=0
)
self.submodules.sdrphy = SDRAMPHYModel(sdram_module, phy_settings)
# controller
self.submodules.controller = LiteDRAMController(
phy_settings,
sdram_module.geom_settings,
@ -49,10 +53,24 @@ class TB(Module):
self.comb += self.controller.dfi.connect(self.sdrphy.dfi)
self.submodules.crossbar = LiteDRAMCrossbar(self.controller.interface,
self.controller.nrowbits)
self.write_port = self.crossbar.get_port(cd="write")
self.read_port = self.crossbar.get_port(cd="read")
self.submodules.generator = LiteDRAMBISTGenerator(self.write_port)
self.submodules.checker = LiteDRAMBISTChecker(self.read_port)
# write port
write_crossbar_port = self.crossbar.get_port()
write_user_port = LiteDRAMPort(write_crossbar_port.aw,
write_crossbar_port.dw,
cd="write")
self.submodules += LiteDRAMPortCDC(write_user_port,
write_crossbar_port)
read_crossbar_port = self.crossbar.get_port()
read_user_port = LiteDRAMPort(read_crossbar_port.aw,
read_crossbar_port.dw,
cd="read")
# read port
self.submodules += LiteDRAMPortCDC(read_user_port,
read_crossbar_port)
self.submodules.generator = LiteDRAMBISTGenerator(write_user_port)
self.submodules.checker = LiteDRAMBISTChecker(read_user_port)
def main_generator(dut):

View file

@ -3,15 +3,16 @@ from litex.gen import *
from litex.soc.interconnect.stream import *
from litedram.common import LiteDRAMPort
from litedram.frontend.crossbar import LiteDRAMConverter
from litedram.frontend.adaptation import LiteDRAMPortConverter
from test.common import DRAMMemory
class TB(Module):
def __init__(self):
self.user_port = LiteDRAMPort(aw=32, dw=64)
self.internal_port = LiteDRAMPort(aw=32, dw=32)
self.submodules.converter = LiteDRAMConverter(self.user_port, self.internal_port)
self.crossbar_port = LiteDRAMPort(aw=32, dw=32)
self.submodules.converter = LiteDRAMPortConverter(self.user_port,
self.crossbar_port)
self.memory = DRAMMemory(32, 128)
def main_generator(dut):
@ -46,8 +47,8 @@ if __name__ == "__main__":
tb = TB()
generators = {
"sys" : [main_generator(tb),
tb.memory.write_generator(tb.internal_port),
tb.memory.read_generator(tb.internal_port)]
tb.memory.write_generator(tb.crossbar_port),
tb.memory.read_generator(tb.crossbar_port)]
}
clocks = {"sys": 10}
run_simulation(tb, generators, clocks, vcd_name="sim.vcd")

View file

@ -3,15 +3,16 @@ from litex.gen import *
from litex.soc.interconnect.stream import *
from litedram.common import LiteDRAMPort
from litedram.frontend.crossbar import LiteDRAMConverter
from litedram.frontend.adaptation import LiteDRAMPortConverter
from test.common import DRAMMemory
class TB(Module):
def __init__(self):
self.user_port = LiteDRAMPort(aw=32, dw=32)
self.internal_port = LiteDRAMPort(aw=32, dw=64)
self.submodules.converter = LiteDRAMConverter(self.user_port, self.internal_port)
self.crossbar_port = LiteDRAMPort(aw=32, dw=64)
self.submodules.converter = LiteDRAMPortConverter(self.user_port,
self.crossbar_port)
self.memory = DRAMMemory(64, 128)
def main_generator(dut):
@ -54,8 +55,8 @@ if __name__ == "__main__":
tb = TB()
generators = {
"sys" : [main_generator(tb),
tb.memory.write_generator(tb.internal_port),
tb.memory.read_generator(tb.internal_port)]
tb.memory.write_generator(tb.crossbar_port),
tb.memory.read_generator(tb.crossbar_port)]
}
clocks = {"sys": 10}
run_simulation(tb, generators, clocks, vcd_name="sim.vcd")