sdram/phy/s6ddrphy: add S6QuarterRateDDRPHY to run DDR3 at higher frequencies.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 22 Aug 2015 10:15:53 +0000 (12:15 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 22 Aug 2015 10:17:48 +0000 (12:17 +0200)
Built on top of S6HalfRateDDRPHY, exposes a 4 phases DFI interface to the controller with a 2x slower clock.
Validated on the Numato Lab opsis board (50MHz sys_clk/ DDR400), should also work on the Novena laptop (same DDR3 module).

misoclib/mem/sdram/phy/s6ddrphy.py

index 64da0cf41d2d8288cd8263fb8e67bb6bc6b28f1d..31cbdef1e67435eb2e727b695541a6509b230513 100644 (file)
@@ -1,4 +1,4 @@
-# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for Spartan-6
+# 1:2 and 1:4 frequency-ratio DDR / LPDDR / DDR2 / DDR3 PHYs for Spartan-6
 #
 # Assert dfi_wrdata_en and present the data
 # on dfi_wrdata_mask/dfi_wrdata in the same
@@ -393,3 +393,98 @@ class S6HalfRateDDRPHY(Module):
                 phase.rddata.eq(d_dfi[n].rddata),
                 phase.rddata_valid.eq(rddata_sr[0]),
             ]
+
+
+class S6QuarterRateDDRPHY(Module):
+    def __init__(self, pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
+        if module.memtype not in ["DDR3"]:
+            raise NotImplementedError("S6QuarterRateDDRPHY only supports DDR3")
+        half_rate_phy = S6HalfRateDDRPHY(pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment)
+        self.submodules += RenameClockDomains(half_rate_phy, {"sys" : "sys2x"})
+
+        addressbits = flen(pads.a)
+        bankbits = flen(pads.ba)
+        databits = flen(pads.dq)
+        nphases = 4
+
+        self.settings = sdram.PhySettings(
+            memtype="DDR3",
+            dfi_databits=2*databits,
+            nphases=nphases,
+            rdphase=0,
+            wrphase=1,
+            rdcmdphase=1,
+            wrcmdphase=0,
+            cl=5,
+            cwl=6,
+            read_latency=6//2+1,
+            write_latency=2//2
+        )
+
+        self.module = module
+
+        self.dfi = Interface(addressbits, bankbits, 2*databits, nphases)
+        self.clk8x_wr_strb = half_rate_phy.clk4x_wr_strb
+        self.clk8x_rd_strb = half_rate_phy.clk4x_rd_strb
+
+        # sys_clk      : system clk, used for dfi interface
+        # sys2x_clk    : half rate  sys clk
+        sd_sys = getattr(self.sync, "sys")
+        sd_sys2x = getattr(self.sync, "sys2x")
+
+        # select active sys2x phase
+        # sys_clk   ----____----____
+        # phase_sel 0   1   0   1
+        phase_sel = Signal()
+        phase_sys2x = Signal.like(phase_sel)
+        phase_sys = Signal.like(phase_sys2x)
+
+        sd_sys += phase_sys.eq(phase_sys2x)
+
+        sd_sys2x += [
+            If(phase_sys2x == phase_sys,
+                phase_sel.eq(0),
+            ).Else(
+                phase_sel.eq(~phase_sel)
+            ),
+            phase_sys2x.eq(~phase_sel)
+        ]
+
+        # DFI adaptation
+
+        # Commands and writes
+        dfi_leave_out = set(["rddata", "rddata_valid", "wrdata_en"])
+        self.comb += [
+            If(~phase_sel,
+                Record.connect(self.dfi.phases[0], half_rate_phy.dfi.phases[0], leave_out=dfi_leave_out),
+                Record.connect(self.dfi.phases[1], half_rate_phy.dfi.phases[1], leave_out=dfi_leave_out),
+            ).Else(
+                Record.connect(self.dfi.phases[2], half_rate_phy.dfi.phases[0], leave_out=dfi_leave_out),
+                Record.connect(self.dfi.phases[3], half_rate_phy.dfi.phases[1], leave_out=dfi_leave_out),
+            ),
+        ]
+        wr_data_en = self.dfi.phases[self.settings.wrphase].wrdata_en & ~phase_sel
+        wr_data_en_d = Signal()
+        sd_sys2x += wr_data_en_d.eq(wr_data_en)
+        self.comb += half_rate_phy.dfi.phases[half_rate_phy.settings.wrphase].wrdata_en.eq(wr_data_en | wr_data_en_d)
+
+        # Reads
+        rddata = Array(Signal(2*databits) for i in range(2))
+        rddata_valid = Signal(2)
+
+        for i in range(2):
+            sd_sys2x += [
+                rddata_valid[i].eq(half_rate_phy.dfi.phases[i].rddata_valid),
+                rddata[i].eq(half_rate_phy.dfi.phases[i].rddata)
+            ]
+
+        sd_sys += [
+            self.dfi.phases[0].rddata.eq(rddata[0]),
+            self.dfi.phases[0].rddata_valid.eq(rddata_valid[0]),
+            self.dfi.phases[1].rddata.eq(rddata[1]),
+            self.dfi.phases[1].rddata_valid.eq(rddata_valid[1]),
+            self.dfi.phases[2].rddata.eq(half_rate_phy.dfi.phases[0].rddata),
+            self.dfi.phases[2].rddata_valid.eq(half_rate_phy.dfi.phases[0].rddata_valid),
+            self.dfi.phases[3].rddata.eq(half_rate_phy.dfi.phases[1].rddata),
+            self.dfi.phases[3].rddata_valid.eq(half_rate_phy.dfi.phases[1].rddata_valid)
+        ]