23286b7a79906b4f0281eb2a8ebd6fb6931188dc
[soc.git] / src / soc / clock / select.py
1 """Clock selection.
2
3 * PLL @ 300mhz input generates a div-6 "test" output
4 * clock select sets the source
5 - 0b000 - CLK_24 (direct)
6 - 0b001 - PLL / 6
7 - 0b010 - PLL / 4
8 - 0b011 - PLL / 3
9 - 0b100 - PLL / 2
10 - 0b101 - PLL
11 - 0b110 - ZERO (direct driving in combination with ONE)
12 - 0b111 - ONE
13 * this is all assumed to be driven by the "PLL CLK".
14 the CLK_24 is the default in case PLL is unstable
15 """
16
17 from nmigen import (Module, Array, Signal, Mux, Elaboratable, ClockSignal,
18 ResetSignal)
19 from nmigen.cli import rtlil
20
21 CLK_24 = 0b000 # this is the default (clk_sel_i = 0 on reset)
22 PLL6 = 0b001
23 PLL4 = 0b010
24 PLL3 = 0b011
25 PLL2 = 0b100
26 PLL = 0b101
27 ZERO = 0b110
28 ONE = 0b111
29
30
31 class ClockSelect(Elaboratable):
32 def __init__(self):
33
34 self.clk_24_i = Signal() # 24 mhz external incoming
35 self.pll_48_o = Signal() # 6-divide (test signal) from PLL
36 self.clk_sel_i = Signal(3) # clock source selection
37 self.core_clk_o = Signal() # main core clock (selectable)
38 self.rst = Signal() # reset
39
40 def elaborate(self, platform):
41 m = Module()
42 comb, sync = m.d.comb, m.d.sync
43 m.d.comb += ResetSignal().eq(self.rst)
44
45 # array of clocks (selectable by clk_sel_i)
46 clkgen = Array([Signal(name="clk%d" % i) for i in range(8)])
47 counter3 = Signal(2) # for divide-by-3
48
49 # set up system, zero and one clocks
50 comb += clkgen[CLK_24].eq(self.clk_24_i) # 1st is external 24mhz
51 comb += clkgen[ZERO].eq(0) # LOW (use with ONE for direct driving)
52 comb += clkgen[ONE].eq(1) # HI
53
54 # (always) generate PLL-driven signals: /2/3/4/6
55 sync += clkgen[PLL2].eq(~clkgen[PLL2]) # half PLL rate
56 with m.If(clkgen[PLL2]):
57 sync += clkgen[PLL4].eq(~clkgen[PLL4]) # quarter PLL rate
58 with m.If(counter3 == 2):
59 sync += counter3.eq(0)
60 sync += clkgen[PLL3].eq(~clkgen[PLL3]) # 1/3 PLL rate
61 with m.If(clkgen[PLL3]):
62 sync += clkgen[PLL6].eq(~clkgen[PLL6]) # 1/6 PLL rate
63 with m.Else():
64 sync += counter3.eq(counter3+1)
65
66 # select from available array of clock sources
67 comb += self.core_clk_o.eq(clkgen[self.clk_sel_i])
68
69 # 48mhz output is PLL/6
70 comb += self.pll_48_o.eq(clkgen[PLL6])
71
72 return m
73
74 def ports(self):
75 return [self.clk_24_i, self.pll_48_o, self.clk_sel_i, self.core_clk_o]
76
77
78 class DummyPLL(Elaboratable):
79 def __init__(self):
80 self.clk_24_i = Signal() # 24 mhz external incoming
81 self.clk_pll_o = Signal() # output fake PLL clock
82 self.rst = Signal() # reset
83
84 def elaborate(self, platform):
85 m = Module()
86 m.d.comb += self.clk_pll_o.eq(self.clk_24_i) # just pass through
87 m.d.comb += ResetSignal().eq(self.rst)
88
89 return m
90
91 def ports(self):
92 return [self.clk_24_i, self.clk_pll_o]
93
94
95 if __name__ == '__main__':
96 dut = ClockSelect()
97
98 vl = rtlil.convert(dut, ports=dut.ports())
99 with open("test_clk_sel.il", "w") as f:
100 f.write(vl)
101