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