Add separate memory clock register to SYSCON
[soc.git] / src / soc / bus / syscon.py
1 #!/usr/bin/env python3
2 #
3 # SPDX-License-Identifier: LGPLv3+
4 # Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # Copyright (C) 2022 Raptor Engineering, LLC <support@raptorengineering.com>
6 # Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073
7 # Part of the Libre-SOC Project.
8 #
9 # this is a System Console peripheral compatible with microwatt
10 # https://github.com/antonblanchard/microwatt/blob/master/syscon.vhdl
11
12 from nmigen import (Elaboratable, Cat, Module, Signal)
13 from nmigen.cli import rtlil, verilog
14
15 from lambdasoc.periph import Peripheral
16
17 __all__ = ["MicrowattSYSCON"]
18
19
20 class MicrowattSYSCON(Peripheral, Elaboratable):
21 """Microwatt-compatible (Sys)tem (Con)figuration module
22 """
23
24 def __init__(self, *, sys_clk_freq=100e6,
25 core_clk_freq=100e6,
26 mem_clk_freq=100e6,
27 spi_offset=None,
28 dram_addr=None,
29 has_uart=True,
30 uart_is_16550=True
31 ):
32 super().__init__(name="syscon")
33 self.sys_clk_freq = sys_clk_freq
34 self.core_clk_freq = core_clk_freq
35 self.mem_clk_freq = mem_clk_freq
36 self.has_uart = has_uart
37 self.spi_offset = spi_offset
38 self.dram_addr = dram_addr
39 self.uart_is_16550 = uart_is_16550
40
41 # System control ports
42 self.dram_at_0 = Signal()
43 self.core_reset = Signal()
44 self.soc_reset = Signal()
45
46 # set up a CSR Bank and associated bridge. has to be in this order
47 # (declare bank, declare bridge) for some unknown reason.
48 # (r)ead regs will have a r_stb and r_data Record entry
49 # (w)rite regs will have a w_stb and w_data Record entry
50 bank = self.csr_bank()
51 self._reg_sig_r = bank.csr(64, "r") # signature
52 self._reg_info_r = bank.csr(64, "r") # info
53 self._bram_info_r = bank.csr(64, "r") # bram info
54 self._dram_info_r = bank.csr(64, "r") # dram info
55 self._clk_info_r = bank.csr(64, "r") # nest clock frequency
56 self._ctrl_info_r = bank.csr(64, "rw") # control info
57 self._dram_init_r = bank.csr(64, "r") # dram initialisation info
58 self._spiflash_info_r = bank.csr(64, "r") # spi flash info
59 self._uart0_info_r = bank.csr(64, "r") # UART0 info (baud etc.)
60 self._uart1_info_r = bank.csr(64, "r") # UART1 info (baud etc.)
61 self._bram_bootaddr_r = bank.csr(64, "r") # BRAM boot address
62 self._core_clk_info_r = bank.csr(64, "r") # core clock frequency
63 self._mem_clk_info_r = bank.csr(64, "r") # memory clock frequency
64
65 # bridge the above-created CSRs over wishbone. ordering and size
66 # above mattered, the bridge automatically packs them together
67 # as memory-addressable "things" for us
68 self._bridge = self.bridge(data_width=32, granularity=8, alignment=3)
69 self.bus = self._bridge.bus
70
71 def elaborate(self, platform):
72 m = Module()
73 comb, sync = m.d.comb, m.d.comb
74 m.submodules.bridge = self._bridge
75
76 # enter data into the CSRs. r_data can be left live all the time,
77 # w_data obviously has to be set only when w_stb triggers.
78
79 # identifying signature
80 comb += self._reg_sig_r.r_data.eq(0xf00daa5500010001)
81
82 # nest clock rate (hz)
83 comb += self._clk_info_r.r_data.eq(int(self.sys_clk_freq)) # in hz
84
85 # core clock rate (hz)
86 comb += self._core_clk_info_r.r_data.eq(int(self.core_clk_freq)) # in hz
87
88 # memory clock rate (hz)
89 comb += self._mem_clk_info_r.r_data.eq(int(self.mem_clk_freq)) # in hz
90
91 # detect peripherals
92 has_spi = self.spi_offset is not None
93 has_dram = self.dram_addr is not None
94
95 # uart peripheral clock rate, currently assumed to be system clock
96 # 0 ..31 : UART clock freq (in HZ)
97 # 32 : UART is 16550 (otherwise pp)
98 comb += self._uart0_info_r.r_data[0:32].eq(int(self.sys_clk_freq))
99 comb += self._uart0_info_r.r_data[32].eq(1)
100
101 # Reg Info, defines what peripherals and characteristics are present
102 comb += self._reg_info_r.r_data[0].eq(self.has_uart) # has UART0
103 comb += self._reg_info_r.r_data[1].eq(has_dram) # has DDR DRAM
104 comb += self._reg_info_r.r_data[3].eq(has_spi) # has SPI Flash
105 comb += self._reg_info_r.r_data[5].eq(1) # Large SYSCON
106
107 # system control
108 sysctrl = Cat(self.dram_at_0, self.core_reset, self.soc_reset)
109 with m.If(self._ctrl_info_r.w_stb):
110 sync += sysctrl.eq(self._ctrl_info_r.w_data)
111 comb += self._ctrl_info_r.r_data.eq(sysctrl)
112
113 # SPI Flash Address
114 comb += self._spiflash_info_r.r_data.eq(self.spi_offset or 0)
115
116 return m
117
118
119 def create_ilang(dut, ports, test_name):
120 vl = rtlil.convert(dut, name=test_name, ports=ports)
121 with open("%s.il" % test_name, "w") as f:
122 f.write(vl)
123
124 def create_verilog(dut, ports, test_name):
125 vl = verilog.convert(dut, name=test_name, ports=ports)
126 with open("%s.v" % test_name, "w") as f:
127 f.write(vl)
128
129
130 if __name__ == "__main__":
131 from nmigen_soc import wishbone
132 class QuickDemo(Elaboratable):
133 def elaborate(self, platform):
134 m = Module()
135 arbiter = wishbone.Arbiter(addr_width=30, data_width=32,
136 granularity=8)
137 decoder = wishbone.Decoder(addr_width=30, data_width=32,
138 granularity=8)
139 m.submodules.syscon = syscon = MicrowattSYSCON()
140 m.submodules.decoder = decoder
141 m.submodules.arbiter = arbiter
142 decoder.add(syscon.bus, addr=0xc0000000)
143 m.d.comb += arbiter.bus.connect(decoder.bus)
144 return m
145 m = QuickDemo()
146 create_ilang(m, None, "syscondemo")
147