From: Sebastien Bourdeauducq Date: Fri, 17 Feb 2012 10:04:44 +0000 (+0100) Subject: Connect DDR PHY X-Git-Tag: 24jan2021_ls180~3235 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5d1dad583b1ab8be6cd0b7b0c85df50e19b8c484;p=litex.git Connect DDR PHY Doesn't do much for the moment, just to check synthesis/P&R. --- diff --git a/build.py b/build.py index fae1a93a..aaf9c569 100644 --- a/build.py +++ b/build.py @@ -4,13 +4,16 @@ import top # list Verilog sources before changing directory verilog_sources = [] def add_core_dir(d): - for root, subFolders, files in os.walk(os.path.join("verilog", d)): - for f in files: + root = os.path.join("verilog", d) + files = os.listdir(root) + for f in files: + if f[-2:] == ".v": verilog_sources.append(os.path.join(root, f)) def add_core_files(d, files): for f in files: verilog_sources.append(os.path.join("verilog", d, f)) add_core_dir("m1crg") +add_core_dir("s6ddrphy") add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v", "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v", "lm32_shifter.v", "lm32_multiplier_spartan6.v", "lm32_mc_arithmetic.v", @@ -31,7 +34,9 @@ def str2file(filename, contents): str2file("soc.v", src_verilog) str2file("soc.ucf", src_ucf) verilog_sources.append("build/soc.v") + #raise SystemExit + # xst xst_prj = "" for s in verilog_sources: diff --git a/constraints.py b/constraints.py index 91b44dd6..4867ae5b 100644 --- a/constraints.py +++ b/constraints.py @@ -1,8 +1,9 @@ -def get(ns, crg0, norflash0, uart0): +def get(ns, crg0, norflash0, uart0, ddrphy0): constraints = [] def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""): constraints.append((ns.get_name(signal), vec, pin, iostandard, extra)) def add_vec(signal, pins, iostandard="LVCMOS33", extra=""): + assert(signal.bv.width == len(pins)) i = 0 for p in pins: add(signal, p, i, iostandard, extra) @@ -12,7 +13,7 @@ def get(ns, crg0, norflash0, uart0): add(crg0.ac97_rst_n, "D6") add(crg0.videoin_rst_n, "W17") add(crg0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8") - add(crg0.rd_clk_lb, "K5") + add(crg0.rd_clk_lb, "K5", extra="IOSTANDARD = SSTL2_I") add(crg0.trigger_reset, "AA4") add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22", @@ -21,7 +22,7 @@ def get(ns, crg0, norflash0, uart0): extra="SLEW = FAST | DRIVE = 8") add_vec(norflash0.d, ["AA20", "U14", "U13", "AA6", "AB6", "W4", "Y4", "Y7", "AA2", "AB2", "V15", "AA18", "AB18", "Y13", "AA12", "AB12"], - extra = "SLEW = FAST | DRIVE = 8 | PULLDOWN") + extra="SLEW = FAST | DRIVE = 8 | PULLDOWN") add(norflash0.oe_n, "M22", extra="SLEW = FAST | DRIVE = 8") add(norflash0.we_n, "N20", extra="SLEW = FAST | DRIVE = 8") add(norflash0.ce_n, "M21", extra="SLEW = FAST | DRIVE = 8") @@ -29,6 +30,24 @@ def get(ns, crg0, norflash0, uart0): add(uart0.tx, "L17", extra="SLEW = SLOW") add(uart0.rx, "K18", extra="PULLUP") + ddrsettings = "IOSTANDARD = SSTL2_I" + add(ddrphy0.sd_clk_out_p, "M3", extra=ddrsettings) + add(ddrphy0.sd_clk_out_n, "L4", extra=ddrsettings) + add_vec(ddrphy0.sd_a, ["B1", "B2", "H8", "J7", "E4", "D5", "K7", "F5", + "G6", "C1", "C3", "D1", "D2"], extra=ddrsettings) + add_vec(ddrphy0.sd_ba, ["A2", "E6"], extra=ddrsettings) + add(ddrphy0.sd_cs_n, "F7", extra=ddrsettings) + add(ddrphy0.sd_cke, "G7", extra=ddrsettings) + add(ddrphy0.sd_ras_n, "E5", extra=ddrsettings) + add(ddrphy0.sd_cas_n, "C4", extra=ddrsettings) + add(ddrphy0.sd_we_n, "D3", extra=ddrsettings) + add_vec(ddrphy0.sd_dq, ["Y2", "W3", "W1", "P8", "P7", "P6", "P5", "T4", "T3", + "U4", "V3", "N6", "N7", "M7", "M8", "R4", "P4", "M6", "L6", "P3", "N4", + "M5", "V2", "V1", "U3", "U1", "T2", "T1", "R3", "R1", "P2", "P1"], + extra=ddrsettings) + add_vec(ddrphy0.sd_dm, ["E1", "E3", "F3", "G4"], extra=ddrsettings) + add_vec(ddrphy0.sd_dqs, ["F1", "F2", "H5", "H6"], extra=ddrsettings) + r = "" for c in constraints: r += "NET \"" + c[0] @@ -42,6 +61,15 @@ def get(ns, crg0, norflash0, uart0): r += """ TIMESPEC "TSclk50" = PERIOD "GRPclk50" 20 ns HIGH 50%; - """ +INST "spartan6_soft_phy/datapath_s6_inst/dq_idelay_cal_inst/max_tap_drp" LOC = "IODELAY_X0Y79"; # use sd_dm[0] at E1 +INST "m1crg/wr_bufpll_left" LOC = "BUFPLL_X0Y2"; +INST "m1crg/wr_bufpll_right" LOC = "BUFPLL_X2Y2"; +INST "m1crg/rd_bufpll_left" LOC = "BUFPLL_X0Y3"; +INST "m1crg/rd_bufpll_right" LOC = "BUFPLL_X2Y3"; + +# MAP (13.4) hallucinates that this placement is unroutable. Tell it to STFU. +PIN "m1crg/rd_bufpll_left.IOCLK" CLOCK_DEDICATED_ROUTE = FALSE; +PIN "spartan6_soft_phy/datapath_s6_inst/dq_idelay_cal_inst/max_tap_drp.IOCLK0" CLOCK_DEDICATED_ROUTE = FALSE; +""" return r diff --git a/milkymist/m1crg/__init__.py b/milkymist/m1crg/__init__.py index 38b09121..37b19e5a 100644 --- a/milkymist/m1crg/__init__.py +++ b/milkymist/m1crg/__init__.py @@ -23,7 +23,7 @@ class M1CRG: "clk4x_rd_strb_left", "clk4x_rd_right", "clk4x_rd_strb_right" - ]: + ]: s = Signal(name=name) setattr(self, name, s) generated.append((name, s)) diff --git a/milkymist/s6ddrphy/__init__.py b/milkymist/s6ddrphy/__init__.py new file mode 100644 index 00000000..3e3b94db --- /dev/null +++ b/milkymist/s6ddrphy/__init__.py @@ -0,0 +1,104 @@ +from migen.fhdl.structure import * +from migen.bus import dfi + +class S6DDRPHY: + def __init__(self, a, ba, d): + ins = [] + outs = [] + inouts = [] + + for name in [ + "clk2x_90", + "clk4x_wr_left", + "clk4x_wr_strb_left", + "clk4x_wr_right", + "clk4x_wr_strb_right", + "clk4x_rd_left", + "clk4x_rd_strb_left", + "clk4x_rd_right", + "clk4x_rd_strb_right", + "reset_n" + ]: + s = Signal(name=name) + setattr(self, name, s) + ins.append((name, s)) + + self._sd_pins = [] + sd_d = d//4 + for name, width, l in [ + ("sd_clk_out_p", 1, outs), + ("sd_clk_out_n", 1, outs), + ("sd_a", a, outs), + ("sd_ba", ba, outs), + ("sd_cs_n", 1, outs), + ("sd_cke", 1, outs), + ("sd_ras_n", 1, outs), + ("sd_cas_n", 1, outs), + ("sd_we_n", 1, outs), + ("sd_dq", sd_d, inouts), + ("sd_dm", sd_d//8, outs), + ("sd_dqs", sd_d//8, inouts) + + ]: + s = Signal(BV(width), name=name) + setattr(self, name, s) + l.append((name, s)) + self._sd_pins.append(s) + + self.dfi = dfi.Interface(a, ba, d) + ins += self.dfi.get_standard_names(True, False) + outs += self.dfi.get_standard_names(False, True) + + ins += [ + ("cfg_al", BV(3)), + ("cfg_cl", BV(3)), + ("cfg_bl", BV(2)), + ("cfg_regdimm", BV(1)), + + ("init_done", BV(1)), + + ("cpg_busy", BV(1)), + + ("diag_dq_recal", BV(1)), + ("diag_io_sel", BV(9)), + ("diag_disable_cal_on_startup", BV(1)), + ("diag_cal_bits", BV(2)), + ("diag_short_cal", BV(1)) + ] + outs += [ + ("phy_cal_done", BV(1)), + + ("cpg_r_req", BV(1)), + ("cpg_w_req", BV(1)), + ("cpg_addr", BV(a)), + ("cpg_b_size", BV(4)) + ] + + self._inst = Instance("spartan6_soft_phy", + outs, + ins, + inouts, + [ + ("DSIZE", d), + ("NUM_AD", a), + ("NUM_BA", ba), + ("ADDR_WIDTH", 31), + ("DQ_IO_LOC", Constant(2**32-1, BV(32))), + ("DM_IO_LOC", Constant(2**4-1, BV(4))) + ], + clkport="clk") + + def get_fragment(self): + comb = [ + self._inst.ins["cfg_al"].eq(0), + self._inst.ins["cfg_cl"].eq(3), + self._inst.ins["cfg_bl"].eq(1), + self._inst.ins["cfg_regdimm"].eq(0), + + self._inst.ins["diag_dq_recal"].eq(0), + self._inst.ins["diag_io_sel"].eq(0), + self._inst.ins["diag_disable_cal_on_startup"].eq(0), + self._inst.ins["diag_cal_bits"].eq(0), + self._inst.ins["diag_short_cal"].eq(0) + ] + return Fragment(comb, instances=[self._inst], pads=set(self._sd_pins)) diff --git a/top.py b/top.py index c46eda58..dbf67dfc 100644 --- a/top.py +++ b/top.py @@ -4,7 +4,7 @@ from migen.fhdl.structure import * from migen.fhdl import verilog, autofragment from migen.bus import wishbone, asmibus, wishbone2asmi, csr, wishbone2csr -from milkymist import m1crg, lm32, norflash, uart, sram#, s6ddrphy +from milkymist import m1crg, lm32, norflash, uart, sram, s6ddrphy import constraints MHz = 1000000 @@ -12,11 +12,26 @@ clk_freq = (83 + Fraction(1, 3))*MHz sram_size = 4096 # in bytes l2_size = 8192 # in bytes +def ddrphy_clocking(crg, phy): + names = [ + "clk2x_90", + "clk4x_wr_left", + "clk4x_wr_strb_left", + "clk4x_wr_right", + "clk4x_wr_strb_right", + "clk4x_rd_left", + "clk4x_rd_strb_left", + "clk4x_rd_right", + "clk4x_rd_strb_right", + ] + comb = [getattr(phy, name).eq(getattr(crg, name)) for name in names] + return Fragment(comb) + def get(): # # ASMI # - #ddrphy0 = s6ddrphy.S6DDRPHY(13, 2, 128) + ddrphy0 = s6ddrphy.S6DDRPHY(13, 2, 128) asmihub0 = asmibus.Hub(23, 128, 12) # TODO: get hub from memory controller asmiport_wb = asmihub0.get_port() asmihub0.finalize() @@ -67,12 +82,12 @@ def get(): # crg0 = m1crg.M1CRG(50*MHz, clk_freq) - frag = autofragment.from_local() + interrupts + frag = autofragment.from_local() + interrupts + ddrphy_clocking(crg0, ddrphy0) src_verilog, vns = verilog.convert(frag, {crg0.trigger_reset}, name="soc", clk_signal=crg0.sys_clk, rst_signal=crg0.sys_rst, return_ns=True) - src_ucf = constraints.get(vns, crg0, norflash0, uart0) + src_ucf = constraints.get(vns, crg0, norflash0, uart0, ddrphy0) return (src_verilog, src_ucf)