Skip to content

Commit 72f9af9

Browse files
author
Sebastien Bourdeauducq
committedFeb 16, 2012
Generate all clocks for the DDR PHY
1 parent 859c9d8 commit 72f9af9

File tree

7 files changed

+495
-100
lines changed

7 files changed

+495
-100
lines changed
 

‎build.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def add_core_dir(d):
1010
def add_core_files(d, files):
1111
for f in files:
1212
verilog_sources.append(os.path.join("verilog", d, f))
13-
add_core_dir("m1reset")
13+
add_core_dir("m1crg")
1414
add_core_files("lm32", ["lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v",
1515
"lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v",
1616
"lm32_shifter.v", "lm32_multiplier_spartan6.v", "lm32_mc_arithmetic.v",
@@ -59,4 +59,4 @@ def str2file(filename, contents):
5959
os.system("par -ol high -w soc.ncd soc-routed.ncd")
6060

6161
# bitgen
62-
os.system("bitgen -g LCK_cycle:6 -g Binary:Yes -g INIT_9K:Yes -w soc-routed.ncd soc.bit")
62+
os.system("bitgen -g Binary:Yes -g INIT_9K:Yes -w soc-routed.ncd soc.bit")

‎constraints.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
def get(ns, clkfx_sys, reset0, norflash0, uart0):
1+
def get(ns, crg0, norflash0, uart0):
22
constraints = []
33
def add(signal, pin, vec=-1, iostandard="LVCMOS33", extra=""):
44
constraints.append((ns.get_name(signal), vec, pin, iostandard, extra))
@@ -8,12 +8,12 @@ def add_vec(signal, pins, iostandard="LVCMOS33", extra=""):
88
add(signal, p, i, iostandard, extra)
99
i += 1
1010

11-
add(clkfx_sys.clkin, "AB11", extra="TNM_NET = \"GRPclk50\"")
12-
13-
add(reset0.trigger_reset, "AA4")
14-
add(reset0.ac97_rst_n, "D6")
15-
add(reset0.videoin_rst_n, "W17")
16-
add(reset0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
11+
add(crg0.clkin, "AB11", extra="TNM_NET = \"GRPclk50\"")
12+
add(crg0.ac97_rst_n, "D6")
13+
add(crg0.videoin_rst_n, "W17")
14+
add(crg0.flash_rst_n, "P22", extra="SLEW = FAST | DRIVE = 8")
15+
add(crg0.rd_clk_lb, "K5")
16+
add(crg0.trigger_reset, "AA4")
1717

1818
add_vec(norflash0.adr, ["L22", "L20", "K22", "K21", "J19", "H20", "F22",
1919
"F21", "K17", "J17", "E22", "E20", "H18", "H19", "F20",

‎milkymist/m1crg/__init__.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from fractions import Fraction
2+
3+
from migen.fhdl.structure import *
4+
5+
class M1CRG:
6+
def __init__(self, infreq, outfreq1x):
7+
self.clkin = Signal()
8+
self.trigger_reset = Signal()
9+
10+
generated = []
11+
for name in [
12+
"sys_clk",
13+
"sys_rst",
14+
"ac97_rst_n",
15+
"videoin_rst_n",
16+
"flash_rst_n",
17+
"clk2x_90",
18+
"clk4x_wr_left",
19+
"clk4x_wr_strb_left",
20+
"clk4x_wr_right",
21+
"clk4x_wr_strb_right",
22+
"clk4x_rd_left",
23+
"clk4x_rd_strb_left",
24+
"clk4x_rd_right",
25+
"clk4x_rd_strb_right"
26+
]:
27+
s = Signal(name=name)
28+
setattr(self, name, s)
29+
generated.append((name, s))
30+
31+
self.rd_clk_lb = Signal()
32+
33+
ratio = Fraction(outfreq1x)/Fraction(infreq)
34+
in_period = float(Fraction(1000000000)/Fraction(infreq))
35+
36+
self._inst = Instance("m1crg",
37+
generated,
38+
[
39+
("clkin", self.clkin),
40+
("trigger_reset", self.trigger_reset),
41+
("rd_clk_lb", self.rd_clk_lb) # TODO: inout
42+
], [
43+
("in_period", in_period),
44+
("f_mult", ratio.numerator),
45+
("f_div", ratio.denominator)
46+
]
47+
)
48+
49+
def get_fragment(self):
50+
return Fragment(instances=[self._inst],
51+
pads={self.clkin, self.ac97_rst_n, self.videoin_rst_n, self.flash_rst_n, self.rd_clk_lb})

‎milkymist/m1reset/__init__.py

-20
This file was deleted.

‎top.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1+
from fractions import Fraction
2+
13
from migen.fhdl.structure import *
24
from migen.fhdl import verilog, autofragment
35
from migen.bus import wishbone, asmibus, wishbone2asmi, csr, wishbone2csr
46

5-
from milkymist import m1reset, clkfx, lm32, norflash, uart, sram
7+
from milkymist import m1crg, lm32, norflash, uart, sram#, s6ddrphy
68
import constraints
79

810
MHz = 1000000
9-
clk_freq = 80*MHz
11+
clk_freq = (83 + Fraction(1, 3))*MHz
1012
sram_size = 4096 # in bytes
1113
l2_size = 8192 # in bytes
1214

1315
def get():
1416
#
1517
# ASMI
1618
#
17-
asmihub0 = asmibus.Hub(24, 64, 8) # TODO: get hub from memory controller
19+
#ddrphy0 = s6ddrphy.S6DDRPHY(13, 2, 128)
20+
asmihub0 = asmibus.Hub(23, 128, 12) # TODO: get hub from memory controller
1821
asmiport_wb = asmihub0.get_port()
1922
asmihub0.finalize()
2023

@@ -62,15 +65,14 @@ def get():
6265
#
6366
# Housekeeping
6467
#
65-
clkfx_sys = clkfx.ClkFX(50*MHz, clk_freq)
66-
reset0 = m1reset.M1Reset()
68+
crg0 = m1crg.M1CRG(50*MHz, clk_freq)
6769

6870
frag = autofragment.from_local() + interrupts
6971
src_verilog, vns = verilog.convert(frag,
70-
{clkfx_sys.clkin, reset0.trigger_reset},
72+
{crg0.trigger_reset},
7173
name="soc",
72-
clk_signal=clkfx_sys.clkout,
73-
rst_signal=reset0.sys_rst,
74+
clk_signal=crg0.sys_clk,
75+
rst_signal=crg0.sys_rst,
7476
return_ns=True)
75-
src_ucf = constraints.get(vns, clkfx_sys, reset0, norflash0, uart0)
77+
src_ucf = constraints.get(vns, crg0, norflash0, uart0)
7678
return (src_verilog, src_ucf)

‎verilog/m1crg/m1crg.v

+424
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,424 @@
1+
/*
2+
* Milkymist-NG SoC
3+
* Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, version 3 of the License.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
module m1crg #(
19+
parameter in_period = 0.0,
20+
parameter f_mult = 0,
21+
parameter f_div = 0,
22+
parameter clk2x_period = (in_period*f_div)/(2.0*f_mult)
23+
) (
24+
input clkin,
25+
input trigger_reset,
26+
27+
output sys_clk,
28+
output reg sys_rst,
29+
30+
/* Reset off-chip devices */
31+
output ac97_rst_n,
32+
output videoin_rst_n,
33+
output flash_rst_n,
34+
35+
/* DDR PHY clocks and reset */
36+
output clk2x_90,
37+
output clk4x_wr_left,
38+
output clk4x_wr_strb_left,
39+
output clk4x_wr_right,
40+
output clk4x_wr_strb_right,
41+
output clk4x_rd_left,
42+
output clk4x_rd_strb_left,
43+
output clk4x_rd_right,
44+
output clk4x_rd_strb_right,
45+
inout rd_clk_lb /* < unconnected clock pin for read clock PLL loopback */
46+
);
47+
48+
/*
49+
* Reset
50+
*/
51+
52+
wire reset_n;
53+
54+
reg [19:0] rst_debounce;
55+
always @(posedge sys_clk, negedge reset_n) begin
56+
if(~reset_n) begin
57+
rst_debounce <= 20'hFFFFF;
58+
sys_rst <= 1'b1;
59+
end else begin
60+
if(trigger_reset)
61+
rst_debounce <= 20'hFFFFF;
62+
else if(rst_debounce != 20'd0)
63+
rst_debounce <= rst_debounce - 20'd1;
64+
sys_rst <= rst_debounce != 20'd0;
65+
end
66+
end
67+
68+
assign ac97_rst_n = ~sys_rst;
69+
assign videoin_rst_n = ~sys_rst;
70+
71+
/*
72+
* We must release the Flash reset before the system reset
73+
* because the Flash needs some time to come out of reset
74+
* and the CPU begins fetching instructions from it
75+
* as soon as the system reset is released.
76+
* From datasheet, minimum reset pulse width is 100ns
77+
* and reset-to-read time is 150ns.
78+
*/
79+
80+
reg [7:0] flash_rstcounter;
81+
82+
always @(posedge sys_clk, negedge reset_n) begin
83+
if(~reset_n) begin
84+
flash_rstcounter <= 8'd0;
85+
end else begin
86+
if(trigger_reset)
87+
flash_rstcounter <= 8'd0;
88+
else if(~flash_rstcounter[7])
89+
flash_rstcounter <= flash_rstcounter + 8'd1;
90+
end
91+
end
92+
93+
assign flash_rst_n = flash_rstcounter[7];
94+
95+
/*
96+
* Clock management. Largely taken from the NWL reference design.
97+
*/
98+
99+
wire sdr_clkin;
100+
wire clkdiv;
101+
102+
IBUF #(
103+
.IOSTANDARD("DEFAULT")
104+
) clk2_iob (
105+
.I(clkin),
106+
.O(sdr_clkin)
107+
);
108+
109+
BUFIO2 #(
110+
.DIVIDE(1),
111+
.DIVIDE_BYPASS("FALSE"),
112+
.I_INVERT("FALSE")
113+
) bufio2_inst2 (
114+
.I(sdr_clkin),
115+
.IOCLK(),
116+
.DIVCLK(clkdiv),
117+
.SERDESSTROBE()
118+
);
119+
120+
wire pll1_lckd;
121+
wire buf_pll1_fb_out;
122+
wire pll1out0;
123+
wire pll1out1;
124+
wire pll1out2;
125+
wire pll1out3;
126+
127+
PLL_ADV #(
128+
.BANDWIDTH("OPTIMIZED"),
129+
.CLKFBOUT_MULT(4*f_mult),
130+
.CLKFBOUT_PHASE(0.0),
131+
.CLKIN1_PERIOD(in_period),
132+
.CLKIN2_PERIOD(in_period),
133+
.CLKOUT0_DIVIDE(f_div),
134+
.CLKOUT0_DUTY_CYCLE(0.5),
135+
.CLKOUT0_PHASE(0),
136+
.CLKOUT1_DIVIDE(f_div),
137+
.CLKOUT1_DUTY_CYCLE(0.5),
138+
.CLKOUT1_PHASE(0),
139+
.CLKOUT2_DIVIDE(4*f_div),
140+
.CLKOUT2_DUTY_CYCLE(0.5),
141+
.CLKOUT2_PHASE(0.0),
142+
.CLKOUT3_DIVIDE(2*f_div),
143+
.CLKOUT3_DUTY_CYCLE(0.5),
144+
.CLKOUT3_PHASE(90),
145+
.CLKOUT4_DIVIDE(7),
146+
.CLKOUT4_DUTY_CYCLE(0.5),
147+
.CLKOUT4_PHASE(0),
148+
.CLKOUT5_DIVIDE(7),
149+
.CLKOUT5_DUTY_CYCLE(0.5),
150+
.CLKOUT5_PHASE(0.0),
151+
.COMPENSATION("INTERNAL"),
152+
.DIVCLK_DIVIDE(1),
153+
.REF_JITTER(0.100),
154+
.CLK_FEEDBACK("CLKFBOUT"),
155+
.SIM_DEVICE("SPARTAN6")
156+
) pll1 (
157+
.CLKFBDCM(),
158+
.CLKFBOUT(buf_pll1_fb_out),
159+
.CLKOUT0(pll1out0), /* < x4 180 clock for transmitter */
160+
.CLKOUT1(pll1out1), /* < x4 180 clock for transmitter */
161+
.CLKOUT2(pll1out2), /* < x1 clock for memory controller */
162+
.CLKOUT3(pll1out3), /* < x2 90 clock to generate memory clock, clock DQS and memory address and control signals. */
163+
.CLKOUT4(),
164+
.CLKOUT5(),
165+
.CLKOUTDCM0(),
166+
.CLKOUTDCM1(),
167+
.CLKOUTDCM2(),
168+
.CLKOUTDCM3(),
169+
.CLKOUTDCM4(),
170+
.CLKOUTDCM5(),
171+
.DO(),
172+
.DRDY(),
173+
.LOCKED(pll1_lckd),
174+
.CLKFBIN(buf_pll1_fb_out),
175+
.CLKIN1(clkdiv),
176+
.CLKIN2(1'b0),
177+
.CLKINSEL(1'b1),
178+
.DADDR(5'b00000),
179+
.DCLK(1'b0),
180+
.DEN(1'b0),
181+
.DI(16'h0000),
182+
.DWE(1'b0),
183+
.RST(1'b0),
184+
.REL(1'b0)
185+
);
186+
187+
BUFPLL #(
188+
.DIVIDE(4)
189+
) wr_bufpll_left (
190+
.PLLIN(pll1out0),
191+
.GCLK(sys_clk),
192+
.LOCKED(pll1_lckd),
193+
.IOCLK(clk4x_wr_left),
194+
.LOCK(),
195+
.SERDESSTROBE(clk4x_wr_strb_left)
196+
);
197+
198+
BUFPLL #(
199+
.DIVIDE(4)
200+
) wr_bufpll_right (
201+
.PLLIN(pll1out1),
202+
.GCLK(sys_clk),
203+
.LOCKED(pll1_lckd),
204+
.IOCLK(clk4x_wr_right),
205+
.LOCK(),
206+
.SERDESSTROBE(clk4x_wr_strb_right)
207+
);
208+
209+
BUFG bufg_x1(
210+
.I(pll1out2),
211+
.O(sys_clk)
212+
);
213+
214+
BUFG bufg_x2_2(
215+
.I(pll1out3),
216+
.O(clk2x_90)
217+
);
218+
219+
/*
220+
* Generate clk4x_rd. This clock is sourced from clk2x_90.
221+
* An IODELAY2 element is included in the path of this clock so that
222+
* any variation in IDELAY element's base delay is compensated when this clock
223+
* is used to capture read data which also goes through IDELAY element.
224+
*/
225+
226+
wire rd_clk_out;
227+
228+
ODDR2 #(
229+
.DDR_ALIGNMENT("C0"),
230+
.INIT(1'b0),
231+
.SRTYPE("ASYNC")
232+
) rd_clk_out_inst (
233+
.Q(rd_clk_out),
234+
.C0(clk2x_90),
235+
.C1(~clk2x_90),
236+
.CE(1'b1),
237+
.D0(1'b1),
238+
.D1(1'b0),
239+
.R(1'b0),
240+
.S(1'b0)
241+
);
242+
243+
wire rd_clk_out_oe_n;
244+
245+
ODDR2 #(
246+
.DDR_ALIGNMENT("C0"),
247+
.INIT(1'b0),
248+
.SRTYPE("ASYNC")
249+
) rd_clk_out_oe_inst (
250+
.Q(rd_clk_out_oe_n),
251+
.C0(clk2x_90),
252+
.C1(~clk2x_90),
253+
.CE(1'b1),
254+
.D0(1'b0),
255+
.D1(1'b0),
256+
.R(1'b0),
257+
.S(1'b0)
258+
);
259+
260+
wire rd_clk_fb;
261+
262+
/* Dummy pin used for calibration */
263+
IOBUF rd_clk_loop_back_inst(
264+
.O(rd_clk_fb),
265+
.IO(rd_clk_lb),
266+
.I(rd_clk_out),
267+
.T(rd_clk_out_oe_n)
268+
);
269+
270+
wire rd_clk_fb_dly;
271+
272+
IODELAY2 #(
273+
.DATA_RATE("DDR"),
274+
.IDELAY_VALUE(0),
275+
.IDELAY2_VALUE(0),
276+
.IDELAY_MODE("NORMAL"),
277+
.ODELAY_VALUE(0),
278+
.IDELAY_TYPE("FIXED"),
279+
.COUNTER_WRAPAROUND("STAY_AT_LIMIT"),
280+
.DELAY_SRC("IDATAIN"),
281+
.SERDES_MODE("NONE"),
282+
.SIM_TAPDELAY_VALUE(49)
283+
) iodelay_cm (
284+
.IDATAIN(rd_clk_fb),
285+
.TOUT(),
286+
.DOUT(),
287+
.T(1'b1),
288+
.ODATAIN(1'b0),
289+
.DATAOUT(rd_clk_fb_dly),
290+
.DATAOUT2(),
291+
.IOCLK0(1'b0),
292+
.IOCLK1(1'b0),
293+
.CLK(1'b0),
294+
.CAL(1'b0),
295+
.INC(1'b0),
296+
.CE(1'b0),
297+
.RST(1'b0),
298+
.BUSY()
299+
);
300+
301+
wire rd_clk_fb_dly_bufio;
302+
303+
BUFIO2 #(
304+
.DIVIDE(1),
305+
.DIVIDE_BYPASS("FALSE"),
306+
.I_INVERT("FALSE")
307+
) bufio2_inst (
308+
.I(rd_clk_fb_dly),
309+
.IOCLK(),
310+
.DIVCLK(rd_clk_fb_dly_bufio),
311+
.SERDESSTROBE()
312+
);
313+
314+
wire pll2_lckd;
315+
wire buf_pll2_fb_out;
316+
wire pll2out0;
317+
wire pll2out1;
318+
319+
PLL_ADV #(
320+
.BANDWIDTH("OPTIMIZED"),
321+
.CLKFBOUT_MULT(4),
322+
.CLKFBOUT_PHASE(0.0),
323+
.CLKIN1_PERIOD(clk2x_period),
324+
.CLKIN2_PERIOD(clk2x_period),
325+
.CLKOUT0_DIVIDE(2),
326+
.CLKOUT0_DUTY_CYCLE(0.5),
327+
.CLKOUT0_PHASE(0.0),
328+
.CLKOUT1_DIVIDE(2),
329+
.CLKOUT1_DUTY_CYCLE(0.5),
330+
.CLKOUT1_PHASE(0.0),
331+
.CLKOUT2_DIVIDE(7),
332+
.CLKOUT2_DUTY_CYCLE(0.5),
333+
.CLKOUT2_PHASE(0.0),
334+
.CLKOUT3_DIVIDE(7),
335+
.CLKOUT3_DUTY_CYCLE(0.5),
336+
.CLKOUT3_PHASE(0.0),
337+
.CLKOUT4_DIVIDE(7),
338+
.CLKOUT4_DUTY_CYCLE(0.5),
339+
.CLKOUT4_PHASE(0.0),
340+
.CLKOUT5_DIVIDE(7),
341+
.CLKOUT5_DUTY_CYCLE (0.5),
342+
.CLKOUT5_PHASE(0.0),
343+
.COMPENSATION("INTERNAL"),
344+
.DIVCLK_DIVIDE(1),
345+
.REF_JITTER(0.100),
346+
.CLK_FEEDBACK("CLKFBOUT"),
347+
.SIM_DEVICE("SPARTAN6")
348+
) pll2 (
349+
.CLKFBDCM(),
350+
.CLKFBOUT(buf_pll2_fb_out),
351+
.CLKOUT0(pll2out0), /* < x4 clock to capture read data */
352+
.CLKOUT1(pll2out1), /* < x4 clock to capture read data */
353+
.CLKOUT2(),
354+
.CLKOUT3(),
355+
.CLKOUT4(),
356+
.CLKOUT5(),
357+
.CLKOUTDCM0(),
358+
.CLKOUTDCM1(),
359+
.CLKOUTDCM2(),
360+
.CLKOUTDCM3(),
361+
.CLKOUTDCM4(),
362+
.CLKOUTDCM5(),
363+
.DO(),
364+
.DRDY(),
365+
.LOCKED(pll2_lckd),
366+
.CLKFBIN(buf_pll2_fb_out),
367+
.CLKIN1(rd_clk_fb_dly_bufio),
368+
.CLKIN2(1'b0),
369+
.CLKINSEL(1'b1),
370+
.DADDR(5'b00000),
371+
.DCLK(1'b0),
372+
.DEN(1'b0),
373+
.DI(16'h0000),
374+
.DWE(1'b0),
375+
.RST(~pll1_lckd),
376+
.REL(1'b0)
377+
);
378+
379+
BUFPLL #(
380+
.DIVIDE(4)
381+
) rd_bufpll_left (
382+
.PLLIN(pll2out0),
383+
.GCLK(sys_clk),
384+
.LOCKED(pll2_lckd),
385+
.IOCLK(clk4x_rd_left),
386+
.LOCK(),
387+
.SERDESSTROBE(clk4x_rd_strb_left)
388+
);
389+
390+
BUFPLL #(
391+
.DIVIDE(4)
392+
) rd_bufpll_right (
393+
.PLLIN(pll2out1),
394+
.GCLK(sys_clk),
395+
.LOCKED(pll2_lckd),
396+
.IOCLK(clk4x_rd_right),
397+
.LOCK(),
398+
.SERDESSTROBE(clk4x_rd_strb_right)
399+
);
400+
401+
wire sdram_sys_clk_lock_d16;
402+
reg sdram_sys_clk_lock_d17;
403+
404+
/*
405+
* Async reset generation
406+
* The reset is de-asserted 16 clocks after both internal clocks are locked.
407+
*/
408+
409+
SRL16 reset_delay_sr(
410+
.CLK(sys_clk),
411+
.D(pll1_lckd & pll2_lckd),
412+
.A0(1'b1),
413+
.A1(1'b1),
414+
.A2(1'b1),
415+
.A3(1'b1),
416+
.Q(sdram_sys_clk_lock_d16)
417+
);
418+
419+
always @(posedge sys_clk)
420+
sdram_sys_clk_lock_d17 <= sdram_sys_clk_lock_d16;
421+
422+
assign reset_n = sdram_sys_clk_lock_d17;
423+
424+
endmodule

‎verilog/m1reset/m1reset.v

-62
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.