Skip to content

Commit 2993928

Browse files
Merge pull request #1207 from pcotret/cv32e41p_support
Add support for the CV32E41P RISC-V CPU
2 parents de6238e + d444882 commit 2993928

File tree

9 files changed

+612
-0
lines changed

9 files changed

+612
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from litex.soc.cores.cpu.cv32e41p.core import CV32E41P
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.section .text, "ax", @progbits
2+
.global boot_helper
3+
boot_helper:
4+
jr x13

litex/soc/cores/cpu/cv32e41p/core.py

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
#
2+
# This file is part of LiteX.
3+
#
4+
# Copyright (c) 2020 Antmicro <www.antmicro.com>
5+
# SPDX-License-Identifier: BSD-2-Clause
6+
7+
import os
8+
import re
9+
10+
from migen import *
11+
from migen.fhdl.specials import Tristate
12+
13+
from litex import get_data_mod
14+
from litex.soc.interconnect import wishbone, stream
15+
from litex.soc.interconnect.csr import *
16+
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
17+
18+
# Variants -----------------------------------------------------------------------------------------
19+
20+
CPU_VARIANTS = ["standard"]
21+
22+
# GCC Flags ----------------------------------------------------------------------------------------
23+
24+
GCC_FLAGS = {
25+
# /-------- Base ISA
26+
# |/------- Hardware Multiply + Divide
27+
# ||/----- Atomics
28+
# |||/---- Compressed ISA
29+
# ||||/--- Single-Precision Floating-Point
30+
# |||||/-- Double-Precision Floating-Point
31+
# imacfd
32+
"standard": "-march=rv32imc -mabi=ilp32 ",
33+
}
34+
35+
# OBI / APB / Trace Layouts ------------------------------------------------------------------------
36+
37+
obi_layout = [
38+
("req", 1),
39+
("gnt", 1),
40+
("addr", 32),
41+
("we", 1),
42+
("be", 4),
43+
("wdata", 32),
44+
("rvalid", 1),
45+
("rdata", 32),
46+
]
47+
48+
apb_layout = [
49+
("paddr", 32),
50+
("pwdata", 32),
51+
("pwrite", 1),
52+
("psel", 1),
53+
("penable", 1),
54+
("prdata", 32),
55+
("pready", 1),
56+
("pslverr", 1),
57+
]
58+
59+
# Helpers ------------------------------------------------------------------------------------------
60+
61+
def add_manifest_sources(platform, manifest):
62+
basedir = get_data_mod("cpu", "cv32e41p").data_location
63+
with open(os.path.join(basedir, manifest), 'r') as f:
64+
for l in f:
65+
res = re.search('\$\{DESIGN_RTL_DIR\}/(.+)', l)
66+
if res and not re.match('//', l):
67+
if re.match('\+incdir\+', l):
68+
platform.add_verilog_include_path(os.path.join(basedir, 'rtl', res.group(1)))
69+
else:
70+
platform.add_source(os.path.join(basedir, 'rtl', res.group(1)))
71+
72+
# OBI <> Wishbone ----------------------------------------------------------------------------------
73+
74+
class OBI2Wishbone(Module):
75+
def __init__(self, obi, wb):
76+
addr = Signal.like(obi.addr)
77+
be = Signal.like(obi.be)
78+
we = Signal.like(obi.we)
79+
wdata = Signal.like(obi.wdata)
80+
81+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
82+
fsm.act("IDLE",
83+
# On OBI request:
84+
If(obi.req,
85+
# Drive Wishbone bus from OBI bus.
86+
wb.adr.eq(obi.addr[2:32]),
87+
wb.stb.eq( 1),
88+
wb.dat_w.eq( obi.wdata),
89+
wb.cyc.eq( 1),
90+
wb.sel.eq( obi.be),
91+
wb.we.eq( obi.we),
92+
93+
# Store OBI bus values.
94+
NextValue(addr, obi.addr),
95+
NextValue(be, obi.be),
96+
NextValue(we, obi.we),
97+
NextValue(wdata, obi.wdata),
98+
99+
# Now we need to wait Wishbone Ack.
100+
NextState("ACK")
101+
),
102+
obi.gnt.eq(1), # Always ack OBI request in Idle.
103+
)
104+
fsm.act("ACK",
105+
# Drive Wishbone bus from stored OBI bus values.
106+
wb.adr.eq(addr[2:32]),
107+
wb.stb.eq( 1),
108+
wb.dat_w.eq( wdata),
109+
wb.cyc.eq( 1),
110+
wb.sel.eq( be),
111+
wb.we.eq( we),
112+
113+
# On Wishbone Ack:
114+
If(wb.ack,
115+
# Generate OBI response.
116+
obi.rvalid.eq(1),
117+
obi.rdata.eq(wb.dat_r),
118+
119+
# Return to Idle.
120+
NextState("IDLE")
121+
)
122+
)
123+
124+
class Wishbone2OBI(Module):
125+
def __init__(self, wb, obi):
126+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
127+
fsm.act("IDLE",
128+
If(wb.cyc & wb.stb,
129+
obi.req.eq(1),
130+
NextState("ACK"),
131+
)
132+
)
133+
fsm.act("ACK",
134+
wb.ack.eq(1),
135+
NextState("IDLE"),
136+
)
137+
138+
self.comb += [
139+
obi.we.eq(wb.we),
140+
obi.be.eq(wb.sel),
141+
obi.addr.eq(Cat(Signal(2), wb.adr)),
142+
obi.wdata.eq(wb.dat_w),
143+
wb.dat_r.eq(obi.rdata),
144+
]
145+
146+
# Wishbone <> APB ----------------------------------------------------------------------------------
147+
148+
class Wishbone2APB(Module):
149+
def __init__(self, wb, apb):
150+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
151+
fsm.act("IDLE",
152+
If(wb.cyc & wb.stb,
153+
NextState("ACK"),
154+
)
155+
)
156+
fsm.act("ACK",
157+
apb.penable.eq(1),
158+
wb.ack.eq(1),
159+
NextState("IDLE"),
160+
)
161+
162+
self.comb += [
163+
apb.paddr.eq(Cat(Signal(2), wb.adr)),
164+
apb.pwrite.eq(wb.we),
165+
apb.psel.eq(1),
166+
apb.pwdata.eq(wb.dat_w),
167+
wb.dat_r.eq(apb.prdata),
168+
]
169+
170+
# Debug Module -------------------------------------------------------------------------------------
171+
172+
class DebugModule(Module):
173+
jtag_layout = [
174+
("tck", 1),
175+
("tms", 1),
176+
("trst", 1),
177+
("tdi", 1),
178+
("tdo", 1),
179+
]
180+
def __init__(self, pads=None):
181+
if pads is None:
182+
pads = Record(self.jtag_layout)
183+
self.pads = pads
184+
self.dmbus = wishbone.Interface()
185+
self.sbbus = wishbone.Interface()
186+
dmbus = Record(obi_layout)
187+
sbbus = Record(obi_layout)
188+
189+
self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus)
190+
self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus)
191+
192+
self.debug_req = Signal()
193+
self.ndmreset = Signal()
194+
195+
tdo_i = Signal()
196+
tdo_o = Signal()
197+
tdo_oe = Signal()
198+
199+
self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i)
200+
201+
self.dm_params = dict(
202+
# Clk / Rst.
203+
i_clk = ClockSignal("sys"),
204+
i_rst_n = ~ResetSignal("sys"),
205+
o_ndmreset = self.ndmreset,
206+
o_debug_req = self.debug_req,
207+
208+
# Slave Bus.
209+
i_dm_req = dmbus.req,
210+
i_dm_we = dmbus.we,
211+
i_dm_addr = dmbus.addr,
212+
i_dm_be = dmbus.be,
213+
i_dm_wdata = dmbus.wdata,
214+
o_dm_rdata = dmbus.rdata,
215+
216+
# Master Bus.
217+
o_sb_req = sbbus.req,
218+
o_sb_addr = sbbus.addr,
219+
o_sb_we = sbbus.we,
220+
o_sb_wdata = sbbus.wdata,
221+
o_sb_be = sbbus.be,
222+
i_sb_gnt = sbbus.gnt,
223+
i_sb_rvalid = sbbus.rvalid,
224+
i_sb_rdata = sbbus.rdata,
225+
226+
# JTAG.
227+
i_tck = pads.tck,
228+
i_tms = pads.tms,
229+
i_trst_n = pads.trst,
230+
i_tdi = pads.tdi,
231+
o_tdo = tdo_o,
232+
o_tdo_oe = tdo_oe,
233+
)
234+
235+
self.comb += [
236+
dmbus.gnt.eq(dmbus.req),
237+
dmbus.rvalid.eq(dmbus.gnt),
238+
]
239+
240+
self.specials += Instance("dm_wrap", **self.dm_params)
241+
242+
# CV32E41P -----------------------------------------------------------------------------------------
243+
244+
class CV32E41P(CPU):
245+
family = "riscv"
246+
name = "cv32e41p"
247+
human_name = "CV32E41P"
248+
variants = CPU_VARIANTS
249+
data_width = 32
250+
endianness = "little"
251+
gcc_triple = CPU_GCC_TRIPLE_RISCV32
252+
linker_output_format = "elf32-littleriscv"
253+
nop = "nop"
254+
io_regions = {0x80000000: 0x80000000} # Origin, Length.
255+
256+
# GCC Flags.
257+
@property
258+
def gcc_flags(self):
259+
flags = GCC_FLAGS[self.variant]
260+
flags += "-D__cv32e41p__ "
261+
return flags
262+
263+
def __init__(self, platform, variant="standard"):
264+
self.platform = platform
265+
self.variant = variant
266+
self.reset = Signal()
267+
self.ibus = wishbone.Interface()
268+
self.dbus = wishbone.Interface()
269+
self.periph_buses = [self.ibus, self.dbus]
270+
self.memory_buses = []
271+
self.interrupt = Signal(16)
272+
self.interrupt_padding = Signal(16)
273+
274+
ibus = Record(obi_layout)
275+
dbus = Record(obi_layout)
276+
277+
# OBI <> Wishbone.
278+
self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus)
279+
self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus)
280+
281+
self.comb += [
282+
ibus.we.eq(0),
283+
ibus.be.eq(1111),
284+
]
285+
286+
self.cpu_params = dict(
287+
# Clk / Rst.
288+
i_clk_i = ClockSignal("sys"),
289+
i_rst_ni = ~ResetSignal("sys"),
290+
291+
# Controls.
292+
i_pulp_clock_en_i = 1,
293+
i_scan_cg_en_i = 0,
294+
i_mtvec_addr_i = 0,
295+
i_dm_halt_addr_i = 0,
296+
i_hart_id_i = 0,
297+
i_dm_exception_addr_i = 0,
298+
299+
# IBus.
300+
o_instr_req_o = ibus.req,
301+
i_instr_gnt_i = ibus.gnt,
302+
i_instr_rvalid_i = ibus.rvalid,
303+
o_instr_addr_o = ibus.addr,
304+
i_instr_rdata_i = ibus.rdata,
305+
306+
# DBus.
307+
o_data_req_o = dbus.req,
308+
i_data_gnt_i = dbus.gnt,
309+
i_data_rvalid_i = dbus.rvalid,
310+
o_data_we_o = dbus.we,
311+
o_data_be_o = dbus.be,
312+
o_data_addr_o = dbus.addr,
313+
o_data_wdata_o = dbus.wdata,
314+
i_data_rdata_i = dbus.rdata,
315+
316+
# APU.
317+
i_apu_gnt_i = 0,
318+
i_apu_rvalid_i = 0,
319+
320+
# IRQ.
321+
i_irq_i = Cat(self.interrupt_padding,self.interrupt),
322+
323+
# Debug.
324+
i_debug_req_i = 0,
325+
326+
# CPU Control.
327+
i_fetch_enable_i = 1,
328+
)
329+
330+
# Add Verilog sources.
331+
add_manifest_sources(platform, 'cv32e41p_manifest.flist')
332+
333+
def add_debug_module(self, dm):
334+
self.cpu_params.update(i_debug_req_i=dm.debug_req)
335+
self.cpu_params.update(i_rst_ni=~(ResetSignal() | dm.ndmreset))
336+
337+
def set_reset_address(self, reset_address):
338+
self.reset_address = reset_address
339+
self.cpu_params.update(i_boot_addr_i=Signal(32, reset=reset_address))
340+
341+
def do_finalize(self):
342+
assert hasattr(self, "reset_address")
343+
self.specials += Instance("cv32e41p_core", **self.cpu_params)

0 commit comments

Comments
 (0)