1313from litex .gen import *
1414
1515from litex .soc .interconnect import wishbone
16+ from litex .soc .interconnect import axi
1617from litex .soc .interconnect .csr import *
1718from litex .soc .cores .cpu import CPU , CPU_GCC_TRIPLE_RISCV32
19+ from litex .soc .integration .soc import SoCRegion
1820
1921# Variants -----------------------------------------------------------------------------------------
2022
21- CPU_VARIANTS = ["minimal" , "standard" ]
23+ CPU_VARIANTS = ["minimal" , "standard" , "standard+atomic" , "standard+atomic+float+double" ]
2224
2325# GCC Flags ----------------------------------------------------------------------------------------
2426
3234 # i macfd
3335 "minimal" : "-march=rv32i2p0 -mabi=ilp32 " ,
3436 "standard" : "-march=rv32i2p0_m -mabi=ilp32 " ,
37+ "standard+atomic" : "-march=rv32i2p0_ma -mabi=ilp32 " ,
38+ "standard+atomic+float+double" : "-march=rv32i2p0_mafd -mabi=ilp32 " ,
3539}
3640
3741# CVA5 ----------------------------------------------------------------------------------------------
@@ -47,12 +51,51 @@ class CVA5(CPU):
4751 linker_output_format = "elf32-littleriscv"
4852 nop = "nop"
4953 io_regions = {0x80000000 : 0x80000000 } # origin, length
54+ plic_base = 0xf800_0000
55+ clint_base = 0xf001_0000
56+ cpu_count = 1
57+ bus_type = "wishbone" #either wishbone or axi
58+ cpu_variant = "Linux" #either linux or default
5059
60+
61+
62+ @staticmethod
63+ def args_fill (parser ):
64+ cpu_group = parser .add_argument_group (title = "CPU options" )
65+ cpu_group .add_argument ("--cpu-count" , default = 1 , help = "Number of CPU(s) in the cluster." , type = int )
66+ cpu_group .add_argument ("--clint-base" , default = "0xf0010000" , help = "CLINT base address." )
67+ cpu_group .add_argument ("--plic-base" , default = "0xf800_0000" , help = "PLIC base address." )
68+ cpu_group .add_argument ("--bus-type" , default = "wishbone" , help = "Bus type can be either wishbone or axi" )
69+ cpu_group .add_argument ("--variant" , default = "Linux" , help = "The CPU type for now it has the linux type" )#TODO add other configs
70+
71+ @staticmethod
72+ def args_read (args ):
73+ CVA5 .cpu_count = args .cpu_count
74+ CVA5 .bus_type = args .bus_type
75+ CVA5 .cpu_variant = args .variant
76+ if (args .clint_base ): CVA5 .clint_base = int (args .clint_base , 16 )
77+ if (args .plic_base ): CVA5 .plic_base = int (args .plic_base , 16 )
78+
79+
80+
81+ # Memory Mapping.
82+ @property
83+ def mem_map (self ):
84+ return {
85+ "rom" : 0x0000_0000 ,
86+ "sram" : 0x0100_0000 ,
87+ "main_ram" : 0x4000_0000 ,
88+ "csr" : 0xf000_0000 ,
89+ }
90+
5191 # GCC Flags.
5292 @property
5393 def gcc_flags (self ):
5494 flags = GCC_FLAGS [self .variant ]
55- flags += "-D__cva5__"
95+ if (CVA5 .cpu_variant == "Linux" ):
96+ flags += "-D__riscv_plic__"
97+ else :
98+ flags += "-D__cva5__"
5699 return flags
57100
58101 def __init__ (self , platform , variant = "standard" ):
@@ -63,60 +106,23 @@ def __init__(self, platform, variant="standard"):
63106 self .interrupt = Signal (2 )
64107 self .periph_buses = [] # Peripheral buses (Connected to main SoC's bus).
65108 self .memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
66-
67- # # #
109+ self .reset = Signal ()
68110
69111 # CPU Instance.
70112 self .cpu_params = dict (
71- # Configuration.
72- p_LITEX_VARIANT = CPU_VARIANTS .index (variant ),
113+ # Configuration.
73114 p_RESET_VEC = 0 ,
74115 p_NON_CACHABLE_L = 0x80000000 , # FIXME: Use io_regions.
75116 p_NON_CACHABLE_H = 0xFFFFFFFF , # FIXME: Use io_regions.
117+ p_NUM_CORES = CVA5 .cpu_count ,
118+ p_AXI = 0 if CVA5 .bus_type == "wishbone" else 1 ,
76119
77120 # Clk/Rst.
78121 i_clk = ClockSignal ("sys" ),
79- i_rst = ResetSignal ("sys" ),
80-
81- # Interrupts.
82- i_litex_interrupt = self .interrupt
122+ i_rst = ResetSignal ("sys" ) | self .reset ,
83123 )
84- # CPU Wishbone Buses.
85- if variant == "minimal" :
86- # Minimal variant has no caches, no multiply or divide support, and no branch predictor.
87- # It also uses separate fetch and load-store wishbone interfaces.
88- self .ibus = ibus = wishbone .Interface (data_width = 32 , address_width = 32 , addressing = "word" )
89- self .dbus = dbus = wishbone .Interface (data_width = 32 , address_width = 32 , addressing = "word" )
90- self .periph_buses .append (ibus )
91- self .periph_buses .append (dbus )
92- self .cpu_params .update (
93- o_ibus_adr = ibus .adr ,
94- o_ibus_dat_w = ibus .dat_w ,
95- o_ibus_sel = ibus .sel ,
96- o_ibus_cyc = ibus .cyc ,
97- o_ibus_stb = ibus .stb ,
98- o_ibus_we = ibus .we ,
99- o_ibus_cti = ibus .cti ,
100- o_ibus_bte = ibus .bte ,
101- i_ibus_dat_r = ibus .dat_r ,
102- i_ibus_ack = ibus .ack ,
103- i_ibus_err = ibus .err ,
104-
105- o_dbus_adr = dbus .adr ,
106- o_dbus_dat_w = dbus .dat_w ,
107- o_dbus_sel = dbus .sel ,
108- o_dbus_cyc = dbus .cyc ,
109- o_dbus_stb = dbus .stb ,
110- o_dbus_we = dbus .we ,
111- o_dbus_cti = dbus .cti ,
112- o_dbus_bte = dbus .bte ,
113- i_dbus_dat_r = dbus .dat_r ,
114- i_dbus_ack = dbus .ack ,
115- i_dbus_err = dbus .err
116- )
117- if variant == "standard" :
118- # Standard variant includes instruction and data caches, multiply and divide support
119- # along with the branch predictor. It uses a shared wishbone interface.
124+
125+ if (CVA5 .bus_type == "wishbone" ):
120126 self .idbus = idbus = wishbone .Interface (data_width = 32 , address_width = 32 , addressing = "word" )
121127 self .periph_buses .append (idbus )
122128 self .cpu_params .update (
@@ -132,6 +138,52 @@ def __init__(self, platform, variant="standard"):
132138 i_idbus_ack = idbus .ack ,
133139 i_idbus_err = idbus .err ,
134140 )
141+ else :
142+ self .axi_if = axi_if = axi .AXIInterface (data_width = 32 , address_width = 32 , id_width = 4 )
143+ self .periph_buses .append (axi_if )
144+
145+ self .cpu_params .update (
146+ # AXI read address channel
147+ i_m_axi_arready = axi_if .ar .ready ,
148+ o_m_axi_arvalid = axi_if .ar .valid ,
149+ o_m_axi_araddr = axi_if .ar .addr ,
150+ o_m_axi_arlen = axi_if .ar .len ,
151+ o_m_axi_arsize = axi_if .ar .size ,
152+ o_m_axi_arburst = axi_if .ar .burst ,
153+ o_m_axi_arcache = axi_if .ar .cache ,
154+ o_m_axi_arid = axi_if .ar .id ,
155+
156+ # AXI read data channel
157+ o_m_axi_rready = axi_if .r .ready ,
158+ i_m_axi_rvalid = axi_if .r .valid ,
159+ i_m_axi_rdata = axi_if .r .data ,
160+ i_m_axi_rresp = axi_if .r .resp ,
161+ i_m_axi_rlast = axi_if .r .last ,
162+ i_m_axi_rid = axi_if .r .id ,
163+
164+ # AXI write address channel
165+ i_m_axi_awready = axi_if .aw .ready ,
166+ o_m_axi_awvalid = axi_if .aw .valid ,
167+ o_m_axi_awaddr = axi_if .aw .addr ,
168+ o_m_axi_awlen = axi_if .aw .len ,
169+ o_m_axi_awsize = axi_if .aw .size ,
170+ o_m_axi_awburst = axi_if .aw .burst ,
171+ o_m_axi_awcache = axi_if .aw .cache ,
172+ o_m_axi_awid = axi_if .aw .id ,
173+
174+ # AXI write data channel
175+ i_m_axi_wready = axi_if .w .ready ,
176+ o_m_axi_wvalid = axi_if .w .valid ,
177+ o_m_axi_wdata = axi_if .w .data ,
178+ o_m_axi_wstrb = axi_if .w .strb ,
179+ o_m_axi_wlast = axi_if .w .last ,
180+
181+ # AXI write response channel
182+ o_m_axi_bready = axi_if .b .ready ,
183+ i_m_axi_bvalid = axi_if .b .valid ,
184+ i_m_axi_bresp = axi_if .b .resp ,
185+ i_m_axi_bid = axi_if .b .id ,
186+ )
135187 self .add_sources (platform )
136188
137189 def set_reset_address (self , reset_address ):
@@ -146,9 +198,148 @@ def add_sources(platform):
146198 for line in f :
147199 if line .strip () != '' :
148200 platform .add_source (os .path .join (cva5_path , line .strip ()))
149- platform .add_source (os .path .join (cva5_path , "examples/litex/l1_to_wishbone.sv" ))
150201 platform .add_source (os .path .join (cva5_path , "examples/litex/litex_wrapper.sv" ))
151202
152203 def do_finalize (self ):
153204 assert hasattr (self , "reset_address" )
154205 self .specials += Instance ("litex_wrapper" , ** self .cpu_params )
206+
207+ def add_soc_components (self , soc ):
208+ soc .csr .add ("sdram" , n = 1 )
209+ soc .csr .add ("uart" , n = 2 )
210+ soc .csr .add ("timer0" , n = 3 )
211+ soc .csr .add ("supervisor" , n = 4 )
212+
213+ # PLIC
214+ seip = Signal (int (self .cpu_params ["p_NUM_CORES" ]))
215+ meip = Signal (int (self .cpu_params ["p_NUM_CORES" ]))
216+ eip = Signal (2 * int (self .cpu_params ["p_NUM_CORES" ]))
217+ es = Signal (2 , reset = 0 )
218+
219+ if (CVA5 .cpu_variant == "Linux" ):
220+ if (CVA5 .bus_type == "wishbone" ):
221+ self .plicbus = plicbus = wishbone .Interface (data_width = 32 , address_width = 32 , addressing = "word" )
222+ self .specials += Instance ("plic_wrapper" ,
223+ p_NUM_SOURCES = 1 ,
224+ p_NUM_TARGETS = 2 * int (self .cpu_params ["p_NUM_CORES" ]),
225+ p_PRIORITY_W = 8 ,
226+ p_REG_STAGE = 1 ,
227+ p_AXI = 0 ,
228+ i_clk = ClockSignal ("sys" ),
229+ i_rst = ResetSignal ("sys" ),
230+ i_irq_srcs = self .interrupt ,
231+ i_edge_sensitive = es ,
232+ o_eip = eip ,
233+ i_wb_cyc = plicbus .cyc ,
234+ i_wb_stb = plicbus .stb ,
235+ i_wb_we = plicbus .we ,
236+ i_wb_adr = plicbus .adr ,
237+ i_wb_dat_i = plicbus .dat_w ,
238+ o_wb_dat_o = plicbus .dat_r ,
239+ o_wb_ack = plicbus .ack ,
240+ )
241+ else :
242+ self .plicbus = plicbus = axi .AXIInterface (data_width = 32 , address_width = 32 , id_width = 4 )
243+ self .specials += Instance ("plic_wrapper" ,
244+ p_NUM_SOURCES = 1 ,
245+ p_NUM_TARGETS = 2 * int (self .cpu_params ["p_NUM_CORES" ]),
246+ p_PRIORITY_W = 8 ,
247+ p_REG_STAGE = 1 ,
248+ p_AXI = 1 ,
249+ i_clk = ClockSignal ("sys" ),
250+ i_rst = ResetSignal ("sys" ),
251+ i_irq_srcs = self .interrupt ,
252+ i_edge_sensitive = es ,
253+ o_eip = eip ,
254+ i_s_axi_awvalid = plicbus .aw .valid ,
255+ i_s_axi_awaddr = plicbus .aw .addr ,
256+ i_s_axi_wvalid = plicbus .w .valid ,
257+ i_s_axi_wdata = plicbus .w .data ,
258+ i_s_axi_bready = plicbus .b .ready ,
259+ i_s_axi_arvalid = plicbus .ar .valid ,
260+ i_s_axi_araddr = plicbus .ar .addr ,
261+ i_s_axi_rready = plicbus .r .ready ,
262+ o_s_axi_awready = plicbus .aw .ready ,
263+ o_s_axi_wready = plicbus .w .ready ,
264+ o_s_axi_bvalid = plicbus .b .valid ,
265+ o_s_axi_arready = plicbus .ar .ready ,
266+ o_s_axi_rvalid = plicbus .r .valid ,
267+ o_s_axi_rdata = plicbus .r .data
268+ )
269+
270+ self .comb += [
271+ meip .eq (Cat (* [eip [i * 2 ] for i in range (int (self .cpu_params ["p_NUM_CORES" ]))])),
272+ seip .eq (Cat (* [eip [i * 2 + 1 ] for i in range (int (self .cpu_params ["p_NUM_CORES" ]))]))
273+ ]
274+
275+ self .cpu_params .update (
276+ i_seip = seip ,
277+ i_meip = meip
278+ )
279+ soc .bus .add_slave ("plic" , self .plicbus , region = SoCRegion (origin = self .plic_base , size = 0x40_0000 , cached = False ))
280+ else :
281+ self .cpu_params .update (
282+ i_meip = self .interrupt [0 ]
283+ )
284+
285+
286+
287+ # CLINT
288+ if (CVA5 .cpu_variant == "Linux" ):
289+ mtime = Signal (64 )
290+ msip = Signal (int (self .cpu_params ["p_NUM_CORES" ]))
291+ mtip = Signal (int (self .cpu_params ["p_NUM_CORES" ]))
292+ if (CVA5 .bus_type == "wishbone" ):
293+ self .clintbus = clintbus = wishbone .Interface (data_width = 32 , address_width = 32 , addressing = "word" )
294+ self .specials += Instance ("clint_wrapper" ,
295+ p_NUM_CORES = int (self .cpu_params ["p_NUM_CORES" ]),
296+ p_AXI = 0 ,
297+ i_clk = ClockSignal ("sys" ),
298+ i_rst = ResetSignal ("sys" ),
299+ o_mtip = mtip ,
300+ o_msip = msip ,
301+ o_mtime = mtime ,
302+ i_wb_cyc = clintbus .cyc ,
303+ i_wb_stb = clintbus .stb ,
304+ i_wb_we = clintbus .we ,
305+ i_wb_adr = clintbus .adr ,
306+ i_wb_dat_i = clintbus .dat_w ,
307+ o_wb_dat_o = clintbus .dat_r ,
308+ o_wb_ack = clintbus .ack ,
309+ )
310+ else :
311+ self .clintbus = clintbus = axi .AXIInterface (data_width = 32 , address_width = 32 , id_width = 4 )
312+ self .specials += Instance ("clint_wrapper" ,
313+ p_NUM_CORES = int (self .cpu_params ["p_NUM_CORES" ]),
314+ p_AXI = 1 ,
315+ i_clk = ClockSignal ("sys" ),
316+ i_rst = ResetSignal ("sys" ),
317+ o_mtip = mtip ,
318+ o_msip = msip ,
319+ o_mtime = mtime ,
320+ i_s_axi_awvalid = clintbus .aw .valid ,
321+ i_s_axi_awaddr = clintbus .aw .addr ,
322+ i_s_axi_wvalid = clintbus .w .valid ,
323+ i_s_axi_wdata = clintbus .w .data ,
324+ i_s_axi_bready = clintbus .b .ready ,
325+ i_s_axi_arvalid = clintbus .ar .valid ,
326+ i_s_axi_araddr = clintbus .ar .addr ,
327+ i_s_axi_rready = clintbus .r .ready ,
328+ o_s_axi_awready = clintbus .aw .ready ,
329+ o_s_axi_wready = clintbus .w .ready ,
330+ o_s_axi_bvalid = clintbus .b .valid ,
331+ o_s_axi_arready = clintbus .ar .ready ,
332+ o_s_axi_rvalid = clintbus .r .valid ,
333+ o_s_axi_rdata = clintbus .r .data
334+ )
335+ self .cpu_params .update (
336+ i_mtime = mtime ,
337+ i_msip = msip ,
338+ i_mtip = mtip
339+ )
340+ soc .bus .add_slave ("clint" , clintbus , region = SoCRegion (origin = self .clint_base , size = 0x1_0000 , cached = False ))
341+ else :
342+ self .cpu_params .update (
343+ i_mtip = self .interrupt [1 ]
344+ )
345+
0 commit comments