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