diff --git a/milkymist/cif.py b/milkymist/cif.py index d040ccdd5..bc5eb13da 100644 --- a/milkymist/cif.py +++ b/milkymist/cif.py @@ -67,7 +67,7 @@ def get_csr_header(csr_base, bank_array, interrupt_map): return r def get_sdram_phy_header(sdram_phy): - if sdram_phy.phy_settings.type not in ["SDR", "DDR", "LPDDR", "DDR2"]: + 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 __HW_SDRAM_PHY_H\n#define __HW_SDRAM_PHY_H\n" @@ -129,7 +129,7 @@ static void command_p{n}(int cmd) cl = sdram_phy.phy_settings.cl - if sdram_phy.phy_settings.type == "SDR": + if sdram_phy.phy_settings.memtype == "SDR": bl = 1*sdram_phy.phy_settings.nphases mr = log2_int(bl) + (cl << 4) reset_dll = 1 << 8 @@ -144,7 +144,7 @@ static void command_p{n}(int cmd) ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) ] - elif sdram_phy.phy_settings.type == "DDR": + elif sdram_phy.phy_settings.memtype == "DDR": bl = 2*sdram_phy.phy_settings.nphases mr = log2_int(bl) + (cl << 4) emr = 0 @@ -161,7 +161,7 @@ static void command_p{n}(int cmd) ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) ] - elif sdram_phy.phy_settings.type == "LPDDR": + elif sdram_phy.phy_settings.memtype == "LPDDR": bl = 2*sdram_phy.phy_settings.nphases mr = log2_int(bl) + (cl << 4) emr = 0 @@ -178,7 +178,7 @@ static void command_p{n}(int cmd) ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) ] - elif sdram_phy.phy_settings.type == "DDR2": + elif sdram_phy.phy_settings.memtype == "DDR2": bl = 2*sdram_phy.phy_settings.nphases mr = log2_int(bl) + (cl << 4) emr = 0 diff --git a/milkymist/lasmicon/__init__.py b/milkymist/lasmicon/__init__.py index f0a389994..ffcb8e3a1 100644 --- a/milkymist/lasmicon/__init__.py +++ b/milkymist/lasmicon/__init__.py @@ -7,14 +7,13 @@ from milkymist.lasmicon.refresher import * from milkymist.lasmicon.bankmachine import * from milkymist.lasmicon.multiplexer import * -PhySettings = namedtuple("PhySettings", "type dfi_d nphases rdphase wrphase cl") +PhySettings = namedtuple("PhySettings", "memtype dfi_d nphases rdphase wrphase cl read_latency write_latency") class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")): def __init__(self, *args, **kwargs): self.mux_a = max(self.row_a, self.col_a) TimingSettings = namedtuple("TimingSettings", "tRP tRCD tWR tWTR tREFI tRFC" \ - " read_latency write_latency" \ " req_queue_size read_time write_time") class LASMIcon(Module): @@ -31,8 +30,8 @@ class LASMIcon(Module): dw=phy_settings.dfi_d*phy_settings.nphases, nbanks=2**geom_settings.bank_a, req_queue_size=timing_settings.req_queue_size, - read_latency=timing_settings.read_latency+1, - write_latency=timing_settings.write_latency+1) + read_latency=phy_settings.read_latency+1, + write_latency=phy_settings.write_latency+1) self.nrowbits = geom_settings.col_a - address_align ### diff --git a/milkymist/lasmicon/multiplexer.py b/milkymist/lasmicon/multiplexer.py index 27978f941..d0cfa48b1 100644 --- a/milkymist/lasmicon/multiplexer.py +++ b/milkymist/lasmicon/multiplexer.py @@ -178,7 +178,7 @@ class Multiplexer(Module, AutoCSR): steerer.sel[0].eq(STEER_REFRESH), If(~refresher.req, NextState("READ")) ) - fsm.delayed_enter("RTW", "WRITE", timing_settings.read_latency-1) + fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1) # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog fsm.finalize() diff --git a/milkymist/s6ddrphy/__init__.py b/milkymist/s6ddrphy/__init__.py index aa88c2ac6..e137b543a 100644 --- a/milkymist/s6ddrphy/__init__.py +++ b/milkymist/s6ddrphy/__init__.py @@ -1,4 +1,3 @@ -# # 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for # Spartan-6 # @@ -12,37 +11,42 @@ # of dfi_rddata_valid. # # This PHY only supports CAS Latency 3. -# Read commands must be sent on phase RDPHASE. -# Write commands must be sent on phase WRPHASE. -#/ +# 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 according to phy_settings +# - automatically determines wrphase / rdphase / latencies from migen.fhdl.std import * from migen.bus.dfi import * from migen.genlib.record import * -def get_latencies(phy_settings): - read_latency=5 - write_latency=0 - return read_latency, write_latency - +from milkymist import lasmicon + class S6DDRPHY(Module): - def __init__(self, pads, phy_settings, bitslip): - if phy_settings.type not in ["DDR", "LPDDR", "DDR2"]: + def __init__(self, pads, memtype, nphases, cl, bitslip): + if memtype not in ["DDR", "LPDDR", "DDR2"]: raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2") - if phy_settings.cl != 3: - raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3 for now") + if cl != 3: + raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3") a = flen(pads.a) ba = flen(pads.ba) d = flen(pads.dq) - nphases = phy_settings.nphases - self.phy_settings = phy_settings - read_latency, write_latency = get_latencies(phy_settings) + + self.phy_settings = lasmicon.PhySettings( + memtype=memtype, + dfi_d=2*d, + nphases=nphases, + rdphase=0, + wrphase=1, + cl=cl, + read_latency=5, + write_latency=0 + ) self.dfi = Interface(a, ba, nphases*d, nphases) self.clk4x_wr_strb = Signal() @@ -112,7 +116,7 @@ class S6DDRPHY(Module): bitslip_inc = Signal() sd_sys += [ - If(bitslip_cnt==bitslip, + If(bitslip_cnt == bitslip, bitslip_inc.eq(0) ).Else( bitslip_cnt.eq(bitslip_cnt+1), @@ -156,7 +160,7 @@ class S6DDRPHY(Module): Instance.Input("S", 0), Instance.Output("Q", dqs_o[i]) - ) + ) # DQS tristate cmd self.specials += Instance("ODDR2", @@ -174,7 +178,7 @@ class S6DDRPHY(Module): Instance.Input("S", 0), Instance.Output("Q", dqs_t[i]) - ) + ) # DQS tristate buffer self.specials += Instance("OBUFT", @@ -182,7 +186,7 @@ class S6DDRPHY(Module): Instance.Input("T", dqs_t[i]), Instance.Output("O", pads.dqs[i]) - ) + ) sd_sdram_half += postamble.eq(drive_dqs) @@ -333,26 +337,26 @@ class S6DDRPHY(Module): Instance.Output("SHIFTOUT4"), ) - # # DQ/DQS/DM control # - self.comb += drive_dq.eq(d_dfi[phy_settings.wrphase].wrdata_en) + self.comb += drive_dq.eq(d_dfi[self.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) + 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(read_latency) - sd_sys += rddata_sr.eq(Cat(rddata_sr[1:read_latency], d_dfi[phy_settings.rdphase].rddata_en)) + 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]), - ] \ No newline at end of file + ] diff --git a/top.py b/top.py index a4d687f3b..2d894f200 100644 --- a/top.py +++ b/top.py @@ -25,20 +25,11 @@ def ns(t, margin=True): t += clk_period_ns/2 return ceil(t/clk_period_ns) -sdram_phy = lasmicon.PhySettings( - type="DDR", - dfi_d=64, - nphases=2, - rdphase=0, - wrphase=1, - cl=3 -) sdram_geom = lasmicon.GeomSettings( bank_a=2, row_a=13, col_a=10 ) -sdram_phy_read_latency, sdram_phy_write_latency = s6ddrphy.get_latencies(sdram_phy) sdram_timing = lasmicon.TimingSettings( tRP=ns(15), tRCD=ns(15), @@ -46,9 +37,6 @@ sdram_timing = lasmicon.TimingSettings( tWTR=2, tREFI=ns(7800, False), tRFC=ns(70), - - read_latency=sdram_phy_read_latency+0, - write_latency=sdram_phy_write_latency+0, req_queue_size=8, read_time=32, @@ -104,10 +92,20 @@ class SoC(Module): } def __init__(self, platform, platform_name, with_memtest): + # + # DFI + # + self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), memtype="DDR", nphases=2, cl=3, bitslip=0) + self.submodules.dfii = dfii.DFIInjector(sdram_geom.mux_a, sdram_geom.bank_a, + self.ddrphy.phy_settings.dfi_d, self.ddrphy.phy_settings.nphases) + self.submodules.dficon0 = dfi.Interconnect(self.dfii.master, self.ddrphy.dfi) + # # LASMI # - self.submodules.lasmicon = lasmicon.LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.lasmicon = lasmicon.LASMIcon(self.ddrphy.phy_settings, sdram_geom, sdram_timing) + self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave) + n_lasmims = 7 if with_memtest else 5 self.submodules.lasmixbar = lasmibus.Crossbar([self.lasmicon.lasmic], n_lasmims, self.lasmicon.nrowbits) lasmims = list(self.lasmixbar.masters) @@ -115,15 +113,6 @@ class SoC(Module): if with_memtest: lasmim_mtw, lasmim_mtr = lasmims.pop(), lasmims.pop() assert(not lasmims) - - # - # DFI - # - 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) - self.submodules.dficon1 = dfi.Interconnect(self.lasmicon.dfi, self.dfii.slave) # # WISHBONE