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():
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)
+++ /dev/null
-# 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]),
- ]
+++ /dev/null
-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
--- /dev/null
+#
+# 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:]))
--- /dev/null
+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
--- /dev/null
+# 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]),
+ ]
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: