TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG;
""")
- for d in ["mxcrg", "s6ddrphy", "minimac3"]:
+ for d in ["mxcrg", "minimac3"]:
platform.add_source_dir(os.path.join("verilog", d))
platform.add_sources(os.path.join("verilog", "lm32", "submodule", "rtl"),
"lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
if build_header:
csr_header = cif.get_csr_header(soc.csr_base, soc.csrbankarray, soc.interrupt_map)
write_to_file("software/include/hw/csr.h", csr_header)
+
+ sdram_phy_header = cif.get_sdram_phy_header(soc.ddrphy)
+ write_to_file("software/include/hw/sdram_phy.h", sdram_phy_header)
+
def main():
parser = argparse.ArgumentParser(description="milkymist-ng - a high performance SoC built on Migen technology.")
parser.add_argument("-p", "--platform", default="mixxeo", help="platform to build for")
parser.add_argument("-B", "--no-bitstream", default=False, action="store_true", help="do not build bitstream file")
- parser.add_argument("-H", "--no-header", default=False, action="store_true", help="do not build C header file with CSR/IRQ defs")
+ parser.add_argument("-H", "--no-header", default=False, action="store_true", help="do not build C header file with CSR/IRQ/SDRAM_PHY defs")
parser.add_argument("-l", "--load", default=False, action="store_true", help="load bitstream to SRAM")
parser.add_argument("-f", "--flash", default=False, action="store_true", help="load bitstream to flash")
args = parser.parse_args()
from operator import itemgetter
import re
+from migen.fhdl.std import *
from migen.bank.description import CSRStatus
def get_macros(filename):
r += "#define "+name.upper()+"_INTERRUPT "+str(interrupt_nr)+"\n"
r += "\n#endif\n"
return r
+
+def get_sdram_phy_header(sdram_phy):
+
+ if sdram_phy.phy_settings.type not in ["SDR", "DDR", "LPDDR", "DDR2"]:
+ raise NotImplementedError("sdram phy header generator only supports SDR, DDR, LPDDR and DDR2")
+
+ r = "#ifndef __HW_SDRAM_PHY_H\n#define __SDRAM_PHY_H\n"
+ r += "#include <hw/common.h>\n#include <hw/csr.h>\n#include <hw/flags.h>\n\n"
+
+ r += "extern 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/* %s */\n" %comment
+ r += "\tdfii_pi0_address_write(0x%04X);\n" %a
+ r += "\tdfii_pi0_baddress_write(%d);\n" %ba
+ if "CKE" in cmd:
+ r += "\tdfii_control_write(%s);\n" %cmd
+ else:
+ r += "\tcommand_p0(%s);\n" %cmd
+ r += "\tcdelay(%d);\n" %delay
+ r += "\n"
+ return r
+
+
+ r += "static void init_sequence(void) {\n"
+
+ cl = sdram_phy.phy_settings.cl
+
+ if sdram_phy.phy_settings.type == "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=%d, BL=%d" %(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),
+ ("Load Mode Register / CL=%d, BL=%d" %(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.type == "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=%d, BL=%d" %(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),
+ ("Load Mode Register / CL=%d, BL=%d" %(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.type == "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=%d, BL=%d" %(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),
+ ("Load Mode Register / CL=%d, BL=%d" %(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.type == "DDR2":
+ 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=%d, BL=%d" %(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),
+ ("Load Mode Register / CL=%d, BL=%d" %(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ for comment, a, ba, cmd, delay in init_sequence:
+ r += gen_cmd(comment, a, ba, cmd, delay)
+
+ r += "}\n"
+ r += "#endif\n"
+
+ return r
from milkymist.lasmicon.bankmachine import *
from milkymist.lasmicon.multiplexer import *
-PhySettings = namedtuple("PhySettings", "dfi_d nphases rdphase wrphase")
+PhySettings = namedtuple("PhySettings", "type dfi_d nphases rdphase wrphase cl")
class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")):
def __init__(self, *args, **kwargs):
class MXCRG(Module, AutoCSR):
def __init__(self, pads, outfreq1x):
self.clock_domains.cd_sys = ClockDomain()
- self.clock_domains.cd_sys2x_270 = ClockDomain()
- self.clock_domains.cd_sys4x_wr = ClockDomain()
- self.clock_domains.cd_sys4x_rd = ClockDomain()
+ self.clock_domains.cd_sdram_half = ClockDomain()
+ self.clock_domains.cd_sdram_full_wr = ClockDomain()
+ self.clock_domains.cd_sdram_full_rd = ClockDomain()
self.clock_domains.cd_eth_rx = ClockDomain()
self.clock_domains.cd_eth_tx = ClockDomain()
self.clock_domains.cd_vga = ClockDomain(reset_less=True)
Instance.Output("sys_clk", self.cd_sys.clk),
Instance.Output("sys_rst", self.cd_sys.rst),
- Instance.Output("clk2x_270", self.cd_sys2x_270.clk),
- Instance.Output("clk4x_wr", self.cd_sys4x_wr.clk),
- Instance.Output("clk4x_rd", self.cd_sys4x_rd.clk),
+ Instance.Output("clk2x_270", self.cd_sdram_half.clk),
+ Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk),
+ Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk),
Instance.Output("eth_rx_clk", self.cd_eth_rx.clk),
Instance.Output("eth_tx_clk", self.cd_eth_tx.clk),
Instance.Output("vga_clk", self.cd_vga.clk),
+#
+# 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
+# CL + 2 cycles later, along with the assertion
+# of dfi_rddata_valid.
+#
+# This PHY supports configurable CAS Latency.
+# Read commands must be sent on phase RDPHASE.
+# Write commands must be sent on phase WRPHASE.
+#/
+
+# Todo:
+# - use CSR for bitslip?
+# - move sdram clk generation to phy?
+
from migen.fhdl.std import *
-from migen.bus import dfi
+from migen.bus.dfi import *
+from migen.genlib.record import *
class S6DDRPHY(Module):
- def __init__(self, pads):
- self.dfi = dfi.Interface(flen(pads.a), flen(pads.ba), 2*flen(pads.dq), 2)
+ def __init__(self, pads, phy_settings, bitslip):
+
+ if phy_settings.type not in ["DDR", "LPDDR", "DDR2"]:
+ raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2")
+
+ a = flen(pads.a)
+ ba = flen(pads.ba)
+ d = flen(pads.dq)
+ nphases = phy_settings.nphases
+ self.phy_settings = phy_settings
+
+ self.dfi = Interface(a, ba, nphases*d, nphases)
self.clk4x_wr_strb = Signal()
self.clk4x_rd_strb = Signal()
###
- inst_items = [
- Instance.Parameter("NUM_AD", flen(pads.a)),
- Instance.Parameter("NUM_BA", flen(pads.ba)),
- Instance.Parameter("NUM_D", 2*flen(pads.dq)),
-
- Instance.Input("sys_clk", ClockSignal()),
- Instance.Input("clk2x_270", ClockSignal("sys2x_270")),
- Instance.Input("clk4x_wr", ClockSignal("sys4x_wr")),
- Instance.Input("clk4x_rd", ClockSignal("sys4x_rd")),
-
- Instance.Input("clk4x_wr_strb", self.clk4x_wr_strb),
- Instance.Input("clk4x_rd_strb", self.clk4x_rd_strb),
-
- Instance.Output("sd_a", pads.a),
- Instance.Output("sd_ba", pads.ba),
- Instance.Output("sd_cs_n", pads.cs_n),
- Instance.Output("sd_cke", pads.cke),
- Instance.Output("sd_ras_n", pads.ras_n),
- Instance.Output("sd_cas_n", pads.cas_n),
- Instance.Output("sd_we_n", pads.we_n),
- Instance.InOut("sd_dq", pads.dq),
- Instance.Output("sd_dm", pads.dm),
- Instance.InOut("sd_dqs", pads.dqs)
+ # 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 write clk
+ sd_sys = getattr(self.sync, "sys")
+ sd_sdram_half = getattr(self.sync, "sdram_half")
+ sd_sdram_full_wr = getattr(self.sync, "sdram_full_wr")
+ sd_sdram_full_rd = getattr(self.sync, "sdram_full_rd")
+
+ 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.cs_n.eq(r_dfi[phase_sel].cs_n),
+ 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)
+ ]
+
+
+ #
+ # Bitslip
+ #
+ bitslip_cnt = Signal(4)
+ bitslip_inc = Signal()
+
+ sd_sys +=[
+ If(bitslip_cnt==bitslip,
+ bitslip_inc.eq(0)
+ ).Else(
+ bitslip_cnt.eq(bitslip_cnt+1),
+ bitslip_inc.eq(1)
+ )
]
- inst_items += [Instance.Input(name, signal)
- for name, signal in self.dfi.get_standard_names(True, False)]
- inst_items += [Instance.Output(name, signal)
- for name, signal in self.dfi.get_standard_names(False, True)]
- self.specials += Instance("s6ddrphy", *inst_items)
+
+ #
+ # DQ/DQS/DM data
+ #
+ sdram_half_clk_n = Signal()
+ self.comb += sdram_half_clk_n.eq(~sdram_half_clk)
+
+ postamble, drive_dqs, dqs_t_d0, dqs_t_d1 = (Signal() for i in range(4))
+
+ 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",
+ Instance.Parameter("DDR_ALIGNMENT", "C1"),
+ Instance.Parameter("INIT", 0),
+ Instance.Parameter("SRTYPE", "ASYNC"),
+
+ Instance.Input("C0", sdram_half_clk),
+ Instance.Input("C1", sdram_half_clk_n),
+
+ Instance.Input("CE", 1),
+ Instance.Input("D0", 0),
+ Instance.Input("D1", 1),
+ Instance.Input("R", 0),
+ Instance.Input("S", 0),
+
+ Instance.Output("Q", dqs_o[i])
+ )
+
+ # DQS tristate cmd
+ self.specials += Instance("ODDR2",
+ Instance.Parameter("DDR_ALIGNMENT", "C1"),
+ Instance.Parameter("INIT", 0),
+ Instance.Parameter("SRTYPE", "ASYNC"),
+
+ Instance.Input("C0", sdram_half_clk),
+ Instance.Input("C1", sdram_half_clk_n),
+
+ Instance.Input("CE", 1),
+ Instance.Input("D0", dqs_t_d0),
+ Instance.Input("D1", dqs_t_d1),
+ Instance.Input("R", 0),
+ Instance.Input("S", 0),
+
+ Instance.Output("Q", dqs_t[i])
+ )
+
+ # DQS tristate buffer
+ self.specials += Instance("OBUFT",
+ Instance.Input("I", dqs_o[i]),
+ Instance.Input("T", dqs_t[i]),
+
+ Instance.Output("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, drive_dq_n, d_drive_dq, d_drive_dq_n = (Signal() for i in range(4))
+ self.comb +=[
+ drive_dq_n.eq(~drive_dq),
+ d_drive_dq_n.eq(~d_drive_dq)
+ ]
+
+ dq_t, dq_o, dq_i = (Signal(d) for i in range(3))
+
+ for i in range(d):
+
+ # Data serializer
+ self.specials += Instance("OSERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE_OQ", "SDR"),
+ Instance.Parameter("DATA_RATE_OT", "SDR"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
+
+ Instance.Output("OQ", dq_o[i]),
+ Instance.Input("OCE", 1),
+ Instance.Input("CLK0", sdram_full_wr_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_wr_strb),
+ Instance.Input("RST", 0),
+ Instance.Input("CLKDIV", sys_clk),
+
+ Instance.Input("D1", d_dfi[1*nphases+0].wrdata[i]),
+ Instance.Input("D2", d_dfi[1*nphases+1].wrdata[i+d]),
+ Instance.Input("D3", d_dfi[1*nphases+1].wrdata[i]),
+ Instance.Input("D4", d_dfi[0*nphases+0].wrdata[i+d]),
+ Instance.Output("TQ", dq_t[i]),
+ Instance.Input("T1", d_drive_dq_n),
+ Instance.Input("T2", d_drive_dq_n),
+ Instance.Input("T3", d_drive_dq_n),
+ Instance.Input("T4", drive_dq_n),
+ Instance.Input("TRAIN", 0),
+ Instance.Input("TCE", 1),
+ Instance.Input("SHIFTIN1", 0),
+ Instance.Input("SHIFTIN2", 0),
+ Instance.Input("SHIFTIN3", 0),
+ Instance.Input("SHIFTIN4", 0),
+
+ Instance.Output("SHIFTOUT1"),
+ Instance.Output("SHIFTOUT2"),
+ Instance.Output("SHIFTOUT3"),
+ Instance.Output("SHIFTOUT4"),
+ )
+
+ # Data deserializer
+ self.specials += Instance("ISERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE", "SDR"),
+ Instance.Parameter("BITSLIP_ENABLE", "TRUE"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
+
+ Instance.Input("D", dq_i[i]),
+ Instance.Input("CE0", 1),
+ Instance.Input("CLK0", sdram_full_rd_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_rd_strb),
+ Instance.Input("RST", ResetSignal()),
+ Instance.Input("CLKDIV", sys_clk),
+ Instance.Output("SHIFTIN"),
+ Instance.Input("BITSLIP", bitslip_inc),
+ Instance.Output("FABRICOUT"),
+
+ Instance.Output("Q1", d_dfi[0*nphases+0].rddata[i+d]),
+ Instance.Output("Q2", d_dfi[0*nphases+0].rddata[i]),
+ Instance.Output("Q3", d_dfi[0*nphases+1].rddata[i+d]),
+ Instance.Output("Q4", d_dfi[0*nphases+1].rddata[i]),
+
+ Instance.Output("DFB"),
+ Instance.Output("CFB0"),
+ Instance.Output("CFB1"),
+ Instance.Output("VALID"),
+ Instance.Output("INCDEC"),
+ Instance.Output("SHIFTOUT")
+ )
+
+ # Data buffer
+ self.specials += Instance("IOBUF",
+ Instance.Input("I", dq_o[i]),
+ Instance.Output("O", dq_i[i]),
+ Instance.Input("T", dq_t[i]),
+ Instance.InOut("IO", pads.dq[i])
+ )
+
+ for i in range(d//8):
+
+ # Mask serializer
+ self.specials += Instance("OSERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE_OQ", "SDR"),
+ Instance.Parameter("DATA_RATE_OT", "SDR"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
+
+ Instance.Output("OQ", pads.dm[i]),
+ Instance.Input("OCE", 1),
+ Instance.Input("CLK0", sdram_full_wr_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_wr_strb),
+ Instance.Input("RST", 0),
+ Instance.Input("CLKDIV", sys_clk),
+
+ Instance.Input("D1", d_dfi[1*nphases+0].wrdata_mask[i]),
+ Instance.Input("D2", d_dfi[1*nphases+1].wrdata_mask[i+d//8]),
+ Instance.Input("D3", d_dfi[1*nphases+1].wrdata_mask[i]),
+ Instance.Input("D4", d_dfi[0*nphases+0].wrdata_mask[i+d//8]),
+ Instance.Output("TQ"),
+ Instance.Input("T1"),
+ Instance.Input("T2"),
+ Instance.Input("T3"),
+ Instance.Input("T4"),
+ Instance.Input("TRAIN", 0),
+ Instance.Input("TCE", 0),
+ Instance.Input("SHIFTIN1", 0),
+ Instance.Input("SHIFTIN2", 0),
+ Instance.Input("SHIFTIN3", 0),
+ Instance.Input("SHIFTIN4", 0),
+
+ Instance.Output("SHIFTOUT1"),
+ Instance.Output("SHIFTOUT2"),
+ Instance.Output("SHIFTOUT3"),
+ Instance.Output("SHIFTOUT4"),
+ )
+
+
+ #
+ # DQ/DQS/DM control
+ #
+ self.comb += drive_dq.eq(d_dfi[phy_settings.wrphase].wrdata_en)
+ sd_sys += d_drive_dq.eq(drive_dq)
+
+
+ d_dfi_wrdata_en = Signal()
+ sd_sys += d_dfi_wrdata_en.eq(d_dfi[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(phy_settings.cl+2)
+ sd_sys += rddata_sr.eq(Cat(rddata_sr[1:phy_settings.cl+2], d_dfi[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]),
+ ]
#include <stdlib.h>
#include <hw/csr.h>
+#include <hw/sdram_phy.h>
#include <hw/flags.h>
#include <hw/mem.h>
#include "sdram.h"
-static void cdelay(int i)
+void cdelay(int i)
{
while(i > 0) {
__asm__ volatile("nop");
}
}
-static void command_p0(int cmd)
-{
- dfii_pi0_command_write(cmd);
- dfii_pi0_command_issue_write(1);
-}
-
-static void command_p1(int cmd)
-{
- dfii_pi1_command_write(cmd);
- dfii_pi1_command_issue_write(1);
-}
-
-static void init_sequence(void)
-{
- int i;
-
- /* Bring CKE high */
- dfii_pi0_address_write(0x0000);
- dfii_pi0_baddress_write(0);
- dfii_control_write(DFII_CONTROL_CKE);
-
- /* Precharge All */
- dfii_pi0_address_write(0x0400);
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-
- /* Load Extended Mode Register */
- dfii_pi0_baddress_write(1);
- dfii_pi0_address_write(0x0000);
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
- dfii_pi0_baddress_write(0);
-
- /* Load Mode Register */
- dfii_pi0_address_write(0x0132); /* Reset DLL, CL=3, BL=4 */
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
- cdelay(200);
-
- /* Precharge All */
- dfii_pi0_address_write(0x0400);
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-
- /* 2x Auto Refresh */
- for(i=0;i<2;i++) {
- dfii_pi0_address_write(0);
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS);
- cdelay(4);
- }
-
- /* Load Mode Register */
- dfii_pi0_address_write(0x0032); /* CL=3, BL=4 */
- command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
- cdelay(200);
-}
-
void ddrsw(void)
{
dfii_control_write(DFII_CONTROL_CKE);
return;
}
- dfii_pi0_address_write(addr);
- dfii_pi0_baddress_write(0);
- command_p0(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
+ dfii_pird_address_write(addr);
+ dfii_pird_baddress_write(0);
+ command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15);
for(i=0;i<8;i++)
MMPTR(0xe000106c+4*i) = 0xf0 + i;
}
- dfii_pi1_address_write(addr);
- dfii_pi1_baddress_write(0);
- command_p1(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
+ dfii_piwr_address_write(addr);
+ dfii_piwr_baddress_write(0);
+ command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
}
#define TEST_SIZE (4*1024*1024)
return ceil(t/clk_period_ns)
sdram_phy = lasmicon.PhySettings(
+ type="DDR",
dfi_d=64,
nphases=2,
rdphase=0,
- wrphase=1
+ wrphase=1,
+ cl=3
)
sdram_geom = lasmicon.GeomSettings(
bank_a=2,
#
# DFI
#
- self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"))
+ self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), sdram_phy, 0)
self.submodules.dfii = dfii.DFIInjector(sdram_geom.mux_a, sdram_geom.bank_a, sdram_phy.dfi_d,
sdram_phy.nphases)
self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, self.ddrphy.dfi)
+++ /dev/null
-/*
- * 1:2 frequency-ratio DDR 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.
- */
-
-module s6ddrphy #(
- parameter NUM_AD = 0,
- parameter NUM_BA = 0,
- parameter NUM_D = 0 /* < number of data lines per DFI phase */
-) (
- /* Clocks */
- input sys_clk,
- input clk2x_270,
- input clk4x_wr,
- input clk4x_wr_strb,
- input clk4x_rd,
- input clk4x_rd_strb,
-
- /* DFI phase 0 */
- input [NUM_AD-1:0] dfi_address_p0,
- input [NUM_BA-1:0] dfi_bank_p0,
- input dfi_cs_n_p0,
- input dfi_cke_p0,
- input dfi_ras_n_p0,
- input dfi_cas_n_p0,
- input dfi_we_n_p0,
- input dfi_wrdata_en_p0,
- input [NUM_D/8-1:0] dfi_wrdata_mask_p0,
- input [NUM_D-1:0] dfi_wrdata_p0,
- input dfi_rddata_en_p0,
- output [NUM_D-1:0] dfi_rddata_w0,
- output dfi_rddata_valid_w0,
-
- /* DFI phase 1 */
- input [NUM_AD-1:0] dfi_address_p1,
- input [NUM_BA-1:0] dfi_bank_p1,
- input dfi_cs_n_p1,
- input dfi_cke_p1,
- input dfi_ras_n_p1,
- input dfi_cas_n_p1,
- input dfi_we_n_p1,
- input dfi_wrdata_en_p1,
- input [NUM_D/8-1:0] dfi_wrdata_mask_p1,
- input [NUM_D-1:0] dfi_wrdata_p1,
- input dfi_rddata_en_p1,
- output [NUM_D-1:0] dfi_rddata_w1,
- output dfi_rddata_valid_w1,
-
- /* DDR SDRAM pads */
- output reg [NUM_AD-1:0] sd_a,
- output reg [NUM_BA-1:0] sd_ba,
- output reg sd_cs_n,
- output reg sd_cke,
- output reg sd_ras_n,
- output reg sd_cas_n,
- output reg sd_we_n,
- inout [NUM_D/2-1:0] sd_dq,
- output [NUM_D/16-1:0] sd_dm,
- inout [NUM_D/16-1:0] sd_dqs
-);
-
-/*
- * Command/address
- */
-
-reg phase_sel;
-always @(posedge clk2x_270)
- phase_sel <= sys_clk;
-
-reg [NUM_AD-1:0] r_dfi_address_p0;
-reg [NUM_BA-1:0] r_dfi_bank_p0;
-reg r_dfi_cs_n_p0;
-reg r_dfi_cke_p0;
-reg r_dfi_ras_n_p0;
-reg r_dfi_cas_n_p0;
-reg r_dfi_we_n_p0;
-reg [NUM_AD-1:0] r_dfi_address_p1;
-reg [NUM_BA-1:0] r_dfi_bank_p1;
-reg r_dfi_cs_n_p1;
-reg r_dfi_cke_p1;
-reg r_dfi_ras_n_p1;
-reg r_dfi_cas_n_p1;
-reg r_dfi_we_n_p1;
-
-always @(posedge clk2x_270) begin
- r_dfi_address_p0 <= dfi_address_p0;
- r_dfi_bank_p0 <= dfi_bank_p0;
- r_dfi_cs_n_p0 <= dfi_cs_n_p0;
- r_dfi_cke_p0 <= dfi_cke_p0;
- r_dfi_ras_n_p0 <= dfi_ras_n_p0;
- r_dfi_cas_n_p0 <= dfi_cas_n_p0;
- r_dfi_we_n_p0 <= dfi_we_n_p0;
-
- r_dfi_address_p1 <= dfi_address_p1;
- r_dfi_bank_p1 <= dfi_bank_p1;
- r_dfi_cs_n_p1 <= dfi_cs_n_p1;
- r_dfi_cke_p1 <= dfi_cke_p1;
- r_dfi_ras_n_p1 <= dfi_ras_n_p1;
- r_dfi_cas_n_p1 <= dfi_cas_n_p1;
- r_dfi_we_n_p1 <= dfi_we_n_p1;
-end
-
-always @(posedge clk2x_270) begin
- if(phase_sel) begin
- sd_a <= r_dfi_address_p0;
- sd_ba <= r_dfi_bank_p0;
- sd_cs_n <= r_dfi_cs_n_p0;
- sd_cke <= r_dfi_cke_p0;
- sd_ras_n <= r_dfi_ras_n_p0;
- sd_cas_n <= r_dfi_cas_n_p0;
- sd_we_n <= r_dfi_we_n_p0;
- end else begin
- sd_a <= r_dfi_address_p1;
- sd_ba <= r_dfi_bank_p1;
- sd_cs_n <= r_dfi_cs_n_p1;
- sd_cke <= r_dfi_cke_p1;
- sd_ras_n <= r_dfi_ras_n_p1;
- sd_cas_n <= r_dfi_cas_n_p1;
- sd_we_n <= r_dfi_we_n_p1;
- end
-end
-
-/*
- * DQ/DQS/DM data
- */
-
-genvar i;
-
-wire drive_dqs;
-wire [NUM_D/16-1:0] dqs_o;
-wire [NUM_D/16-1:0] dqs_t;
-reg postamble;
-generate
- for(i=0;i<NUM_D/16;i=i+1)
- begin: gen_dqs
- ODDR2 #(
- .DDR_ALIGNMENT("C1"),
- .INIT(1'b0),
- .SRTYPE("ASYNC")
- ) dqs_o_oddr (
- .Q(dqs_o[i]),
- .C0(clk2x_270),
- .C1(~clk2x_270),
- .CE(1'b1),
- .D0(1'b0),
- .D1(1'b1),
- .R(1'b0),
- .S(1'b0)
- );
- ODDR2 #(
- .DDR_ALIGNMENT("C1"),
- .INIT(1'b0),
- .SRTYPE("ASYNC")
- ) dqs_t_oddr (
- .Q(dqs_t[i]),
- .C0(clk2x_270),
- .C1(~clk2x_270),
- .CE(1'b1),
- .D0(~(drive_dqs | postamble)),
- .D1(~drive_dqs),
- .R(1'b0),
- .S(1'b0)
- );
- OBUFT dqs_obuft(
- .I(dqs_o[i]),
- .T(dqs_t[i]),
- .O(sd_dqs[i])
- );
- end
-endgenerate
-always @(posedge clk2x_270)
- postamble <= drive_dqs;
-
-reg [NUM_D-1:0] d_dfi_wrdata_p0;
-reg [NUM_D-1:0] d_dfi_wrdata_p1;
-reg [NUM_D/8-1:0] d_dfi_wrdata_mask_p0;
-reg [NUM_D/8-1:0] d_dfi_wrdata_mask_p1;
-always @(posedge sys_clk) begin
- d_dfi_wrdata_p0 <= dfi_wrdata_p0;
- d_dfi_wrdata_p1 <= dfi_wrdata_p1;
- d_dfi_wrdata_mask_p0 <= dfi_wrdata_mask_p0;
- d_dfi_wrdata_mask_p1 <= dfi_wrdata_mask_p1;
-end
-
-wire drive_dq;
-wire d_drive_dq;
-wire [NUM_D/2-1:0] dq_i;
-wire [NUM_D/2-1:0] dq_o;
-wire [NUM_D/2-1:0] dq_t;
-generate
- for(i=0;i<NUM_D/2;i=i+1)
- begin: gen_dq
- OSERDES2 #(
- .DATA_WIDTH(4),
- .DATA_RATE_OQ("SDR"),
- .DATA_RATE_OT("SDR"),
- .SERDES_MODE("NONE"),
- .OUTPUT_MODE("SINGLE_ENDED")
- ) dq_oserdes (
- .OQ(dq_o[i]),
- .OCE(1'b1),
- .CLK0(clk4x_wr),
- .CLK1(1'b0),
- .IOCE(clk4x_wr_strb),
- .RST(1'b0),
- .CLKDIV(sys_clk),
- .D1(d_dfi_wrdata_p0[i]),
- .D2(d_dfi_wrdata_p1[i+NUM_D/2]),
- .D3(d_dfi_wrdata_p1[i]),
- .D4(dfi_wrdata_p0[i+NUM_D/2]),
- .TQ(dq_t[i]),
- .T1(~d_drive_dq),
- .T2(~d_drive_dq),
- .T3(~d_drive_dq),
- .T4(~drive_dq),
- .TRAIN(1'b0),
- .TCE(1'b1),
- .SHIFTIN1(1'b0),
- .SHIFTIN2(1'b0),
- .SHIFTIN3(1'b0),
- .SHIFTIN4(1'b0),
- .SHIFTOUT1(),
- .SHIFTOUT2(),
- .SHIFTOUT3(),
- .SHIFTOUT4()
- );
- ISERDES2 #(
- .DATA_WIDTH(4),
- .DATA_RATE("SDR"),
- .BITSLIP_ENABLE("FALSE"),
- .SERDES_MODE("NONE"),
- .INTERFACE_TYPE("RETIMED")
- ) dq_iserdes (
- .D(dq_i[i]),
- .CE0(1'b1),
- .CLK0(clk4x_rd),
- .CLK1(1'b0),
- .IOCE(clk4x_rd_strb),
- .RST(1'b0),
- .CLKDIV(sys_clk),
- .SHIFTIN(),
- .BITSLIP(1'b0),
- .FABRICOUT(),
- .Q1(dfi_rddata_w0[i+NUM_D/2]),
- .Q2(dfi_rddata_w0[i]),
- .Q3(dfi_rddata_w1[i+NUM_D/2]),
- .Q4(dfi_rddata_w1[i]),
- .DFB(),
- .CFB0(),
- .CFB1(),
- .VALID(),
- .INCDEC(),
- .SHIFTOUT()
- );
- IOBUF dq_iobuf(
- .I(dq_o[i]),
- .O(dq_i[i]),
- .T(dq_t[i]),
- .IO(sd_dq[i])
- );
- end
-endgenerate
-
-generate
- for(i=0;i<NUM_D/16;i=i+1)
- begin: gen_dm_oserdes
- OSERDES2 #(
- .DATA_WIDTH(4),
- .DATA_RATE_OQ("SDR"),
- .DATA_RATE_OT("SDR"),
- .SERDES_MODE("NONE"),
- .OUTPUT_MODE("SINGLE_ENDED")
- ) dm_oserdes (
- .OQ(sd_dm[i]),
- .OCE(1'b1),
- .CLK0(clk4x_wr),
- .CLK1(1'b0),
- .IOCE(clk4x_wr_strb),
- .RST(1'b0),
- .CLKDIV(sys_clk),
- .D1(d_dfi_wrdata_mask_p0[i]),
- .D2(d_dfi_wrdata_mask_p1[i+NUM_D/16]),
- .D3(d_dfi_wrdata_mask_p1[i]),
- .D4(dfi_wrdata_mask_p0[i+NUM_D/16]),
- .TQ(),
- .T1(),
- .T2(),
- .T3(),
- .T4(),
- .TRAIN(1'b0),
- .TCE(1'b0),
- .SHIFTIN1(1'b0),
- .SHIFTIN2(1'b0),
- .SHIFTIN3(1'b0),
- .SHIFTIN4(1'b0),
- .SHIFTOUT1(),
- .SHIFTOUT2(),
- .SHIFTOUT3(),
- .SHIFTOUT4()
- );
- end
-endgenerate
-
-/*
- * DQ/DQS/DM control
- */
-
-reg d_dfi_wrdata_en_p1;
-always @(posedge sys_clk)
- d_dfi_wrdata_en_p1 <= dfi_wrdata_en_p1;
-
-assign drive_dq = dfi_wrdata_en_p1;
-assign d_drive_dq = d_dfi_wrdata_en_p1;
-
-reg r_dfi_wrdata_en;
-reg r2_dfi_wrdata_en;
-always @(posedge clk2x_270) begin
- r_dfi_wrdata_en <= d_dfi_wrdata_en_p1;
- r2_dfi_wrdata_en <= r_dfi_wrdata_en;
-end
-
-assign drive_dqs = r2_dfi_wrdata_en;
-
-wire rddata_valid;
-reg [4:0] rddata_sr;
-assign dfi_rddata_valid_w0 = rddata_sr[0];
-assign dfi_rddata_valid_w1 = rddata_sr[0];
-always @(posedge sys_clk)
- rddata_sr <= {dfi_rddata_en_p0, rddata_sr[4:1]};
-
-endmodule