tools/bin2hex
tools/flterm
tools/mkmmimg
-verilog/s6ddrphy/*.v
-verilog/s6ddrphy/.pc
cd build && par -ol high -w soc.ncd soc-routed.ncd
build/soc.bit build/soc.bin: build/soc-routed.ncd
- cd build && bitgen -g Binary:Yes -g INIT_9K:Yes -w soc-routed.ncd soc.bit
+ cd build && bitgen -g LCK_cycle:6 -g Binary:Yes -g INIT_9K:Yes -w soc-routed.ncd soc.bit
load: build/soc.bit
jtag -n load.jtag
First, download and install Migen from:
https://github.com/milkymist/migen
-Then, you will need to fetch the "Spartan-6 FPGA DDR/DDR2 SDRAM PHY core"
-(PHY only solution, we do not need the NWL memory controller) from:
- http://www.xilinx.com/products/intellectual-property/1-1MFEDB.htm
-Downloading it is free of charge, but it cannot be redistributed in
-source form due to copyright restrictions.
-
-Place the Verilog source code of the PHY (contents of
-phy_rtl/spartan6_soft_phy) into the verilog/s6ddrphy folder.
-Then run (from verilog/s6ddrphy):
- quilt push -a
-in order to apply patches that make the PHY more compliant with the DFI
-specification in general, and in particular with the capability to send
-multiple SDRAM commands in one system clock cycle, which our new SDRAM
-controller is capable of doing.
-The patches are against version 1.04 of the PHY.
-
Once this is done, build the bitstream with:
python3 build.py
This will generate the build/soc.bit programming file.
PARTICULAR PURPOSE. See the GNU General Public License for more details.
The authors grant the additional permissions that the code can be used in
-conjunction with the LatticeMico32 CPU core from Lattice and the
-Spartan-6 FPGA DDR/DDR2 SDRAM PHY core from Xilinx and Northwest Logic.
+conjunction with the LatticeMico32 CPU core from Lattice.
Unless otherwise noted, Milkymist-NG's source code is copyright (C)
2011-2012 Sebastien Bourdeauducq. Other authors retain ownership of their
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", extra="IOSTANDARD = SSTL2_I")
add(crg0.trigger_reset, "AA4")
add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
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;
+INST "m1crg/wr_bufpll" LOC = "BUFPLL_X0Y2";
+INST "m1crg/rd_bufpll" LOC = "BUFPLL_X0Y3";
"""
return r
"videoin_rst_n",
"flash_rst_n",
"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"
+ "clk4x_wr",
+ "clk4x_wr_strb",
+ "clk4x_rd",
+ "clk4x_rd_strb"
]:
s = Signal(name=name)
setattr(self, name, s)
generated.append((name, s))
- self.rd_clk_lb = Signal()
-
ratio = Fraction(outfreq1x)/Fraction(infreq)
in_period = float(Fraction(1000000000)/Fraction(infreq))
[
("clkin", self.clkin),
("trigger_reset", self.trigger_reset)
- ], [
- ("rd_clk_lb", self.rd_clk_lb)
- ], [
+ ],
+ parameters=[
("in_period", in_period),
("f_mult", ratio.numerator),
("f_div", ratio.denominator)
def get_fragment(self):
return Fragment(instances=[self._inst],
- pads={self.clkin, self.ac97_rst_n, self.videoin_rst_n, self.flash_rst_n, self.rd_clk_lb})
+ pads={self.clkin, self.ac97_rst_n, self.videoin_rst_n, self.flash_rst_n})
from migen.fhdl.structure import *
from migen.bus import dfi
-from migen.bank.description import *
-from migen.bank import csrgen
class S6DDRPHY:
- def __init__(self, csr_address, a, ba, d):
+ 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"
+ "clk4x_wr",
+ "clk4x_wr_strb",
+ "clk4x_rd",
+ "clk4x_rd_strb"
]:
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_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)
+ ("sd_dq", d//2, inouts),
+ ("sd_dm", d//16, outs),
+ ("sd_dqs", d//16, inouts)
]:
s = Signal(BV(width), name=name)
l.append((name, s))
self._sd_pins.append(s)
- self.dfi = dfi.Interface(a, ba, d)
+ self.dfi = dfi.Interface(a, ba, d, 2)
ins += self.dfi.get_standard_names(True, False)
outs += self.dfi.get_standard_names(False, True)
- ins += [
- ("reset_n", BV(1)),
-
- ("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",
+ self._inst = Instance("s6ddrphy",
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)))
+ ("NUM_D", d)
],
- clkport="clk")
-
- self._reset_n = Field("reset_n")
- self._init_done = Field("init_done")
- self._phy_cal_done = Field("phy_cal_done", 1, READ_ONLY, WRITE_ONLY)
- self._status = RegisterFields("status",
- [self._reset_n, self._init_done, self._phy_cal_done])
- self._req = RegisterRaw("req", 2)
- self._req_addr = RegisterField("req_addr", 8, READ_ONLY, WRITE_ONLY)
-
- self.bank = csrgen.Bank([self._status, self._req, self._req_addr],
- address=csr_address)
+ clkport="sys_clk")
def get_fragment(self):
- pending_r = Signal()
- pending_w = Signal()
- cpg_busy = Signal()
-
- 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),
-
- self._inst.ins["reset_n"].eq(self._reset_n.r),
- self._inst.ins["init_done"].eq(self._init_done.r),
- self._phy_cal_done.w.eq(self._inst.outs["phy_cal_done"]),
- self._req_addr.field.w.eq(self._inst.outs["cpg_addr"][2:10]),
-
- self._req.w.eq(Cat(pending_r, pending_w)),
- cpg_busy.eq(pending_r | pending_w),
- self._inst.ins["cpg_busy"].eq(cpg_busy)
- ]
- sync = [
- If(self._inst.outs["cpg_r_req"], pending_r.eq(1)),
- If(self._inst.outs["cpg_w_req"], pending_w.eq(1)),
- If(self._req.re & self._req.r[0], pending_r.eq(0)),
- If(self._req.re & self._req.r[1], pending_w.eq(0))
- ]
- return Fragment(comb, sync, instances=[self._inst], pads=set(self._sd_pins)) \
- + self.bank.get_fragment()
+ return Fragment(instances=[self._inst], pads=set(self._sd_pins))
#include <stdio.h>
-#include <hw/s6ddrphy.h>
#include <hw/dfii.h>
#include "ddrinit.h"
cdelay(200);
}
-static void calibrate_phy(void)
-{
- int requests;
- int addr;
-
- printf("Calibrating PHY...\n");
-
- CSR_DFII_WRDELAY = 4;
- CSR_DFII_WRDURATION = 1;
- CSR_DFII_RDDELAY = 7;
- CSR_DFII_RDDURATION = 1;
-
- /* Use bank 0, activate row 0 */
- CSR_DFII_BA = 0;
- setaddr(0x0000);
- CSR_DFII_COMMAND = DFII_COMMAND_RAS|DFII_COMMAND_CS;
-
- while(!(CSR_DDRPHY_STATUS & DDRPHY_STATUS_PHY_CAL_DONE)) {
- cdelay(20);
- requests = CSR_DDRPHY_REQUESTS;
- addr = CSR_DDRPHY_REQADDR;
-
- setaddr(addr << 2);
- if(requests & DDRPHY_REQUEST_READ) {
- printf("R %d\n", addr);
- CSR_DFII_COMMAND = DFII_COMMAND_RDDATA|DFII_COMMAND_CAS|DFII_COMMAND_CS;
- }
- if(requests & DDRPHY_REQUEST_WRITE) {
- printf("W %d\n", addr);
- CSR_DFII_COMMAND = DFII_COMMAND_WRDATA|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS;
- }
-
- CSR_DDRPHY_REQUESTS = requests;
- }
-
- /* Precharge All */
- setaddr(0x0400);
- CSR_DFII_COMMAND = DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS;
-}
-
int ddrinit(void)
{
printf("Initializing DDR SDRAM...\n");
- CSR_DDRPHY_STATUS = DDRPHY_STATUS_RESETN;
init_sequence();
- CSR_DDRPHY_STATUS = DDRPHY_STATUS_RESETN|DDRPHY_STATUS_INIT_DONE;
- calibrate_phy();
return 1;
}
#include <hw/common.h>
-#define CSR_DFII_CONTROL MMPTR(0xe0001000)
+#define CSR_DFII_CONTROL MMPTR(0xe0000800)
#define DFII_CONTROL_SEL (0x01)
#define DFII_CONTROL_CKE (0x02)
#define DFII_COMMAND_RDDATA (0x10)
#define DFII_COMMAND_WRDATA (0x20)
-#define CSR_DFII_AH MMPTR(0xe0001008)
-#define CSR_DFII_AL MMPTR(0xe000100C)
-#define CSR_DFII_BA MMPTR(0xe0001010)
+#define CSR_DFII_AH MMPTR(0xe0000808)
+#define CSR_DFII_AL MMPTR(0xe000080C)
+#define CSR_DFII_BA MMPTR(0xe0000810)
-#define CSR_DFII_RDDELAY MMPTR(0xe0001014)
-#define CSR_DFII_RDDURATION MMPTR(0xe0001018)
-#define CSR_DFII_WRDELAY MMPTR(0xe000101C)
-#define CSR_DFII_WRDURATION MMPTR(0xe0001020)
+#define CSR_DFII_RDDELAY MMPTR(0xe0000814)
+#define CSR_DFII_RDDURATION MMPTR(0xe0000818)
+#define CSR_DFII_WRDELAY MMPTR(0xe000081C)
+#define CSR_DFII_WRDURATION MMPTR(0xe0000820)
#endif /* __HW_DFII_H */
+++ /dev/null
-/*
- * Milkymist SoC (Software)
- * Copyright (C) 2012 Sebastien Bourdeauducq
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __HW_S6DDRPHY_H
-#define __HW_S6DDRPHY_H
-
-#include <hw/common.h>
-
-#define CSR_DDRPHY_STATUS MMPTR(0xe0000800)
-
-#define DDRPHY_STATUS_RESETN (0x1)
-#define DDRPHY_STATUS_INIT_DONE (0x2)
-#define DDRPHY_STATUS_PHY_CAL_DONE (0x4)
-
-#define CSR_DDRPHY_REQUESTS MMPTR(0xe0000804)
-
-#define DDRPHY_REQUEST_READ (0x1)
-#define DDRPHY_REQUEST_WRITE (0x2)
-
-#define CSR_DDRPHY_REQADDR MMPTR(0xe0000808)
-
-#endif /* __HW_S6DDRPHY_H */
dfi_a = 13
dfi_ba = 2
-dfi_d = 128 # TODO -> 64
+dfi_d = 64
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",
+ "clk4x_wr",
+ "clk4x_wr_strb",
+ "clk4x_rd",
+ "clk4x_rd_strb"
]
comb = [getattr(phy, name).eq(getattr(crg, name)) for name in names]
return Fragment(comb)
#
# DFI
#
- ddrphy0 = s6ddrphy.S6DDRPHY(1, dfi_a, dfi_ba, dfi_d)
- dfii0 = dfii.DFIInjector(2, dfi_a, dfi_ba, dfi_d, 1)
+ ddrphy0 = s6ddrphy.S6DDRPHY(dfi_a, dfi_ba, dfi_d)
+ dfii0 = dfii.DFIInjector(1, dfi_a, dfi_ba, dfi_d, 2)
dficon0 = dfi.Interconnect(dfii0.master, ddrphy0.dfi)
#
uart0 = uart.UART(0, clk_freq, baud=115200)
csrcon0 = csr.Interconnect(wishbone2csr0.csr, [
uart0.bank.interface,
- ddrphy0.bank.interface,
dfii0.bank.interface
])
output videoin_rst_n,
output flash_rst_n,
- /* DDR PHY clocks and reset */
+ /* DDR PHY clocks */
output clk2x_90,
- output clk4x_wr_left,
- output clk4x_wr_strb_left,
- output clk4x_wr_right,
- output clk4x_wr_strb_right,
- output clk4x_rd_left,
- output clk4x_rd_strb_left,
- output clk4x_rd_right,
- output clk4x_rd_strb_right,
- inout rd_clk_lb /* < unconnected clock pin for read clock PLL loopback */
+ output clk4x_wr,
+ output clk4x_wr_strb,
+ output clk4x_rd,
+ output clk4x_rd_strb
);
/*
* Reset
*/
-wire reset_n;
-
reg [19:0] rst_debounce;
-always @(posedge sys_clk, negedge reset_n) begin
- if(~reset_n) begin
+always @(posedge sys_clk) begin
+ if(trigger_reset)
rst_debounce <= 20'hFFFFF;
- sys_rst <= 1'b1;
- end else begin
- if(trigger_reset)
- rst_debounce <= 20'hFFFFF;
- else if(rst_debounce != 20'd0)
- rst_debounce <= rst_debounce - 20'd1;
- sys_rst <= rst_debounce != 20'd0;
- end
+ else if(rst_debounce != 20'd0)
+ rst_debounce <= rst_debounce - 20'd1;
+ sys_rst <= rst_debounce != 20'd0;
end
assign ac97_rst_n = ~sys_rst;
reg [7:0] flash_rstcounter;
-always @(posedge sys_clk, negedge reset_n) begin
- if(~reset_n) begin
+always @(posedge sys_clk) begin
+ if(trigger_reset)
flash_rstcounter <= 8'd0;
- end else begin
- if(trigger_reset)
- flash_rstcounter <= 8'd0;
- else if(~flash_rstcounter[7])
- flash_rstcounter <= flash_rstcounter + 8'd1;
- end
+ else if(~flash_rstcounter[7])
+ flash_rstcounter <= flash_rstcounter + 8'd1;
end
assign flash_rst_n = flash_rstcounter[7];
/*
- * Clock management. Largely taken from the NWL reference design.
+ * Clock management. Inspired by the NWL reference design.
*/
-
+
wire sdr_clkin;
wire clkdiv;
.SERDESSTROBE()
);
-wire pll1_lckd;
-wire buf_pll1_fb_out;
-wire pll1out0;
-wire pll1out1;
-wire pll1out2;
-wire pll1out3;
+wire pll_lckd;
+wire buf_pll_fb_out;
+wire pllout0;
+wire pllout1;
+wire pllout2;
+wire pllout3;
PLL_ADV #(
.BANDWIDTH("OPTIMIZED"),
.CLKOUT1_DIVIDE(f_div),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT1_PHASE(0),
- .CLKOUT2_DIVIDE(4*f_div),
+ .CLKOUT2_DIVIDE(2*f_div),
.CLKOUT2_DUTY_CYCLE(0.5),
- .CLKOUT2_PHASE(0.0),
- .CLKOUT3_DIVIDE(2*f_div),
+ .CLKOUT2_PHASE(90.0),
+ .CLKOUT3_DIVIDE(4*f_div),
.CLKOUT3_DUTY_CYCLE(0.5),
- .CLKOUT3_PHASE(90),
+ .CLKOUT3_PHASE(0.0),
.CLKOUT4_DIVIDE(7),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT4_PHASE(0),
.REF_JITTER(0.100),
.CLK_FEEDBACK("CLKFBOUT"),
.SIM_DEVICE("SPARTAN6")
-) pll1 (
+) pll (
.CLKFBDCM(),
- .CLKFBOUT(buf_pll1_fb_out),
- .CLKOUT0(pll1out0), /* < x4 180 clock for transmitter */
- .CLKOUT1(pll1out1), /* < x4 180 clock for transmitter */
- .CLKOUT2(pll1out2), /* < x1 clock for memory controller */
- .CLKOUT3(pll1out3), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
+ .CLKFBOUT(buf_pll_fb_out),
+ .CLKOUT0(pllout0), /* < x4 clock for writes */
+ .CLKOUT1(pllout1), /* < x4 clock for reads */
+ .CLKOUT2(pllout2), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
+ .CLKOUT3(pllout3), /* < x1 clock for system and memory controller */
.CLKOUT4(),
.CLKOUT5(),
.CLKOUTDCM0(),
.CLKOUTDCM5(),
.DO(),
.DRDY(),
- .LOCKED(pll1_lckd),
- .CLKFBIN(buf_pll1_fb_out),
+ .LOCKED(pll_lckd),
+ .CLKFBIN(buf_pll_fb_out),
.CLKIN1(clkdiv),
.CLKIN2(1'b0),
.CLKINSEL(1'b1),
BUFPLL #(
.DIVIDE(4)
-) wr_bufpll_left (
- .PLLIN(pll1out0),
+) wr_bufpll (
+ .PLLIN(pllout0),
.GCLK(sys_clk),
- .LOCKED(pll1_lckd),
- .IOCLK(clk4x_wr_left),
+ .LOCKED(pll_lckd),
+ .IOCLK(clk4x_wr),
.LOCK(),
- .SERDESSTROBE(clk4x_wr_strb_left)
+ .SERDESSTROBE(clk4x_wr_strb)
);
BUFPLL #(
.DIVIDE(4)
-) wr_bufpll_right (
- .PLLIN(pll1out1),
+) rd_bufpll (
+ .PLLIN(pllout1),
.GCLK(sys_clk),
- .LOCKED(pll1_lckd),
- .IOCLK(clk4x_wr_right),
+ .LOCKED(pll_lckd),
+ .IOCLK(clk4x_rd),
.LOCK(),
- .SERDESSTROBE(clk4x_wr_strb_right)
-);
-
-BUFG bufg_x1(
- .I(pll1out2),
- .O(sys_clk)
+ .SERDESSTROBE(clk4x_rd_strb)
);
BUFG bufg_x2_2(
- .I(pll1out3),
+ .I(pllout2),
.O(clk2x_90)
);
-/*
- * Generate clk4x_rd. This clock is sourced from clk2x_90.
- * An IODELAY2 element is included in the path of this clock so that
- * any variation in IDELAY element's base delay is compensated when this clock
- * is used to capture read data which also goes through IDELAY element.
- */
-
-wire rd_clk_out;
-
-ODDR2 #(
- .DDR_ALIGNMENT("C0"),
- .INIT(1'b0),
- .SRTYPE("ASYNC")
-) rd_clk_out_inst (
- .Q(rd_clk_out),
- .C0(clk2x_90),
- .C1(~clk2x_90),
- .CE(1'b1),
- .D0(1'b1),
- .D1(1'b0),
- .R(1'b0),
- .S(1'b0)
-);
-
-wire rd_clk_out_oe_n;
-
-ODDR2 #(
- .DDR_ALIGNMENT("C0"),
- .INIT(1'b0),
- .SRTYPE("ASYNC")
-) rd_clk_out_oe_inst (
- .Q(rd_clk_out_oe_n),
- .C0(clk2x_90),
- .C1(~clk2x_90),
- .CE(1'b1),
- .D0(1'b0),
- .D1(1'b0),
- .R(1'b0),
- .S(1'b0)
-);
-
-wire rd_clk_fb;
-
-/* Dummy pin used for calibration */
-IOBUF rd_clk_loop_back_inst(
- .O(rd_clk_fb),
- .IO(rd_clk_lb),
- .I(rd_clk_out),
- .T(rd_clk_out_oe_n)
-);
-
-wire rd_clk_fb_dly;
-
-IODELAY2 #(
- .DATA_RATE("DDR"),
- .IDELAY_VALUE(0),
- .IDELAY2_VALUE(0),
- .IDELAY_MODE("NORMAL"),
- .ODELAY_VALUE(0),
- .IDELAY_TYPE("FIXED"),
- .COUNTER_WRAPAROUND("STAY_AT_LIMIT"),
- .DELAY_SRC("IDATAIN"),
- .SERDES_MODE("NONE"),
- .SIM_TAPDELAY_VALUE(49)
-) iodelay_cm (
- .IDATAIN(rd_clk_fb),
- .TOUT(),
- .DOUT(),
- .T(1'b1),
- .ODATAIN(1'b0),
- .DATAOUT(rd_clk_fb_dly),
- .DATAOUT2(),
- .IOCLK0(1'b0),
- .IOCLK1(1'b0),
- .CLK(1'b0),
- .CAL(1'b0),
- .INC(1'b0),
- .CE(1'b0),
- .RST(1'b0),
- .BUSY()
-);
-
-wire rd_clk_fb_dly_bufio;
-
-BUFIO2 #(
- .DIVIDE(1),
- .DIVIDE_BYPASS("FALSE"),
- .I_INVERT("FALSE")
-) bufio2_inst (
- .I(rd_clk_fb_dly),
- .IOCLK(),
- .DIVCLK(rd_clk_fb_dly_bufio),
- .SERDESSTROBE()
-);
-
-wire pll2_lckd;
-wire buf_pll2_fb_out;
-wire pll2out0;
-wire pll2out1;
-
-PLL_ADV #(
- .BANDWIDTH("OPTIMIZED"),
- .CLKFBOUT_MULT(4),
- .CLKFBOUT_PHASE(0.0),
- .CLKIN1_PERIOD(clk2x_period),
- .CLKIN2_PERIOD(clk2x_period),
- .CLKOUT0_DIVIDE(2),
- .CLKOUT0_DUTY_CYCLE(0.5),
- .CLKOUT0_PHASE(0.0),
- .CLKOUT1_DIVIDE(2),
- .CLKOUT1_DUTY_CYCLE(0.5),
- .CLKOUT1_PHASE(0.0),
- .CLKOUT2_DIVIDE(7),
- .CLKOUT2_DUTY_CYCLE(0.5),
- .CLKOUT2_PHASE(0.0),
- .CLKOUT3_DIVIDE(7),
- .CLKOUT3_DUTY_CYCLE(0.5),
- .CLKOUT3_PHASE(0.0),
- .CLKOUT4_DIVIDE(7),
- .CLKOUT4_DUTY_CYCLE(0.5),
- .CLKOUT4_PHASE(0.0),
- .CLKOUT5_DIVIDE(7),
- .CLKOUT5_DUTY_CYCLE (0.5),
- .CLKOUT5_PHASE(0.0),
- .COMPENSATION("INTERNAL"),
- .DIVCLK_DIVIDE(1),
- .REF_JITTER(0.100),
- .CLK_FEEDBACK("CLKFBOUT"),
- .SIM_DEVICE("SPARTAN6")
-) pll2 (
- .CLKFBDCM(),
- .CLKFBOUT(buf_pll2_fb_out),
- .CLKOUT0(pll2out0), /* < x4 clock to capture read data */
- .CLKOUT1(pll2out1), /* < x4 clock to capture read data */
- .CLKOUT2(),
- .CLKOUT3(),
- .CLKOUT4(),
- .CLKOUT5(),
- .CLKOUTDCM0(),
- .CLKOUTDCM1(),
- .CLKOUTDCM2(),
- .CLKOUTDCM3(),
- .CLKOUTDCM4(),
- .CLKOUTDCM5(),
- .DO(),
- .DRDY(),
- .LOCKED(pll2_lckd),
- .CLKFBIN(buf_pll2_fb_out),
- .CLKIN1(rd_clk_fb_dly_bufio),
- .CLKIN2(1'b0),
- .CLKINSEL(1'b1),
- .DADDR(5'b00000),
- .DCLK(1'b0),
- .DEN(1'b0),
- .DI(16'h0000),
- .DWE(1'b0),
- .RST(~pll1_lckd),
- .REL(1'b0)
-);
-
-BUFPLL #(
- .DIVIDE(4)
-) rd_bufpll_left (
- .PLLIN(pll2out0),
- .GCLK(sys_clk),
- .LOCKED(pll2_lckd),
- .IOCLK(clk4x_rd_left),
- .LOCK(),
- .SERDESSTROBE(clk4x_rd_strb_left)
-);
-
-BUFPLL #(
- .DIVIDE(4)
-) rd_bufpll_right (
- .PLLIN(pll2out1),
- .GCLK(sys_clk),
- .LOCKED(pll2_lckd),
- .IOCLK(clk4x_rd_right),
- .LOCK(),
- .SERDESSTROBE(clk4x_rd_strb_right)
-);
-
-wire sdram_sys_clk_lock_d16;
-reg sdram_sys_clk_lock_d17;
-
-/*
- * Async reset generation
- * The reset is de-asserted 16 clocks after both internal clocks are locked.
- */
-
-SRL16 reset_delay_sr(
- .CLK(sys_clk),
- .D(pll1_lckd & pll2_lckd),
- .A0(1'b1),
- .A1(1'b1),
- .A2(1'b1),
- .A3(1'b1),
- .Q(sdram_sys_clk_lock_d16)
+BUFG bufg_x1(
+ .I(pllout3),
+ .O(sys_clk)
);
-
-always @(posedge sys_clk)
- sdram_sys_clk_lock_d17 <= sdram_sys_clk_lock_d16;
-
-assign reset_n = sdram_sys_clk_lock_d17;
endmodule
+++ /dev/null
-The Verilog files of the Spartan-6 DDR PHY from Xilinx/Northwest Logic go here.
+++ /dev/null
-Index: s6ddrphy/spartan6_soft_phy.v
-===================================================================
---- s6ddrphy.orig/spartan6_soft_phy.v
-+++ s6ddrphy/spartan6_soft_phy.v
-@@ -116,7 +116,6 @@ module spartan6_soft_phy # (
- inout [NUM_DQ-1:0] sd_dq, // Data in from SDRAM device
- output [NUM_DQS-1:0] sd_dm, // Data mask to SDRAM devices
- inout [NUM_DQS-1:0] sd_dqs, // DQS
-- inout [NUM_DQS-1:0] sd_dqs_n, // complimentary DQS
-
- // configuration ports
- input [2:0] cfg_al, // Posted CAS additive latency
-@@ -300,12 +299,11 @@ genvar j;
- generate
- for (j = 0; j < NUM_DQ/8*(NIBBLE_DEVICES+1) ; j = j + 1)
- begin:dqs_iob
-- IOBUFDS iobufds (
-+ IOBUF iobufds (
- .O (sd_dqs_in[j]),
- .I (sd_dqs_out[j]),
- .T (sd_dqs_oe_n[j]),
-- .IO (sd_dqs[j]),
-- .IOB (sd_dqs_n[j])
-+ .IO (sd_dqs[j])
- );
- end
- endgenerate
+++ /dev/null
-s6ddrphy.diff
--- /dev/null
+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_90,
+ 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 sd_clk_out_p,
+ output sd_clk_out_n,
+ output [NUM_AD-1:0] sd_a,
+ output [NUM_BA-1:0] sd_ba,
+ output sd_cs_n,
+ output sd_cke,
+ output sd_ras_n,
+ output sd_cas_n,
+ output 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
+);
+
+endmodule