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
15 from litedram
.common
import LiteDRAMNativePort
25 class Open(Signal
): pass
27 class VexRiscvSMP(CPU
):
29 human_name
= "VexRiscv SMP"
30 variants
= CPU_VARIANTS
33 gcc_triple
= CPU_GCC_TRIPLE_RISCV32
34 linker_output_format
= "elf32-littleriscv"
36 io_regions
= {0x80000000: 0x80000000} # origin, length
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="")
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
70 "main_ram": 0x40000000,
77 flags
= " -march=rv32ima -mabi=ilp32"
78 flags
+= " -D__vexriscv__"
79 flags
+= " -DUART_POLLING"
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 ''}"
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
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()
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()
110 def generate_netlist():
111 print(f
"Generating cluster netlist")
112 vdir
= get_data_mod("cpu", "vexriscv_smp").data_location
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}")
127 cmd
= 'cd {path} && sbt "runMain vexriscv.demo.smp.VexRiscvLitexSmpClusterCmdGen {args}"'.format(path
=os
.path
.join(vdir
, "ext", "VexRiscv"), args
=" ".join(gen_args
))
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()
148 self
.periph_buses
= [pbus
]
149 self
.memory_buses
= [] # Added dynamically
151 VexRiscvSMP
.generate_cluster_name()
154 self
.cpu_params
= dict(
156 i_debugCd_external_clk
= ClockSignal(),
157 i_debugCd_external_reset
= ResetSignal() | self
.reset
,
160 i_interrupts
= self
.interrupt
,
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
,
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
,
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
,
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
204 if self
.coherent_dma
:
205 self
.dma_bus
= dma_bus
= wishbone
.Interface(data_width
=64)
207 dma_bus_stall
= Signal()
208 dma_bus_inhibit
= Signal()
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
223 If(dma_bus
.stb
& dma_bus
.cyc
& ~dma_bus_stall
,
224 dma_bus_inhibit
.eq(1),
227 dma_bus_inhibit
.eq(0)
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
,
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
,
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
,
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
,
298 # Add verilog sources
299 self
.add_sources(platform
, variant
)
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
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()
312 platform
.add_source(os
.path
.join(vdir
, "RamXilinx.v"), "verilog")
313 platform
.add_source(os
.path
.join(vdir
, self
.cluster_name
+ ".v"), "verilog")
315 def do_finalize(self
):
316 assert hasattr(self
, "reset_address")
317 self
.specials
+= Instance(self
.cluster_name
, **self
.cpu_params
)