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>
8 from litex
import get_data_mod
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
22 class Open(Signal
): pass
24 class VexRiscvSMP(CPU
):
26 human_name
= "VexRiscv SMP"
27 variants
= CPU_VARIANTS
30 gcc_triple
= CPU_GCC_TRIPLE_RISCV32
31 linker_output_format
= "elf32-littleriscv"
33 io_regions
= {0x80000000: 0x80000000} # origin, length
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")
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
)
83 "main_ram": 0x40000000,
90 flags
= " -march=rv32ima -mabi=ilp32"
91 flags
+= " -D__vexriscv__"
92 flags
+= " -DUART_POLLING"
96 def generate_cluster_name():
97 VexRiscvSMP
.cluster_name
= f
"VexRiscvLitexSmpCluster_" \
98 f
"Cc{VexRiscvSMP.cpu_count}" \
100 f
"Iw{VexRiscvSMP.icache_width}" \
101 f
"Is{VexRiscvSMP.icache_size}" \
102 f
"Iy{VexRiscvSMP.icache_ways}" \
104 f
"Dw{VexRiscvSMP.dcache_width}" \
105 f
"Ds{VexRiscvSMP.dcache_size}" \
106 f
"Dy{VexRiscvSMP.dcache_ways}" \
108 f
"Ldw{VexRiscvSMP.litedram_width}" \
109 f
"{'_Cdma' if VexRiscvSMP.coherent_dma else ''}"
112 def generate_default_configs():
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
122 VexRiscvSMP
.dcache_size
= 4096
123 VexRiscvSMP
.icache_size
= 4096
124 VexRiscvSMP
.dcache_ways
= 1
125 VexRiscvSMP
.icache_ways
= 1
128 VexRiscvSMP
.coherent_dma
= False
129 VexRiscvSMP
.generate_cluster_name()
130 VexRiscvSMP
.generate_netlist()
133 VexRiscvSMP
.coherent_dma
= True
134 VexRiscvSMP
.generate_cluster_name()
135 VexRiscvSMP
.generate_netlist()
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
146 VexRiscvSMP
.coherent_dma
= False
147 VexRiscvSMP
.generate_cluster_name()
148 VexRiscvSMP
.generate_netlist()
151 VexRiscvSMP
.coherent_dma
= True
152 VexRiscvSMP
.generate_cluster_name()
153 VexRiscvSMP
.generate_netlist()
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()
170 def generate_netlist():
171 print(f
"Generating cluster netlist")
172 vdir
= get_data_mod("cpu", "vexriscv_smp").data_location
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}")
187 cmd
= 'cd {path} && sbt "runMain vexriscv.demo.smp.VexRiscvLitexSmpClusterCmdGen {args}"'.format(path
=os
.path
.join(vdir
, "ext", "VexRiscv"), args
=" ".join(gen_args
))
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()
208 self
.periph_buses
= [pbus
]
209 self
.memory_buses
= [] # Added dynamically
212 self
.cpu_params
= dict(
214 i_debugCd_external_clk
= ClockSignal(),
215 i_debugCd_external_reset
= ResetSignal() | self
.reset
,
218 i_interrupts
= self
.interrupt
,
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
,
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
,
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
,
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
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
278 If(dma_bus
.stb
& dma_bus
.cyc
& ~dma_bus_stall
,
279 dma_bus_inhibit
.eq(1),
282 dma_bus_inhibit
.eq(0)
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
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()
297 platform
.add_source(os
.path
.join(vdir
, "RamXilinx.v"), "verilog")
298 platform
.add_source(os
.path
.join(vdir
, self
.cluster_name
+ ".v"), "verilog")
300 def add_memory_buses(self
, address_width
, data_width
):
301 VexRiscvSMP
.litedram_width
= data_width
303 VexRiscvSMP
.generate_cluster_name()
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
,
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
,
339 def do_finalize(self
):
340 assert hasattr(self
, "reset_address")
341 self
.specials
+= Instance(self
.cluster_name
, **self
.cpu_params
)
343 # Add verilog sources
344 self
.add_sources(self
.platform
)