sdramphy: move and clean up s6ddrphy, add generic SDRAM PHY
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 17 Apr 2014 17:38:13 +0000 (19:38 +0200)
committerSebastien Bourdeauducq <sb@m-labs.hk>
Thu, 17 Apr 2014 17:38:25 +0000 (19:38 +0200)
make.py
misoclib/s6ddrphy/__init__.py [deleted file]
misoclib/s6ddrphy/initsequence.py [deleted file]
misoclib/sdramphy/gensdrphy.py [new file with mode: 0644]
misoclib/sdramphy/initsequence.py [new file with mode: 0644]
misoclib/sdramphy/s6ddrphy.py [new file with mode: 0644]
targets/mlabs_video.py

diff --git a/make.py b/make.py
index c245e0c8b20843bd639160b43c5f1f153f12d455..c8ef3db3ed31461ad2511359d67beebca901f8aa 100755 (executable)
--- a/make.py
+++ b/make.py
@@ -7,7 +7,7 @@ from migen.util.misc import autotype
 from migen.fhdl import simplify
 
 from misoclib.gensoc import cpuif
-from misoclib.s6ddrphy import initsequence
+from misoclib.sdramphy import initsequence
 import programmer
 
 def _get_args():
@@ -151,9 +151,10 @@ Subtarget: {}
                write_to_file("software/include/generated/mem.h", boilerplate + mem_header)
                csr_header = cpuif.get_csr_header(soc.csr_base, soc.csrbankarray, soc.interrupt_map)
                write_to_file("software/include/generated/csr.h", boilerplate + csr_header)
-               if hasattr(soc, "ddrphy"):
-                       sdram_phy_header = initsequence.get_sdram_phy_header(soc.ddrphy)
-                       write_to_file("software/include/generated/sdram_phy.h", boilerplate + sdram_phy_header)
+               for sdram_phy in ["sdrphy", "ddrphy"]:
+                       if hasattr(soc, sdram_phy):
+                               sdram_phy_header = initsequence.get_sdram_phy_header(getattr(soc, sdram_phy))
+                               write_to_file("software/include/generated/sdram_phy.h", boilerplate + sdram_phy_header)
 
        if actions["build-csr-csv"]:
                csr_csv = cpuif.get_csr_csv(soc.csr_base, soc.csrbankarray)
diff --git a/misoclib/s6ddrphy/__init__.py b/misoclib/s6ddrphy/__init__.py
deleted file mode 100644 (file)
index 044c0af..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for 
-# Spartan-6
-# 
-# Assert dfi_wrdata_en and present the data 
-# on dfi_wrdata_mask/dfi_wrdata in the same
-# cycle as the write command.
-#
-# Assert dfi_rddata_en in the same cycle as the read
-# command. The data will come back on dfi_rddata
-# 5 cycles later, along with the assertion 
-# of dfi_rddata_valid.
-#
-# This PHY only supports CAS Latency 3.
-# Read commands must be sent on phase 0.
-# Write commands must be sent on phase 1.
-#
-
-# Todo:
-#      - use CSR for bitslip?
-#      - add configurable CAS Latency
-#      - automatically determines wrphase / rdphase / latencies
-
-from migen.fhdl.std import *
-from migen.bus.dfi import *
-from migen.genlib.record import *
-
-from misoclib import lasmicon
-
-class S6DDRPHY(Module):
-       def __init__(self, pads, memtype, nphases, cl, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
-               if memtype not in ["DDR", "LPDDR", "DDR2"]:
-                       raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2")
-               if cl != 3:
-                       raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3")
-               a = flen(pads.a)
-               ba = flen(pads.ba)
-               d = flen(pads.dq)
-
-               self.phy_settings = lasmicon.PhySettings(
-                       memtype=memtype,
-                       dfi_d=2*d,
-                       nphases=nphases,
-                       rdphase=0,
-                       wrphase=1,
-                       rdcmdphase=1,
-                       wrcmdphase=0,
-                       cl=cl,
-                       read_latency=5,
-                       write_latency=0
-               )
-
-               self.dfi = Interface(a, ba, nphases*d, nphases)
-               self.clk4x_wr_strb = Signal()
-               self.clk4x_rd_strb = Signal()
-
-               ###
-
-               # sys_clk           : system clk, used for dfi interface
-               # sdram_half_clk    : half rate sdram clk
-               # sdram_full_wr_clk : full rate sdram write clk
-               # sdram_full_rd_clk : full rate sdram read clk
-               sd_sys = getattr(self.sync, "sys")
-               sd_sdram_half = getattr(self.sync, "sdram_half")
-
-               sys_clk = ClockSignal("sys")
-               sdram_half_clk = ClockSignal("sdram_half")
-               sdram_full_wr_clk = ClockSignal("sdram_full_wr")
-               sdram_full_rd_clk = ClockSignal("sdram_full_rd")
-
-               # 
-               # Command/address
-               #
-
-               # select active phase
-               #             sys_clk   ----____----____
-               #  phase_sel(nphases=1) 0       0
-               #  phase_sel(nphases=2) 0   1   0   1
-               #  phase_sel(nphases=4) 0 1 2 3 0 1 2 3
-               phase_sel = Signal(log2_int(nphases))
-               sys_clk_d = Signal()
-
-               sd_sdram_half += [
-                       If(sys_clk & ~sys_clk_d,
-                               phase_sel.eq(0)
-                       ).Else(
-                               phase_sel.eq(phase_sel+1)
-                       ),
-                       sys_clk_d.eq(sys_clk)
-               ]
-
-               # register dfi cmds on half_rate clk
-               r_dfi = Array(Record(phase_cmd_description(a, ba)) for i in range(nphases))
-               for n, phase in enumerate(self.dfi.phases):
-                       sd_sdram_half +=[
-                               r_dfi[n].address.eq(phase.address),
-                               r_dfi[n].bank.eq(phase.bank),
-                               r_dfi[n].cs_n.eq(phase.cs_n),
-                               r_dfi[n].cke.eq(phase.cke),
-                               r_dfi[n].cas_n.eq(phase.cas_n),
-                               r_dfi[n].ras_n.eq(phase.ras_n),
-                               r_dfi[n].we_n.eq(phase.we_n)
-                       ]
-
-               # output cmds
-               sd_sdram_half += [
-                       pads.a.eq(r_dfi[phase_sel].address),
-                       pads.ba.eq(r_dfi[phase_sel].bank),
-                       pads.cke.eq(r_dfi[phase_sel].cke),
-                       pads.ras_n.eq(r_dfi[phase_sel].ras_n),
-                       pads.cas_n.eq(r_dfi[phase_sel].cas_n),
-                       pads.we_n.eq(r_dfi[phase_sel].we_n)
-               ]
-               if hasattr(pads, "cs_n"):
-                       sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n)
-
-               # 
-               # Bitslip
-               #
-               bitslip_cnt = Signal(4)
-               bitslip_inc = Signal()
-
-               sd_sys += [
-                       If(bitslip_cnt == rd_bitslip,
-                               bitslip_inc.eq(0)
-                       ).Else(
-                               bitslip_cnt.eq(bitslip_cnt+1),
-                               bitslip_inc.eq(1)
-                       )
-               ]
-
-               # 
-               # DQ/DQS/DM data
-               #
-               sdram_half_clk_n = Signal()
-               self.comb += sdram_half_clk_n.eq(~sdram_half_clk)
-
-               postamble = Signal()
-               drive_dqs = Signal()
-               dqs_t_d0 = Signal()
-               dqs_t_d1 = Signal()
-
-               dqs_o = Signal(d//8) 
-               dqs_t = Signal(d//8)
-
-               self.comb += [
-                       dqs_t_d0.eq(~(drive_dqs | postamble)),
-                       dqs_t_d1.eq(~drive_dqs),
-               ]
-
-               for i in range(d//8):
-                       # DQS output
-                       self.specials += Instance("ODDR2",
-                               p_DDR_ALIGNMENT=dqs_ddr_alignment,
-                               p_INIT=0,
-                               p_SRTYPE="ASYNC",
-
-                               i_C0=sdram_half_clk,
-                               i_C1=sdram_half_clk_n,
-
-                               i_CE=1,
-                               i_D0=0,
-                               i_D1=1,
-                               i_R=0,
-                               i_S=0,
-
-                               o_Q=dqs_o[i]
-                       )
-
-                       # DQS tristate cmd
-                       self.specials += Instance("ODDR2",
-                               p_DDR_ALIGNMENT=dqs_ddr_alignment,
-                               p_INIT=0,
-                               p_SRTYPE="ASYNC",
-
-                               i_C0=sdram_half_clk,
-                               i_C1=sdram_half_clk_n,
-
-                               i_CE=1,
-                               i_D0=dqs_t_d0,
-                               i_D1=dqs_t_d1,
-                               i_R=0,
-                               i_S=0,
-
-                               o_Q=dqs_t[i]
-                       )
-
-                       # DQS tristate buffer
-                       if hasattr(pads, "dqs_n"):
-                               self.specials += Instance("OBUFTDS",
-                                       i_I=dqs_o[i],
-                                       i_T=dqs_t[i],
-
-                                       o_O=pads.dqs[i],
-                                       o_OB=pads.dqs_n[i],
-                               )
-                       else:
-                               self.specials += Instance("OBUFT",
-                                       i_I=dqs_o[i],
-                                       i_T=dqs_t[i],
-
-                                       o_O=pads.dqs[i]
-                               )
-
-               sd_sdram_half += postamble.eq(drive_dqs)
-
-               d_dfi = [Record(phase_wrdata_description(nphases*d)+phase_rddata_description(nphases*d)) 
-                       for i in range(2*nphases)]
-
-               for n, phase in enumerate(self.dfi.phases):
-                       self.comb += [
-                               d_dfi[n].wrdata.eq(phase.wrdata),
-                               d_dfi[n].wrdata_mask.eq(phase.wrdata_mask),
-                               d_dfi[n].wrdata_en.eq(phase.wrdata_en),
-                               d_dfi[n].rddata_en.eq(phase.rddata_en),
-                       ]
-                       sd_sys += [
-                               d_dfi[nphases+n].wrdata.eq(phase.wrdata),
-                               d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask)
-                       ]
-
-
-               drive_dq = Signal()
-               drive_dq_n = [Signal() for i in range(2)]
-               self.comb += drive_dq_n[0].eq(~drive_dq)
-               sd_sys += drive_dq_n[1].eq(drive_dq_n[0])
-
-               dq_t = Signal(d)
-               dq_o = Signal(d)
-               dq_i = Signal(d)
-
-               dq_wrdata = []
-               for i in range(2):
-                       for j in reversed(range(nphases)):
-                               dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:d])
-                               dq_wrdata.append(d_dfi[i*nphases+j].wrdata[d:])
-
-               for i in range(d):
-                       # Data serializer
-                       self.specials += Instance("OSERDES2",
-                               p_DATA_WIDTH=4,
-                               p_DATA_RATE_OQ="SDR",
-                               p_DATA_RATE_OT="SDR",
-                               p_SERDES_MODE="NONE",
-                               p_OUTPUT_MODE="SINGLE_ENDED",
-
-                               o_OQ=dq_o[i],
-                               i_OCE=1,
-                               i_CLK0=sdram_full_wr_clk,
-                               i_CLK1=0,
-                               i_IOCE=self.clk4x_wr_strb,
-                               i_RST=0,
-                               i_CLKDIV=sys_clk,
-
-                               i_D1=dq_wrdata[wr_bitslip+3][i],
-                               i_D2=dq_wrdata[wr_bitslip+2][i],
-                               i_D3=dq_wrdata[wr_bitslip+1][i],
-                               i_D4=dq_wrdata[wr_bitslip+0][i],
-
-                               o_TQ=dq_t[i],
-                               i_T1=drive_dq_n[(wr_bitslip+3)//4],
-                               i_T2=drive_dq_n[(wr_bitslip+2)//4],
-                               i_T3=drive_dq_n[(wr_bitslip+1)//4],
-                               i_T4=drive_dq_n[(wr_bitslip+0)//4],
-                               i_TRAIN=0,
-                               i_TCE=1,
-                               i_SHIFTIN1=0,
-                               i_SHIFTIN2=0,
-                               i_SHIFTIN3=0,
-                               i_SHIFTIN4=0,
-                       )
-
-                       # Data deserializer
-                       self.specials += Instance("ISERDES2",
-                               p_DATA_WIDTH=4,
-                               p_DATA_RATE="SDR",
-                               p_BITSLIP_ENABLE="TRUE",
-                               p_SERDES_MODE="NONE",
-                               p_INTERFACE_TYPE="RETIMED",
-
-                               i_D=dq_i[i],
-                               i_CE0=1,
-                               i_CLK0=sdram_full_rd_clk,
-                               i_CLK1=0,
-                               i_IOCE=self.clk4x_rd_strb,
-                               i_RST=ResetSignal(),
-                               i_CLKDIV=sys_clk,
-                               i_BITSLIP=bitslip_inc,
-
-                               o_Q1=d_dfi[0*nphases+0].rddata[i+d],
-                               o_Q2=d_dfi[0*nphases+0].rddata[i],
-                               o_Q3=d_dfi[0*nphases+1].rddata[i+d],
-                               o_Q4=d_dfi[0*nphases+1].rddata[i],
-                       )
-
-                       # Data buffer
-                       self.specials += Instance("IOBUF",
-                               i_I=dq_o[i],
-                               o_O=dq_i[i],
-                               i_T=dq_t[i],
-                               io_IO=pads.dq[i]
-                       )
-
-               dq_wrdata_mask = []
-               for i in range(2):
-                       for j in reversed(range(nphases)):
-                               dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:d//8])
-                               dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[d//8:])
-
-               for i in range(d//8):
-                       # Mask serializer
-                       self.specials += Instance("OSERDES2",
-                               p_DATA_WIDTH=4,
-                               p_DATA_RATE_OQ="SDR",
-                               p_DATA_RATE_OT="SDR",
-                               p_SERDES_MODE="NONE",
-                               p_OUTPUT_MODE="SINGLE_ENDED",
-
-                               o_OQ=pads.dm[i],
-                               i_OCE=1,
-                               i_CLK0=sdram_full_wr_clk,
-                               i_CLK1=0,
-                               i_IOCE=self.clk4x_wr_strb,
-                               i_RST=0,
-                               i_CLKDIV=sys_clk,
-
-                               i_D1=dq_wrdata_mask[wr_bitslip+3][i],
-                               i_D2=dq_wrdata_mask[wr_bitslip+2][i],
-                               i_D3=dq_wrdata_mask[wr_bitslip+1][i],
-                               i_D4=dq_wrdata_mask[wr_bitslip+0][i],
-
-                               i_TRAIN=0,
-                               i_TCE=0,
-                               i_SHIFTIN1=0,
-                               i_SHIFTIN2=0,
-                               i_SHIFTIN3=0,
-                               i_SHIFTIN4=0,
-                       )
-
-               #
-               # ODT
-               #
-               # ODT not yet supported
-               if hasattr(pads, "odt"):
-                       self.comb += pads.odt.eq(0)
-
-               # 
-               # DQ/DQS/DM control
-               #
-               self.comb += drive_dq.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
-
-               d_dfi_wrdata_en = Signal()
-               sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
-               
-               r_dfi_wrdata_en = Signal(2)
-               sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0])) 
-
-               self.comb += drive_dqs.eq(r_dfi_wrdata_en[1])
-
-               rddata_sr = Signal(self.phy_settings.read_latency)
-               sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.phy_settings.read_latency],
-                       d_dfi[self.phy_settings.rdphase].rddata_en))
-               
-               for n, phase in enumerate(self.dfi.phases):
-                       self.comb += [
-                               phase.rddata.eq(d_dfi[n].rddata),
-                               phase.rddata_valid.eq(rddata_sr[0]),
-                       ]
diff --git a/misoclib/s6ddrphy/initsequence.py b/misoclib/s6ddrphy/initsequence.py
deleted file mode 100644 (file)
index cf76d4e..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-from migen.fhdl.std import log2_int
-
-def get_sdram_phy_header(sdram_phy):
-       if sdram_phy.phy_settings.memtype not in ["SDR", "DDR", "LPDDR", "DDR2"]:
-               raise NotImplementedError("The SDRAM PHY header generator only supports SDR, DDR, LPDDR and DDR2")
-
-       r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n"
-       r += "#include <hw/common.h>\n#include <generated/csr.h>\n#include <hw/flags.h>\n\n"
-
-       r += "static void cdelay(int i);\n"
-
-       #
-       # commands_px functions
-       # 
-       for n in range(sdram_phy.phy_settings.nphases):
-               r += """
-static void command_p{n}(int cmd)
-{{
-       dfii_pi{n}_command_write(cmd);
-       dfii_pi{n}_command_issue_write(1);
-}}""".format(n=str(n))
-       r += "\n\n"
-
-       #
-       # rd/wr access macros
-       #
-       r += """
-#define dfii_pird_address_write(X) dfii_pi{rdphase}_address_write(X)
-#define dfii_piwr_address_write(X) dfii_pi{wrphase}_address_write(X)
-
-#define dfii_pird_baddress_write(X) dfii_pi{rdphase}_baddress_write(X)
-#define dfii_piwr_baddress_write(X) dfii_pi{wrphase}_baddress_write(X)
-
-#define command_prd(X) command_p{rdphase}(X)
-#define command_pwr(X) command_p{wrphase}(X)
-""".format(rdphase=str(sdram_phy.phy_settings.rdphase), wrphase=str(sdram_phy.phy_settings.wrphase)) 
-       r +="\n"
-       
-       #
-       # init sequence
-       # 
-       cmds = {
-               "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
-               "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
-               "AUTO_REFRESH"  : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS",
-               "CKE"           : "DFII_CONTROL_CKE"
-       }
-
-       def gen_cmd(comment, a, ba, cmd, delay):        
-               r = "\t/* {0} */\n".format(comment)
-               r += "\tdfii_pi0_address_write({0:#x});\n".format(a)
-               r += "\tdfii_pi0_baddress_write({0:d});\n".format(ba)
-               if "CKE" in cmd:
-                       r += "\tdfii_control_write({0});\n".format(cmd)
-               else:
-                       r += "\tcommand_p0({0});\n".format(cmd)
-               r += "\tcdelay({0:d});\n".format(delay)
-               r += "\n"
-               return r
-
-
-       r += "static void init_sequence(void)\n{\n"
-
-       cl = sdram_phy.phy_settings.cl
-       
-       if sdram_phy.phy_settings.memtype == "SDR":
-               bl = 1*sdram_phy.phy_settings.nphases
-               mr  = log2_int(bl) + (cl << 4)
-               reset_dll = 1 << 8
-
-               init_sequence = [
-                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
-                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
-                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
-               ]
-
-       elif sdram_phy.phy_settings.memtype == "DDR":
-               bl = 2*sdram_phy.phy_settings.nphases
-               mr  = log2_int(bl) + (cl << 4)
-               emr = 0
-               reset_dll = 1 << 8
-
-               init_sequence = [
-                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
-                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
-                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
-                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
-               ]
-
-       elif sdram_phy.phy_settings.memtype == "LPDDR":
-               bl = 2*sdram_phy.phy_settings.nphases
-               mr  = log2_int(bl) + (cl << 4)
-               emr = 0
-               reset_dll = 1 << 8
-
-               init_sequence = [
-                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
-                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0),
-                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
-                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
-               ]
-
-       elif sdram_phy.phy_settings.memtype == "DDR2":
-               bl = 2*sdram_phy.phy_settings.nphases
-               wr = 2
-               mr  = log2_int(bl) + (cl << 4) + (wr << 9)
-               emr = 0
-               emr2 = 0
-               emr3 = 0
-               reset_dll = 1 << 8
-               ocd = 7 << 7
-
-               init_sequence = [
-                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
-                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0),
-                       ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0),
-                       ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
-                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
-                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
-                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200),
-                       ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0),
-                       ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0),
-               ]
-
-       for comment, a, ba, cmd, delay in init_sequence:
-               r += gen_cmd(comment, a, ba, cmd, delay)
-
-       r += "}\n"
-       r += "#endif\n"
-
-       return r
diff --git a/misoclib/sdramphy/gensdrphy.py b/misoclib/sdramphy/gensdrphy.py
new file mode 100644 (file)
index 0000000..01ccc19
--- /dev/null
@@ -0,0 +1,97 @@
+#
+# 1:1 frequency-ratio Generic SDR PHY 
+# 
+# The GENSDRPHY is validated on CycloneIV (Altera) but since it does 
+# not use vendor-dependent code, it can also be used on other architectures.
+#
+# The PHY needs 2 Clock domains:
+#  - sys_clk    : The System Clock domain
+#  - sys_clk_ps : The System Clock domain with its phase shifted 
+#                 (-0.75ns on C4@100MHz)
+#
+# Assert dfi_wrdata_en and present the data 
+# on dfi_wrdata_mask/dfi_wrdata in the same
+# cycle as the write command.
+#
+# Assert dfi_rddata_en in the same cycle as the read
+# command. The data will come back on dfi_rddata
+# 4 cycles later, along with the assertion of
+# dfi_rddata_valid.
+#
+# This PHY only supports CAS Latency 2.
+#
+
+from migen.fhdl.std import *
+from migen.bus.dfi import *
+from migen.genlib.record import *
+from migen.fhdl.specials import *
+
+from misoclib import lasmicon
+
+class GENSDRPHY(Module):
+       def __init__(self, pads, memtype, nphases, cl):
+               if memtype not in ["SDR"]:
+                       raise NotImplementedError("GENSDRPHY only supports SDR")
+               if cl != 2:
+                       raise NotImplementedError("GENSDRPHY only supports CAS LATENCY 2")
+               if nphases > 1:
+                       raise NotImplementedError("GENSDRPHY only supports Full Rate (nphases=1)")
+
+               a = flen(pads.a)
+               ba = flen(pads.ba)
+               d = flen(pads.dq)
+
+               self.phy_settings = lasmicon.PhySettings(
+                       memtype=memtype,
+                       dfi_d=d,
+                       nphases=nphases,
+                       rdphase=0,
+                       wrphase=0,
+                       rdcmdphase=0,
+                       wrcmdphase=0,
+                       cl=cl,
+                       read_latency=4,
+                       write_latency=0
+               )
+               
+               self.dfi = Interface(a, ba, nphases*d, nphases)
+
+               ###
+
+               # 
+               # Command/address
+               #
+               self.sync += [
+                       pads.a.eq(self.dfi.p0.address),
+                       pads.ba.eq(self.dfi.p0.bank),
+                       pads.cs_n.eq(self.dfi.p0.cs_n),
+                       pads.cke.eq(self.dfi.p0.cke),
+                       pads.cas_n.eq(self.dfi.p0.cas_n),
+                       pads.ras_n.eq(self.dfi.p0.ras_n),
+                       pads.we_n.eq(self.dfi.p0.we_n)
+               ]
+               if hasattr(pads, "cs_n"):
+                       self.sync += pads.cs_n.eq(self.dfi.p0.cs_n),
+
+               #
+               # DQ/DQS/DM data
+               #
+               sd_dq_out = Signal(d)
+               drive_dq = Signal()
+               self.sync += sd_dq_out.eq(self.dfi.p0.wrdata),
+               self.specials += Tristate(pads.dq, sd_dq_out, drive_dq)
+               self.comb += pads.dqm.eq(0)
+               sd_dq_in_ps = Signal(d)
+               self.sync.sys_ps += sd_dq_in_ps.eq(pads.dq)
+               self.sync += self.dfi.p0.rddata.eq(sd_dq_in_ps)
+
+               # 
+               # DQ/DM control
+               #
+               d_dfi_wrdata_en = Signal()
+               self.sync += d_dfi_wrdata_en.eq(self.dfi.p0.wrdata_en)
+               self.comb += drive_dq.eq(d_dfi_wrdata_en)
+
+               rddata_sr = Signal(4)
+               self.comb += self.dfi.p0.rddata_valid.eq(rddata_sr[0])
+               self.sync += rddata_sr.eq(Cat(self.dfi.p0.rddata_en, rddata_sr[1:]))
diff --git a/misoclib/sdramphy/initsequence.py b/misoclib/sdramphy/initsequence.py
new file mode 100644 (file)
index 0000000..cf76d4e
--- /dev/null
@@ -0,0 +1,146 @@
+from migen.fhdl.std import log2_int
+
+def get_sdram_phy_header(sdram_phy):
+       if sdram_phy.phy_settings.memtype not in ["SDR", "DDR", "LPDDR", "DDR2"]:
+               raise NotImplementedError("The SDRAM PHY header generator only supports SDR, DDR, LPDDR and DDR2")
+
+       r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n"
+       r += "#include <hw/common.h>\n#include <generated/csr.h>\n#include <hw/flags.h>\n\n"
+
+       r += "static void cdelay(int i);\n"
+
+       #
+       # commands_px functions
+       # 
+       for n in range(sdram_phy.phy_settings.nphases):
+               r += """
+static void command_p{n}(int cmd)
+{{
+       dfii_pi{n}_command_write(cmd);
+       dfii_pi{n}_command_issue_write(1);
+}}""".format(n=str(n))
+       r += "\n\n"
+
+       #
+       # rd/wr access macros
+       #
+       r += """
+#define dfii_pird_address_write(X) dfii_pi{rdphase}_address_write(X)
+#define dfii_piwr_address_write(X) dfii_pi{wrphase}_address_write(X)
+
+#define dfii_pird_baddress_write(X) dfii_pi{rdphase}_baddress_write(X)
+#define dfii_piwr_baddress_write(X) dfii_pi{wrphase}_baddress_write(X)
+
+#define command_prd(X) command_p{rdphase}(X)
+#define command_pwr(X) command_p{wrphase}(X)
+""".format(rdphase=str(sdram_phy.phy_settings.rdphase), wrphase=str(sdram_phy.phy_settings.wrphase)) 
+       r +="\n"
+       
+       #
+       # init sequence
+       # 
+       cmds = {
+               "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
+               "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
+               "AUTO_REFRESH"  : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS",
+               "CKE"           : "DFII_CONTROL_CKE"
+       }
+
+       def gen_cmd(comment, a, ba, cmd, delay):        
+               r = "\t/* {0} */\n".format(comment)
+               r += "\tdfii_pi0_address_write({0:#x});\n".format(a)
+               r += "\tdfii_pi0_baddress_write({0:d});\n".format(ba)
+               if "CKE" in cmd:
+                       r += "\tdfii_control_write({0});\n".format(cmd)
+               else:
+                       r += "\tcommand_p0({0});\n".format(cmd)
+               r += "\tcdelay({0:d});\n".format(delay)
+               r += "\n"
+               return r
+
+
+       r += "static void init_sequence(void)\n{\n"
+
+       cl = sdram_phy.phy_settings.cl
+       
+       if sdram_phy.phy_settings.memtype == "SDR":
+               bl = 1*sdram_phy.phy_settings.nphases
+               mr  = log2_int(bl) + (cl << 4)
+               reset_dll = 1 << 8
+
+               init_sequence = [
+                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+               ]
+
+       elif sdram_phy.phy_settings.memtype == "DDR":
+               bl = 2*sdram_phy.phy_settings.nphases
+               mr  = log2_int(bl) + (cl << 4)
+               emr = 0
+               reset_dll = 1 << 8
+
+               init_sequence = [
+                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
+                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+               ]
+
+       elif sdram_phy.phy_settings.memtype == "LPDDR":
+               bl = 2*sdram_phy.phy_settings.nphases
+               mr  = log2_int(bl) + (cl << 4)
+               emr = 0
+               reset_dll = 1 << 8
+
+               init_sequence = [
+                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0),
+                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+               ]
+
+       elif sdram_phy.phy_settings.memtype == "DDR2":
+               bl = 2*sdram_phy.phy_settings.nphases
+               wr = 2
+               mr  = log2_int(bl) + (cl << 4) + (wr << 9)
+               emr = 0
+               emr2 = 0
+               emr3 = 0
+               reset_dll = 1 << 8
+               ocd = 7 << 7
+
+               init_sequence = [
+                       ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+                       ("Precharge All",  0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0),
+                       ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0),
+                       ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
+                       ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+                       ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+                       ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200),
+                       ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0),
+                       ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0),
+               ]
+
+       for comment, a, ba, cmd, delay in init_sequence:
+               r += gen_cmd(comment, a, ba, cmd, delay)
+
+       r += "}\n"
+       r += "#endif\n"
+
+       return r
diff --git a/misoclib/sdramphy/s6ddrphy.py b/misoclib/sdramphy/s6ddrphy.py
new file mode 100644 (file)
index 0000000..7211ca0
--- /dev/null
@@ -0,0 +1,361 @@
+# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for Spartan-6
+# 
+# Assert dfi_wrdata_en and present the data 
+# on dfi_wrdata_mask/dfi_wrdata in the same
+# cycle as the write command.
+#
+# Assert dfi_rddata_en in the same cycle as the read
+# command. The data will come back on dfi_rddata
+# 5 cycles later, along with the assertion 
+# of dfi_rddata_valid.
+#
+# This PHY only supports CAS Latency 3.
+# Read commands must be sent on phase 0.
+# Write commands must be sent on phase 1.
+#
+
+from migen.fhdl.std import *
+from migen.bus.dfi import *
+from migen.genlib.record import *
+
+from misoclib import lasmicon
+
+class S6DDRPHY(Module):
+       def __init__(self, pads, memtype, nphases, cl, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
+               if memtype not in ["DDR", "LPDDR", "DDR2"]:
+                       raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2")
+               if cl != 3:
+                       raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3")
+               if nphases != 2:
+                       raise NotImplementedError("S6DDRPHY only supports Half Rate (nphases=2)")
+               a = flen(pads.a)
+               ba = flen(pads.ba)
+               d = flen(pads.dq)
+
+               self.phy_settings = lasmicon.PhySettings(
+                       memtype=memtype,
+                       dfi_d=2*d,
+                       nphases=nphases,
+                       rdphase=0,
+                       wrphase=1,
+                       rdcmdphase=1,
+                       wrcmdphase=0,
+                       cl=cl,
+                       read_latency=5,
+                       write_latency=0
+               )
+
+               self.dfi = Interface(a, ba, nphases*d, nphases)
+               self.clk4x_wr_strb = Signal()
+               self.clk4x_rd_strb = Signal()
+
+               ###
+
+               # sys_clk           : system clk, used for dfi interface
+               # sdram_half_clk    : half rate sdram clk
+               # sdram_full_wr_clk : full rate sdram write clk
+               # sdram_full_rd_clk : full rate sdram read clk
+               sd_sys = getattr(self.sync, "sys")
+               sd_sdram_half = getattr(self.sync, "sdram_half")
+
+               sys_clk = ClockSignal("sys")
+               sdram_half_clk = ClockSignal("sdram_half")
+               sdram_full_wr_clk = ClockSignal("sdram_full_wr")
+               sdram_full_rd_clk = ClockSignal("sdram_full_rd")
+
+               # 
+               # Command/address
+               #
+
+               # select active phase
+               #             sys_clk   ----____----____
+               #  phase_sel(nphases=2) 0   1   0   1     Half Rate
+               phase_sel = Signal(log2_int(nphases))
+               sys_clk_d = Signal()
+
+               sd_sdram_half += [
+                       If(sys_clk & ~sys_clk_d,
+                               phase_sel.eq(0)
+                       ).Else(
+                               phase_sel.eq(phase_sel+1)
+                       ),
+                       sys_clk_d.eq(sys_clk)
+               ]
+
+               # register dfi cmds on half_rate clk
+               r_dfi = Array(Record(phase_cmd_description(a, ba)) for i in range(nphases))
+               for n, phase in enumerate(self.dfi.phases):
+                       sd_sdram_half +=[
+                               r_dfi[n].address.eq(phase.address),
+                               r_dfi[n].bank.eq(phase.bank),
+                               r_dfi[n].cs_n.eq(phase.cs_n),
+                               r_dfi[n].cke.eq(phase.cke),
+                               r_dfi[n].cas_n.eq(phase.cas_n),
+                               r_dfi[n].ras_n.eq(phase.ras_n),
+                               r_dfi[n].we_n.eq(phase.we_n)
+                       ]
+
+               # output cmds
+               sd_sdram_half += [
+                       pads.a.eq(r_dfi[phase_sel].address),
+                       pads.ba.eq(r_dfi[phase_sel].bank),
+                       pads.cke.eq(r_dfi[phase_sel].cke),
+                       pads.ras_n.eq(r_dfi[phase_sel].ras_n),
+                       pads.cas_n.eq(r_dfi[phase_sel].cas_n),
+                       pads.we_n.eq(r_dfi[phase_sel].we_n)
+               ]
+               if hasattr(pads, "cs_n"):
+                       sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n)
+
+               # 
+               # Bitslip
+               #
+               bitslip_cnt = Signal(4)
+               bitslip_inc = Signal()
+
+               sd_sys += [
+                       If(bitslip_cnt == rd_bitslip,
+                               bitslip_inc.eq(0)
+                       ).Else(
+                               bitslip_cnt.eq(bitslip_cnt+1),
+                               bitslip_inc.eq(1)
+                       )
+               ]
+
+               # 
+               # DQ/DQS/DM data
+               #
+               sdram_half_clk_n = Signal()
+               self.comb += sdram_half_clk_n.eq(~sdram_half_clk)
+
+               postamble = Signal()
+               drive_dqs = Signal()
+               dqs_t_d0 = Signal()
+               dqs_t_d1 = Signal()
+
+               dqs_o = Signal(d//8) 
+               dqs_t = Signal(d//8)
+
+               self.comb += [
+                       dqs_t_d0.eq(~(drive_dqs | postamble)),
+                       dqs_t_d1.eq(~drive_dqs),
+               ]
+
+               for i in range(d//8):
+                       # DQS output
+                       self.specials += Instance("ODDR2",
+                               p_DDR_ALIGNMENT=dqs_ddr_alignment,
+                               p_INIT=0,
+                               p_SRTYPE="ASYNC",
+
+                               i_C0=sdram_half_clk,
+                               i_C1=sdram_half_clk_n,
+
+                               i_CE=1,
+                               i_D0=0,
+                               i_D1=1,
+                               i_R=0,
+                               i_S=0,
+
+                               o_Q=dqs_o[i]
+                       )
+
+                       # DQS tristate cmd
+                       self.specials += Instance("ODDR2",
+                               p_DDR_ALIGNMENT=dqs_ddr_alignment,
+                               p_INIT=0,
+                               p_SRTYPE="ASYNC",
+
+                               i_C0=sdram_half_clk,
+                               i_C1=sdram_half_clk_n,
+
+                               i_CE=1,
+                               i_D0=dqs_t_d0,
+                               i_D1=dqs_t_d1,
+                               i_R=0,
+                               i_S=0,
+
+                               o_Q=dqs_t[i]
+                       )
+
+                       # DQS tristate buffer
+                       if hasattr(pads, "dqs_n"):
+                               self.specials += Instance("OBUFTDS",
+                                       i_I=dqs_o[i],
+                                       i_T=dqs_t[i],
+
+                                       o_O=pads.dqs[i],
+                                       o_OB=pads.dqs_n[i],
+                               )
+                       else:
+                               self.specials += Instance("OBUFT",
+                                       i_I=dqs_o[i],
+                                       i_T=dqs_t[i],
+
+                                       o_O=pads.dqs[i]
+                               )
+
+               sd_sdram_half += postamble.eq(drive_dqs)
+
+               d_dfi = [Record(phase_wrdata_description(nphases*d)+phase_rddata_description(nphases*d)) 
+                       for i in range(2*nphases)]
+
+               for n, phase in enumerate(self.dfi.phases):
+                       self.comb += [
+                               d_dfi[n].wrdata.eq(phase.wrdata),
+                               d_dfi[n].wrdata_mask.eq(phase.wrdata_mask),
+                               d_dfi[n].wrdata_en.eq(phase.wrdata_en),
+                               d_dfi[n].rddata_en.eq(phase.rddata_en),
+                       ]
+                       sd_sys += [
+                               d_dfi[nphases+n].wrdata.eq(phase.wrdata),
+                               d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask)
+                       ]
+
+
+               drive_dq = Signal()
+               drive_dq_n = [Signal() for i in range(2)]
+               self.comb += drive_dq_n[0].eq(~drive_dq)
+               sd_sys += drive_dq_n[1].eq(drive_dq_n[0])
+
+               dq_t = Signal(d)
+               dq_o = Signal(d)
+               dq_i = Signal(d)
+
+               dq_wrdata = []
+               for i in range(2):
+                       for j in reversed(range(nphases)):
+                               dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:d])
+                               dq_wrdata.append(d_dfi[i*nphases+j].wrdata[d:])
+
+               for i in range(d):
+                       # Data serializer
+                       self.specials += Instance("OSERDES2",
+                               p_DATA_WIDTH=4,
+                               p_DATA_RATE_OQ="SDR",
+                               p_DATA_RATE_OT="SDR",
+                               p_SERDES_MODE="NONE",
+                               p_OUTPUT_MODE="SINGLE_ENDED",
+
+                               o_OQ=dq_o[i],
+                               i_OCE=1,
+                               i_CLK0=sdram_full_wr_clk,
+                               i_CLK1=0,
+                               i_IOCE=self.clk4x_wr_strb,
+                               i_RST=0,
+                               i_CLKDIV=sys_clk,
+
+                               i_D1=dq_wrdata[wr_bitslip+3][i],
+                               i_D2=dq_wrdata[wr_bitslip+2][i],
+                               i_D3=dq_wrdata[wr_bitslip+1][i],
+                               i_D4=dq_wrdata[wr_bitslip+0][i],
+
+                               o_TQ=dq_t[i],
+                               i_T1=drive_dq_n[(wr_bitslip+3)//4],
+                               i_T2=drive_dq_n[(wr_bitslip+2)//4],
+                               i_T3=drive_dq_n[(wr_bitslip+1)//4],
+                               i_T4=drive_dq_n[(wr_bitslip+0)//4],
+                               i_TRAIN=0,
+                               i_TCE=1,
+                               i_SHIFTIN1=0,
+                               i_SHIFTIN2=0,
+                               i_SHIFTIN3=0,
+                               i_SHIFTIN4=0,
+                       )
+
+                       # Data deserializer
+                       self.specials += Instance("ISERDES2",
+                               p_DATA_WIDTH=4,
+                               p_DATA_RATE="SDR",
+                               p_BITSLIP_ENABLE="TRUE",
+                               p_SERDES_MODE="NONE",
+                               p_INTERFACE_TYPE="RETIMED",
+
+                               i_D=dq_i[i],
+                               i_CE0=1,
+                               i_CLK0=sdram_full_rd_clk,
+                               i_CLK1=0,
+                               i_IOCE=self.clk4x_rd_strb,
+                               i_RST=ResetSignal(),
+                               i_CLKDIV=sys_clk,
+                               i_BITSLIP=bitslip_inc,
+
+                               o_Q1=d_dfi[0*nphases+0].rddata[i+d],
+                               o_Q2=d_dfi[0*nphases+0].rddata[i],
+                               o_Q3=d_dfi[0*nphases+1].rddata[i+d],
+                               o_Q4=d_dfi[0*nphases+1].rddata[i],
+                       )
+
+                       # Data buffer
+                       self.specials += Instance("IOBUF",
+                               i_I=dq_o[i],
+                               o_O=dq_i[i],
+                               i_T=dq_t[i],
+                               io_IO=pads.dq[i]
+                       )
+
+               dq_wrdata_mask = []
+               for i in range(2):
+                       for j in reversed(range(nphases)):
+                               dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:d//8])
+                               dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[d//8:])
+
+               for i in range(d//8):
+                       # Mask serializer
+                       self.specials += Instance("OSERDES2",
+                               p_DATA_WIDTH=4,
+                               p_DATA_RATE_OQ="SDR",
+                               p_DATA_RATE_OT="SDR",
+                               p_SERDES_MODE="NONE",
+                               p_OUTPUT_MODE="SINGLE_ENDED",
+
+                               o_OQ=pads.dm[i],
+                               i_OCE=1,
+                               i_CLK0=sdram_full_wr_clk,
+                               i_CLK1=0,
+                               i_IOCE=self.clk4x_wr_strb,
+                               i_RST=0,
+                               i_CLKDIV=sys_clk,
+
+                               i_D1=dq_wrdata_mask[wr_bitslip+3][i],
+                               i_D2=dq_wrdata_mask[wr_bitslip+2][i],
+                               i_D3=dq_wrdata_mask[wr_bitslip+1][i],
+                               i_D4=dq_wrdata_mask[wr_bitslip+0][i],
+
+                               i_TRAIN=0,
+                               i_TCE=0,
+                               i_SHIFTIN1=0,
+                               i_SHIFTIN2=0,
+                               i_SHIFTIN3=0,
+                               i_SHIFTIN4=0,
+                       )
+
+               #
+               # ODT
+               #
+               # ODT not yet supported
+               if hasattr(pads, "odt"):
+                       self.comb += pads.odt.eq(0)
+
+               # 
+               # DQ/DQS/DM control
+               #
+               self.comb += drive_dq.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
+
+               d_dfi_wrdata_en = Signal()
+               sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
+               
+               r_dfi_wrdata_en = Signal(2)
+               sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0])) 
+
+               self.comb += drive_dqs.eq(r_dfi_wrdata_en[1])
+
+               rddata_sr = Signal(self.phy_settings.read_latency)
+               sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.phy_settings.read_latency],
+                       d_dfi[self.phy_settings.rdphase].rddata_en))
+               
+               for n, phase in enumerate(self.dfi.phases):
+                       self.comb += [
+                               phase.rddata.eq(d_dfi[n].rddata),
+                               phase.rddata_valid.eq(rddata_sr[0]),
+                       ]
index 06b9f4c99ba309f6d127c7f611441014ac3f23e7..3c179c26f468d5952bfe030653586b748f4e004a 100644 (file)
@@ -4,7 +4,8 @@ from fractions import Fraction
 from migen.fhdl.std import *
 from mibuild.generic_platform import ConstraintError
 
-from misoclib import lasmicon, mxcrg, norflash16, s6ddrphy, minimac3, framebuffer, dvisampler, gpio
+from misoclib import lasmicon, mxcrg, norflash16, minimac3, framebuffer, dvisampler, gpio
+from misoclib.sdramphy import s6ddrphy
 from misoclib.gensoc import SDRAMSoC
 
 class _MXClockPads: