|
1 | 1 | from amaranth import * |
2 | | -from amaranth.lib.cdc import ResetSynchronizer |
3 | 2 | from amaranth.vendor import LatticeICE40Platform |
4 | 3 |
|
5 | | -from ..build_plan import GatewareBuildError |
6 | 4 | from . import GlasgowPlatform |
7 | 5 |
|
8 | 6 |
|
|
12 | 10 | class GlasgowICE40Platform(GlasgowPlatform, LatticeICE40Platform): |
13 | 11 | def bitstream_filename(self, design_name): |
14 | 12 | return f"{design_name}.bin" |
15 | | - |
16 | | - def get_pll(self, pll, simple_feedback=True): |
17 | | - if not 10e6 <= pll.f_in <= 133e6: |
18 | | - pll.logger.error("PLL: f_in (%.3f MHz) must be between 10 and 133 MHz", |
19 | | - pll.f_in / 1e6) |
20 | | - raise GatewareBuildError("PLL f_in out of range") |
21 | | - |
22 | | - if not 16e6 <= pll.f_out <= 275e6: |
23 | | - pll.logger.error("PLL: f_out (%.3f MHz) must be between 16 and 275 MHz", |
24 | | - pll.f_out / 1e6) |
25 | | - raise GatewareBuildError("PLL f_out out of range") |
26 | | - |
27 | | - # The documentation in the iCE40 PLL Usage Guide incorrectly lists the |
28 | | - # maximum value of DIVF as 63, when it is only limited to 63 when using |
29 | | - # feedback modes other that SIMPLE. |
30 | | - if simple_feedback: |
31 | | - divf_max = 128 |
32 | | - else: |
33 | | - divf_max = 64 |
34 | | - |
35 | | - variants = [] |
36 | | - for divr in range(0, 16): |
37 | | - f_pfd = pll.f_in / (divr + 1) |
38 | | - if not 10e6 <= f_pfd <= 133e6: |
39 | | - continue |
40 | | - |
41 | | - for divf in range(0, divf_max): |
42 | | - if simple_feedback: |
43 | | - f_vco = f_pfd * (divf + 1) |
44 | | - if not 533e6 <= f_vco <= 1066e6: |
45 | | - continue |
46 | | - |
47 | | - for divq in range(1, 7): |
48 | | - f_out = f_vco * (2 ** -divq) |
49 | | - variants.append((divr, divf, divq, f_pfd, f_out)) |
50 | | - |
51 | | - else: |
52 | | - for divq in range(1, 7): |
53 | | - f_vco = f_pfd * (divf + 1) * (2 ** divq) |
54 | | - if not 533e6 <= f_vco <= 1066e6: |
55 | | - continue |
56 | | - |
57 | | - f_out = f_vco * (2 ** -divq) |
58 | | - variants.append((divr, divf, divq, f_pfd, f_out)) |
59 | | - |
60 | | - if not variants: |
61 | | - pll.logger.error("PLL: f_in (%.3f MHz) to f_out (%.3f) constraints not satisfiable", |
62 | | - pll.f_in / 1e6, pll.f_out / 1e6) |
63 | | - raise GatewareBuildError("PLL f_in/f_out out of range") |
64 | | - |
65 | | - def f_out_diff(variant): |
66 | | - *_, f_out = variant |
67 | | - return abs(f_out - pll.f_out) |
68 | | - divr, divf, divq, f_pfd, f_out = min(variants, key=f_out_diff) |
69 | | - |
70 | | - if f_pfd < 17: |
71 | | - filter_range = 1 |
72 | | - elif f_pfd < 26: |
73 | | - filter_range = 2 |
74 | | - elif f_pfd < 44: |
75 | | - filter_range = 3 |
76 | | - elif f_pfd < 66: |
77 | | - filter_range = 4 |
78 | | - elif f_pfd < 101: |
79 | | - filter_range = 5 |
80 | | - else: |
81 | | - filter_range = 6 |
82 | | - |
83 | | - if simple_feedback: |
84 | | - feedback_path = "SIMPLE" |
85 | | - else: |
86 | | - feedback_path = "NON_SIMPLE" |
87 | | - |
88 | | - ppm = abs(pll.f_out - f_out) / pll.f_out * 1e6 |
89 | | - |
90 | | - pll.logger.debug("PLL: f_in=%.3f f_out(req)=%.3f f_out(act)=%.3f [MHz] ppm=%d", |
91 | | - pll.f_in / 1e6, pll.f_out / 1e6, f_out / 1e6, ppm) |
92 | | - pll.logger.trace("iCE40 PLL: feedback_path=%s divr=%d divf=%d divq=%d filter_range=%d", |
93 | | - feedback_path, divr, divf, divq, filter_range) |
94 | | - |
95 | | - m = Module() |
96 | | - locked = Signal() |
97 | | - m.submodules.reset_sync = ResetSynchronizer(~locked, domain=pll.odomain) |
98 | | - m.submodules.pll_core = Instance("SB_PLL40_CORE", |
99 | | - p_FEEDBACK_PATH=feedback_path, |
100 | | - p_PLLOUT_SELECT="GENCLK", |
101 | | - p_DIVR=divr, |
102 | | - p_DIVF=divf, |
103 | | - p_DIVQ=divq, |
104 | | - p_FILTER_RANGE=filter_range, |
105 | | - i_REFERENCECLK=ClockSignal(pll.idomain), |
106 | | - o_PLLOUTCORE=ClockSignal(pll.odomain), |
107 | | - i_RESETB=~ResetSignal(pll.idomain), |
108 | | - o_LOCK=locked, |
109 | | - i_BYPASS=Const(0), |
110 | | - ) |
111 | | - return m |
0 commit comments