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