From b3a11fb6696f4df757e91e951081b8aa1e911c1b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 May 2016 11:03:55 +0200 Subject: [PATCH] frontend: move port adaptation modules to adaptation.py and do adaptation manually (and not in get_port) --- litedram/frontend/adaptation.py | 213 +++++++++++++++++++++++++++++++ litedram/frontend/crossbar.py | 220 +------------------------------- test/bist_async_tb.py | 26 +++- test/downconverter_tb.py | 11 +- test/upconverter_tb.py | 11 +- 5 files changed, 251 insertions(+), 230 deletions(-) create mode 100644 litedram/frontend/adaptation.py diff --git a/litedram/frontend/adaptation.py b/litedram/frontend/adaptation.py new file mode 100644 index 0000000..f0a4d85 --- /dev/null +++ b/litedram/frontend/adaptation.py @@ -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) + ] diff --git a/litedram/frontend/crossbar.py b/litedram/frontend/crossbar.py index f1baebd..9301ce7 100644 --- a/litedram/frontend/crossbar.py +++ b/litedram/frontend/crossbar.py @@ -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) diff --git a/test/bist_async_tb.py b/test/bist_async_tb.py index afdb03f..b0c70e6 100644 --- a/test/bist_async_tb.py +++ b/test/bist_async_tb.py @@ -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): diff --git a/test/downconverter_tb.py b/test/downconverter_tb.py index ece87c9..d903d06 100644 --- a/test/downconverter_tb.py +++ b/test/downconverter_tb.py @@ -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") diff --git a/test/upconverter_tb.py b/test/upconverter_tb.py index 7c66884..39b9878 100644 --- a/test/upconverter_tb.py +++ b/test/upconverter_tb.py @@ -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")