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