5ca7ba9065fcc4f7e038e2c74375f7cc7e4fa6b3
[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
39 def elaborate(self, platform):
40 m = Module()
41 comb, sync = m.d.comb, m.d.sync
42
43 # array of clocks (selectable by clk_sel_i)
44 clkgen = Array([Signal(name="clk%d" % i) for i in range(8)])
45 counter3 = Signal(2) # for divide-by-3
46
47 # set up system, zero and one clocks
48 comb += clkgen[CLK_24].eq(self.clk_24_i) # 1st is external 24mhz
49 comb += clkgen[ZERO].eq(0) # LOW (use with ONE for direct driving)
50 comb += clkgen[ONE].eq(1) # HI
51
52 # (always) generate PLL-driven signals: /2/3/4/6
53 sync += clkgen[PLL2].eq(~clkgen[PLL2]) # half PLL rate
54 with m.If(clkgen[PLL2]):
55 sync += clkgen[PLL4].eq(~clkgen[PLL4]) # quarter PLL rate
56 with m.If(counter3 == 2):
57 sync += counter3.eq(0)
58 sync += clkgen[PLL3].eq(~clkgen[PLL3]) # 1/3 PLL rate
59 with m.If(clkgen[PLL3]):
60 sync += clkgen[PLL6].eq(~clkgen[PLL6]) # 1/6 PLL rate
61 with m.Else():
62 sync += counter3.eq(counter3+1)
63
64 # select from available array of clock sources
65 comb += self.core_clk_o.eq(clkgen[self.clk_sel_i])
66
67 # 48mhz output is PLL/6
68 comb += self.pll_48_o.eq(clkgen[PLL6])
69
70 return m
71
72 def ports(self):
73 return [self.clk_24_i, self.pll_48_o, self.clk_sel_i, self.core_clk_o]
74
75
76 class DummyPLL(Elaboratable):
77 def __init__(self):
78 self.clk_24_i = Signal() # 24 mhz external incoming
79 self.clk_pll_o = Signal() # output fake PLL clock
80
81 def elaborate(self, platform):
82 m = Module()
83 m.d.comb += self.clk_pll_o.eq(self.clk_24_i) # just pass through
84
85 return m
86
87 def ports(self):
88 return [self.clk_24_i, self.clk_pll_o]
89
90
91 if __name__ == '__main__':
92 dut = ClockSelect()
93
94 vl = rtlil.convert(dut, ports=dut.ports())
95 with open("test_clk_sel.il", "w") as f:
96 f.write(vl)
97