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.
9 # this is a System Console peripheral compatible with microwatt
10 # https://github.com/antonblanchard/microwatt/blob/master/syscon.vhdl
12 from nmigen
import (Elaboratable
, Cat
, Module
, Signal
)
13 from nmigen
.cli
import rtlil
, verilog
15 from lambdasoc
.periph
import Peripheral
17 __all__
= ["MicrowattSYSCON"]
20 class MicrowattSYSCON(Peripheral
, Elaboratable
):
21 """Microwatt-compatible (Sys)tem (Con)figuration module
24 def __init__(self
, *, sys_clk_freq
=100e6
,
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
41 # System control ports
42 self
.dram_at_0
= Signal()
43 self
.core_reset
= Signal()
44 self
.soc_reset
= Signal()
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
._uart
0_info
_r
= bank
.csr(64, "r") # UART0 info (baud etc.)
60 self
._uart
1_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
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
71 def elaborate(self
, platform
):
73 comb
, sync
= m
.d
.comb
, m
.d
.comb
74 m
.submodules
.bridge
= self
._bridge
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.
79 # identifying signature
80 comb
+= self
._reg
_sig
_r
.r_data
.eq(0xf00daa5500010001)
82 # nest clock rate (hz)
83 comb
+= self
._clk
_info
_r
.r_data
.eq(int(self
.sys_clk_freq
)) # in hz
85 # core clock rate (hz)
86 comb
+= self
._core
_clk
_info
_r
.r_data
.eq(int(self
.core_clk_freq
)) # in hz
88 # memory clock rate (hz)
89 comb
+= self
._mem
_clk
_info
_r
.r_data
.eq(int(self
.mem_clk_freq
)) # in hz
92 has_spi
= self
.spi_offset
is not None
93 has_dram
= self
.dram_addr
is not None
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
._uart
0_info
_r
.r_data
[0:32].eq(int(self
.sys_clk_freq
))
99 comb
+= self
._uart
0_info
_r
.r_data
[32].eq(1)
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
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
)
114 comb
+= self
._spiflash
_info
_r
.r_data
.eq(self
.spi_offset
or 0)
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
:
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
:
130 if __name__
== "__main__":
131 from nmigen_soc
import wishbone
132 class QuickDemo(Elaboratable
):
133 def elaborate(self
, platform
):
135 arbiter
= wishbone
.Arbiter(addr_width
=30, data_width
=32,
137 decoder
= wishbone
.Decoder(addr_width
=30, data_width
=32,
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
)
146 create_ilang(m
, None, "syscondemo")