cpu/vexriscv_smp: cleanup, fix coherent_dma connection.
[litex.git] / litex / soc / cores / cpu / vexriscv_smp / core.py
1 # This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2020 Dolu1990 <charles.papon.90@gmail.com>
3 # License: BSD
4
5 import os
6 from os import path
7
8 from litex import get_data_mod
9 from migen import *
10
11 from litex.soc.interconnect import wishbone
12 from litex.soc.interconnect.csr import *
13 from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
14
15 import os
16
17
18 CPU_VARIANTS = {
19 "linux": "VexRiscv",
20 }
21
22 class Open(Signal): pass
23
24 class VexRiscvSMP(CPU):
25 name = "vexriscv"
26 human_name = "VexRiscv SMP"
27 variants = CPU_VARIANTS
28 data_width = 32
29 endianness = "little"
30 gcc_triple = CPU_GCC_TRIPLE_RISCV32
31 linker_output_format = "elf32-littleriscv"
32 nop = "nop"
33 io_regions = {0x80000000: 0x80000000} # origin, length
34
35 cpu_count = 1
36 dcache_size = 4096
37 icache_size = 4096
38 dcache_ways = 1
39 icache_ways = 1
40 coherent_dma = False
41 litedram_width = 32
42 dcache_width = 32
43 icache_width = 32
44
45 @staticmethod
46 def args_fill(parser):
47 parser.add_argument("--cpu-count", default=1, help="")
48 parser.add_argument("--dcache-width", default=None, help="L1 data cache bus width")
49 parser.add_argument("--icache-width", default=None, help="L1 instruction cache bus width")
50 parser.add_argument("--dcache-size", default=None, help="L1 data cache size in byte per CPU")
51 parser.add_argument("--dcache-ways", default=None, help="L1 data cache ways per CPU")
52 parser.add_argument("--icache-size", default=None, help="L1 instruction cache size in byte per CPU")
53 parser.add_argument("--icache-ways", default=None, help="L1 instruction cache ways per CPU")
54
55
56 @staticmethod
57 def args_read(args):
58 VexRiscvSMP.cpu_count = args.cpu_count
59 if args.cpu_count != 1:
60 VexRiscvSMP.icache_width = 64
61 VexRiscvSMP.dcache_width = 64
62 VexRiscvSMP.dcache_size = 8192
63 VexRiscvSMP.icache_size = 8192
64 VexRiscvSMP.dcache_ways = 2
65 VexRiscvSMP.icache_ways = 2
66 VexRiscvSMP.coherent_dma = True
67 if(args.dcache_width): VexRiscvSMP.dcache_width = args.dcache_width
68 if(args.icache_width): VexRiscvSMP.icache_width = args.icache_width
69 if(args.icache_width): VexRiscvSMP.dcache_size = args.dcache_size
70 if(args.icache_width): VexRiscvSMP.icache_size = args.icache_size
71 if(args.icache_width): VexRiscvSMP.dcache_ways = args.dcache_ways
72 if(args.icache_width): VexRiscvSMP.icache_ways = args.icache_ways
73
74 @property
75 def mem_map(self):
76 return {
77 "rom": 0x00000000,
78 "sram": 0x10000000,
79 "main_ram": 0x40000000,
80 "csr": 0xf0000000,
81 "clint": 0xf0010000,
82 }
83
84 @property
85 def gcc_flags(self):
86 flags = " -march=rv32ima -mabi=ilp32"
87 flags += " -D__vexriscv__"
88 flags += " -DUART_POLLING"
89 return flags
90
91 @staticmethod
92 def generate_cluster_name():
93 VexRiscvSMP.cluster_name = f"VexRiscvLitexSmpCluster_" \
94 f"Cc{VexRiscvSMP.cpu_count}" \
95 "_" \
96 f"Iw{VexRiscvSMP.icache_width}" \
97 f"Is{VexRiscvSMP.icache_size}" \
98 f"Iy{VexRiscvSMP.icache_ways}" \
99 "_" \
100 f"Dw{VexRiscvSMP.dcache_width}" \
101 f"Ds{VexRiscvSMP.dcache_size}" \
102 f"Dy{VexRiscvSMP.dcache_ways}" \
103 "_" \
104 f"Ldw{VexRiscvSMP.litedram_width}" \
105 f"{'_Cdma' if VexRiscvSMP.coherent_dma else ''}"
106
107 @staticmethod
108 def generate_default_configs():
109 # Single cores
110 for data_width in [16, 32, 64, 128]:
111 VexRiscvSMP.litedram_width = data_width
112 VexRiscvSMP.icache_width = 32
113 VexRiscvSMP.dcache_width = 32
114 VexRiscvSMP.coherent_dma = False
115 VexRiscvSMP.cpu_count = 1
116
117 # Low cache amount
118 VexRiscvSMP.dcache_size = 4096
119 VexRiscvSMP.icache_size = 4096
120 VexRiscvSMP.dcache_ways = 1
121 VexRiscvSMP.icache_ways = 1
122
123 # Without DMA
124 VexRiscvSMP.coherent_dma = False
125 VexRiscvSMP.generate_cluster_name()
126 VexRiscvSMP.generate_netlist()
127
128 # With DMA
129 VexRiscvSMP.coherent_dma = True
130 VexRiscvSMP.generate_cluster_name()
131 VexRiscvSMP.generate_netlist()
132
133 # High cache amount
134 VexRiscvSMP.dcache_size = 8192
135 VexRiscvSMP.icache_size = 8192
136 VexRiscvSMP.dcache_ways = 2
137 VexRiscvSMP.icache_ways = 2
138 VexRiscvSMP.icache_width = 32 if data_width < 64 else 64
139 VexRiscvSMP.dcache_width = 32 if data_width < 64 else 64
140
141 # Without DMA
142 VexRiscvSMP.coherent_dma = False
143 VexRiscvSMP.generate_cluster_name()
144 VexRiscvSMP.generate_netlist()
145
146 # With DMA
147 VexRiscvSMP.coherent_dma = True
148 VexRiscvSMP.generate_cluster_name()
149 VexRiscvSMP.generate_netlist()
150
151 # Multi cores
152 for core_count in [2,4]:
153 VexRiscvSMP.litedram_width = 128
154 VexRiscvSMP.icache_width = 64
155 VexRiscvSMP.dcache_width = 64
156 VexRiscvSMP.dcache_size = 8192
157 VexRiscvSMP.icache_size = 8192
158 VexRiscvSMP.dcache_ways = 2
159 VexRiscvSMP.icache_ways = 2
160 VexRiscvSMP.coherent_dma = True
161 VexRiscvSMP.cpu_count = core_count
162 VexRiscvSMP.generate_cluster_name()
163 VexRiscvSMP.generate_netlist()
164
165 @staticmethod
166 def generate_netlist():
167 print(f"Generating cluster netlist")
168 vdir = get_data_mod("cpu", "vexriscv_smp").data_location
169 gen_args = []
170 if(VexRiscvSMP.coherent_dma):
171 gen_args.append("--coherent-dma")
172 gen_args.append(f"--cpu-count={VexRiscvSMP.cpu_count}")
173 gen_args.append(f"--ibus-width={VexRiscvSMP.icache_width}")
174 gen_args.append(f"--dbus-width={VexRiscvSMP.dcache_width}")
175 gen_args.append(f"--dcache-size={VexRiscvSMP.dcache_size}")
176 gen_args.append(f"--icache-size={VexRiscvSMP.icache_size}")
177 gen_args.append(f"--dcache-ways={VexRiscvSMP.dcache_ways}")
178 gen_args.append(f"--icache-ways={VexRiscvSMP.icache_ways}")
179 gen_args.append(f"--litedram-width={VexRiscvSMP.litedram_width}")
180 gen_args.append(f"--netlist-name={VexRiscvSMP.cluster_name}")
181 gen_args.append(f"--netlist-directory={vdir}")
182
183 cmd = 'cd {path} && sbt "runMain vexriscv.demo.smp.VexRiscvLitexSmpClusterCmdGen {args}"'.format(path=os.path.join(vdir, "ext", "VexRiscv"), args=" ".join(gen_args))
184 os.system(cmd)
185
186 def __init__(self, platform, variant):
187 self.platform = platform
188 self.variant = "standard"
189 self.human_name = self.human_name + "-" + variant.upper()
190 self.reset = Signal()
191 self.jtag_clk = Signal()
192 self.jtag_enable = Signal()
193 self.jtag_capture = Signal()
194 self.jtag_shift = Signal()
195 self.jtag_update = Signal()
196 self.jtag_reset = Signal()
197 self.jtag_tdo = Signal()
198 self.jtag_tdi = Signal()
199 self.interrupt = Signal(32)
200 self.pbus = pbus = wishbone.Interface()
201 self.cbus = cbus = wishbone.Interface()
202 self.plicbus = plicbus = wishbone.Interface()
203
204 self.periph_buses = [pbus]
205 self.memory_buses = [] # Added dynamically
206
207 # # #
208 self.cpu_params = dict(
209 # Clk / Rst
210 i_debugCd_external_clk = ClockSignal(),
211 i_debugCd_external_reset = ResetSignal() | self.reset,
212
213 # Interrupts
214 i_interrupts = self.interrupt,
215
216 # JTAG
217 i_jtag_clk = self.jtag_clk,
218 i_debugPort_enable = self.jtag_enable,
219 i_debugPort_capture = self.jtag_capture,
220 i_debugPort_shift = self.jtag_shift,
221 i_debugPort_update = self.jtag_update,
222 i_debugPort_reset = self.jtag_reset,
223 i_debugPort_tdi = self.jtag_tdi,
224 o_debugPort_tdo = self.jtag_tdo,
225
226 # Peripheral Bus (Master)
227 o_peripheral_CYC = pbus.cyc,
228 o_peripheral_STB = pbus.stb,
229 i_peripheral_ACK = pbus.ack,
230 o_peripheral_WE = pbus.we,
231 o_peripheral_ADR = pbus.adr,
232 i_peripheral_DAT_MISO = pbus.dat_r,
233 o_peripheral_DAT_MOSI = pbus.dat_w,
234 o_peripheral_SEL = pbus.sel,
235 i_peripheral_ERR = pbus.err,
236 o_peripheral_CTI = pbus.cti,
237 o_peripheral_BTE = pbus.bte,
238
239 # CLINT Bus (Slave)
240 i_clintWishbone_CYC = cbus.cyc,
241 i_clintWishbone_STB = cbus.stb,
242 o_clintWishbone_ACK = cbus.ack,
243 i_clintWishbone_WE = cbus.we,
244 i_clintWishbone_ADR = cbus.adr,
245 o_clintWishbone_DAT_MISO = cbus.dat_r,
246 i_clintWishbone_DAT_MOSI = cbus.dat_w,
247
248 # PLIC Bus (Slave)
249 i_plicWishbone_CYC = plicbus.cyc,
250 i_plicWishbone_STB = plicbus.stb,
251 o_plicWishbone_ACK = plicbus.ack,
252 i_plicWishbone_WE = plicbus.we,
253 i_plicWishbone_ADR = plicbus.adr,
254 o_plicWishbone_DAT_MISO = plicbus.dat_r,
255 i_plicWishbone_DAT_MOSI = plicbus.dat_w
256 )
257
258 def set_reset_address(self, reset_address):
259 assert not hasattr(self, "reset_address")
260 self.reset_address = reset_address
261 assert reset_address == 0x00000000
262
263 def add_sources(self, platform):
264 vdir = get_data_mod("cpu", "vexriscv_smp").data_location
265 print(f"VexRiscv cluster : {self.cluster_name}")
266 if not path.exists(os.path.join(vdir, self.cluster_name + ".v")):
267 self.generate_netlist()
268
269 platform.add_source(os.path.join(vdir, "RamXilinx.v"), "verilog")
270 platform.add_source(os.path.join(vdir, self.cluster_name + ".v"), "verilog")
271
272 def add_memory_buses(self, address_width, data_width):
273 VexRiscvSMP.litedram_width = data_width
274
275 VexRiscvSMP.generate_cluster_name()
276 if VexRiscvSMP.coherent_dma:
277 self.dma_bus = dma_bus = wishbone.Interface(data_width=VexRiscvSMP.dcache_width)
278 dma_bus_stall = Signal()
279 dma_bus_inhibit = Signal()
280 self.cpu_params.update(
281 i_dma_wishbone_CYC = dma_bus.cyc,
282 i_dma_wishbone_STB = dma_bus.stb & ~dma_bus_inhibit,
283 o_dma_wishbone_ACK = dma_bus.ack,
284 i_dma_wishbone_WE = dma_bus.we,
285 i_dma_wishbone_SEL = dma_bus.sel,
286 i_dma_wishbone_ADR = dma_bus.adr,
287 o_dma_wishbone_DAT_MISO = dma_bus.dat_r,
288 i_dma_wishbone_DAT_MOSI = dma_bus.dat_w,
289 o_dma_wishbone_STALL = dma_bus_stall
290 )
291 self.sync += [
292 If(dma_bus.stb & dma_bus.cyc & ~dma_bus_stall,
293 dma_bus_inhibit.eq(1),
294 ),
295 If(dma_bus.ack,
296 dma_bus_inhibit.eq(0)
297 )
298 ]
299
300 from litedram.common import LiteDRAMNativePort
301 ibus = LiteDRAMNativePort(mode="both", address_width=32, data_width=VexRiscvSMP.litedram_width)
302 dbus = LiteDRAMNativePort(mode="both", address_width=32, data_width=VexRiscvSMP.litedram_width)
303 self.memory_buses.append(ibus)
304 self.memory_buses.append(dbus)
305 self.cpu_params.update(
306 # Instruction Memory Bus (Master)
307 o_iBridge_dram_cmd_valid = ibus.cmd.valid,
308 i_iBridge_dram_cmd_ready = ibus.cmd.ready,
309 o_iBridge_dram_cmd_payload_we = ibus.cmd.we,
310 o_iBridge_dram_cmd_payload_addr = ibus.cmd.addr,
311 o_iBridge_dram_wdata_valid = ibus.wdata.valid,
312 i_iBridge_dram_wdata_ready = ibus.wdata.ready,
313 o_iBridge_dram_wdata_payload_data = ibus.wdata.data,
314 o_iBridge_dram_wdata_payload_we = ibus.wdata.we,
315 i_iBridge_dram_rdata_valid = ibus.rdata.valid,
316 o_iBridge_dram_rdata_ready = ibus.rdata.ready,
317 i_iBridge_dram_rdata_payload_data = ibus.rdata.data,
318
319 # Data Memory Bus (Master)
320 o_dBridge_dram_cmd_valid = dbus.cmd.valid,
321 i_dBridge_dram_cmd_ready = dbus.cmd.ready,
322 o_dBridge_dram_cmd_payload_we = dbus.cmd.we,
323 o_dBridge_dram_cmd_payload_addr = dbus.cmd.addr,
324 o_dBridge_dram_wdata_valid = dbus.wdata.valid,
325 i_dBridge_dram_wdata_ready = dbus.wdata.ready,
326 o_dBridge_dram_wdata_payload_data = dbus.wdata.data,
327 o_dBridge_dram_wdata_payload_we = dbus.wdata.we,
328 i_dBridge_dram_rdata_valid = dbus.rdata.valid,
329 o_dBridge_dram_rdata_ready = dbus.rdata.ready,
330 i_dBridge_dram_rdata_payload_data = dbus.rdata.data,
331 )
332
333
334 def do_finalize(self):
335 assert hasattr(self, "reset_address")
336 self.specials += Instance(self.cluster_name, **self.cpu_params)
337
338 # Add verilog sources
339 self.add_sources(self.platform)