551bfa837535904b6956f313e5ac196cd11ac4ad
[litex.git] / litex / soc / cores / cpu / vexriscv / core.py
1 # This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
2 # This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2018-2019 Sean Cross <sean@xobs.io>
4 # This file is Copyright (c) 2019 Tim 'mithro' Ansell <me@mith.ro>
5 # This file is Copyright (c) 2019 David Shah <dave@ds0.me>
6 # This file is Copyright (c) 2019 Antmicro <www.antmicro.com>
7 # This file is Copyright (c) 2019 Kurt Kiefer <kekiefer@gmail.com>
8
9 # License: BSD
10
11 import os
12
13 from migen import *
14
15 from litex import get_data_mod
16 from litex.soc.interconnect import wishbone
17 from litex.soc.interconnect.csr import *
18 from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32
19
20
21 CPU_VARIANTS = {
22 "minimal": "VexRiscv_Min",
23 "minimal+debug": "VexRiscv_MinDebug",
24 "lite": "VexRiscv_Lite",
25 "lite+debug": "VexRiscv_LiteDebug",
26 "standard": "VexRiscv",
27 "standard+debug": "VexRiscv_Debug",
28 "imac": "VexRiscv_IMAC",
29 "imac+debug": "VexRiscv_IMACDebug",
30 "full": "VexRiscv_Full",
31 "full+debug": "VexRiscv_FullDebug",
32 "linux": "VexRiscv_Linux",
33 "linux+debug": "VexRiscv_LinuxDebug",
34 "linux+no-dsp": "VexRiscv_LinuxNoDspFmax",
35 }
36
37
38 GCC_FLAGS = {
39 # /-------- Base ISA
40 # |/------- Hardware Multiply + Divide
41 # ||/----- Atomics
42 # |||/---- Compressed ISA
43 # ||||/--- Single-Precision Floating-Point
44 # |||||/-- Double-Precision Floating-Point
45 # imacfd
46 "minimal": "-march=rv32i -mabi=ilp32",
47 "minimal+debug": "-march=rv32i -mabi=ilp32",
48 "lite": "-march=rv32i -mabi=ilp32",
49 "lite+debug": "-march=rv32i -mabi=ilp32",
50 "standard": "-march=rv32im -mabi=ilp32",
51 "standard+debug": "-march=rv32im -mabi=ilp32",
52 "imac": "-march=rv32imac -mabi=ilp32",
53 "imac+debug": "-march=rv32imac -mabi=ilp32",
54 "full": "-march=rv32im -mabi=ilp32",
55 "full+debug": "-march=rv32im -mabi=ilp32",
56 "linux": "-march=rv32ima -mabi=ilp32",
57 "linux+debug": "-march=rv32ima -mabi=ilp32",
58 "linux+no-dsp": "-march=rv32ima -mabi=ilp32",
59 }
60
61
62 class VexRiscvTimer(Module, AutoCSR):
63 def __init__(self):
64 self._latch = CSR()
65 self._time = CSRStatus(64)
66 self._time_cmp = CSRStorage(64, reset=2**64-1)
67 self.interrupt = Signal()
68
69 # # #
70
71 time = Signal(64)
72 self.sync += time.eq(time + 1)
73 self.sync += If(self._latch.re, self._time.status.eq(time))
74
75 time_cmp = Signal(64, reset=2**64-1)
76 self.sync += If(self._latch.re, time_cmp.eq(self._time_cmp.storage))
77
78 self.comb += self.interrupt.eq(time >= time_cmp)
79
80
81 class VexRiscv(CPU, AutoCSR):
82 name = "vexriscv"
83 human_name = "VexRiscv"
84 variants = CPU_VARIANTS
85 data_width = 32
86 endianness = "little"
87 gcc_triple = CPU_GCC_TRIPLE_RISCV32
88 linker_output_format = "elf32-littleriscv"
89 nop = "nop"
90 io_regions = {0x80000000: 0x80000000} # origin, length
91
92 @property
93 def mem_map_linux(self):
94 return {
95 "rom": 0x00000000,
96 "sram": 0x10000000,
97 "main_ram": 0x40000000,
98 "csr": 0xf0000000,
99 }
100
101 @property
102 def gcc_flags(self):
103 flags = GCC_FLAGS[self.variant]
104 flags += " -D__vexriscv__"
105 return flags
106
107 def __init__(self, platform, variant="standard"):
108 self.platform = platform
109 self.variant = variant
110 self.external_variant = None
111 self.reset = Signal()
112 self.interrupt = Signal(32)
113 self.ibus = ibus = wishbone.Interface()
114 self.dbus = dbus = wishbone.Interface()
115 self.periph_buses = [ibus, dbus]
116 self.memory_buses = []
117
118 # # #
119
120 self.cpu_params = dict(
121 i_clk = ClockSignal(),
122 i_reset = ResetSignal() | self.reset,
123
124 i_externalInterruptArray = self.interrupt,
125 i_timerInterrupt = 0,
126 i_softwareInterrupt = 0,
127
128 o_iBusWishbone_ADR = ibus.adr,
129 o_iBusWishbone_DAT_MOSI = ibus.dat_w,
130 o_iBusWishbone_SEL = ibus.sel,
131 o_iBusWishbone_CYC = ibus.cyc,
132 o_iBusWishbone_STB = ibus.stb,
133 o_iBusWishbone_WE = ibus.we,
134 o_iBusWishbone_CTI = ibus.cti,
135 o_iBusWishbone_BTE = ibus.bte,
136 i_iBusWishbone_DAT_MISO = ibus.dat_r,
137 i_iBusWishbone_ACK = ibus.ack,
138 i_iBusWishbone_ERR = ibus.err,
139
140 o_dBusWishbone_ADR = dbus.adr,
141 o_dBusWishbone_DAT_MOSI = dbus.dat_w,
142 o_dBusWishbone_SEL = dbus.sel,
143 o_dBusWishbone_CYC = dbus.cyc,
144 o_dBusWishbone_STB = dbus.stb,
145 o_dBusWishbone_WE = dbus.we,
146 o_dBusWishbone_CTI = dbus.cti,
147 o_dBusWishbone_BTE = dbus.bte,
148 i_dBusWishbone_DAT_MISO = dbus.dat_r,
149 i_dBusWishbone_ACK = dbus.ack,
150 i_dBusWishbone_ERR = dbus.err
151 )
152
153 if "linux" in variant:
154 self.add_timer()
155 self.mem_map = self.mem_map_linux
156
157 if "debug" in variant:
158 self.add_debug()
159
160 def add_debug(self):
161 debug_reset = Signal()
162
163 ibus_err = Signal()
164 dbus_err = Signal()
165
166 self.i_cmd_valid = Signal()
167 self.i_cmd_payload_wr = Signal()
168 self.i_cmd_payload_address = Signal(8)
169 self.i_cmd_payload_data = Signal(32)
170 self.o_cmd_ready = Signal()
171 self.o_rsp_data = Signal(32)
172 self.o_resetOut = Signal()
173
174 reset_debug_logic = Signal()
175
176 self.transfer_complete = Signal()
177 self.transfer_in_progress = Signal()
178 self.transfer_wait_for_ack = Signal()
179
180 self.debug_bus = wishbone.Interface()
181
182 self.sync += [
183 self.debug_bus.dat_r.eq(self.o_rsp_data),
184 debug_reset.eq(reset_debug_logic | ResetSignal()),
185 ]
186
187 self.sync += [
188 # CYC is held high for the duration of the transfer.
189 # STB is kept high when the transfer finishes (write)
190 # or the master is waiting for data (read), and stays
191 # there until ACK, ERR, or RTY are asserted.
192 If((self.debug_bus.stb & self.debug_bus.cyc)
193 & (~self.transfer_in_progress)
194 & (~self.transfer_complete)
195 & (~self.transfer_wait_for_ack),
196 self.i_cmd_payload_data.eq(self.debug_bus.dat_w),
197 self.i_cmd_payload_address.eq((self.debug_bus.adr[0:6] << 2) | 0),
198 self.i_cmd_payload_wr.eq(self.debug_bus.we),
199 self.i_cmd_valid.eq(1),
200 self.transfer_in_progress.eq(1),
201 self.transfer_complete.eq(0),
202 self.debug_bus.ack.eq(0)
203 ).Elif(self.transfer_in_progress,
204 If(self.o_cmd_ready,
205 self.i_cmd_valid.eq(0),
206 self.i_cmd_payload_wr.eq(0),
207 self.transfer_complete.eq(1),
208 self.transfer_in_progress.eq(0)
209 )
210 ).Elif(self.transfer_complete,
211 self.transfer_complete.eq(0),
212 self.debug_bus.ack.eq(1),
213 self.transfer_wait_for_ack.eq(1)
214 ).Elif(self.transfer_wait_for_ack & ~(self.debug_bus.stb & self.debug_bus.cyc),
215 self.transfer_wait_for_ack.eq(0),
216 self.debug_bus.ack.eq(0)
217 ),
218 # Force a Wishbone error if transferring during a reset sequence.
219 # Because o_resetOut is multiple cycles and i.stb/d.stb should
220 # deassert one cycle after i_err/i_ack/d_err/d_ack are asserted,
221 # this will give i_err and o_err enough time to be reset to 0
222 # once the reset cycle finishes.
223 If(self.o_resetOut,
224 If(self.ibus.cyc & self.ibus.stb, ibus_err.eq(1)).Else(ibus_err.eq(0)),
225 If(self.dbus.cyc & self.dbus.stb, dbus_err.eq(1)).Else(dbus_err.eq(0)),
226 reset_debug_logic.eq(1))
227 .Else(
228 reset_debug_logic.eq(0)
229 )
230 ]
231
232 self.cpu_params.update(
233 i_reset=ResetSignal() | self.reset | debug_reset,
234 i_iBusWishbone_ERR=self.ibus.err | ibus_err,
235 i_dBusWishbone_ERR=self.dbus.err | dbus_err,
236 i_debugReset = ResetSignal(),
237 i_debug_bus_cmd_valid = self.i_cmd_valid,
238 i_debug_bus_cmd_payload_wr = self.i_cmd_payload_wr,
239 i_debug_bus_cmd_payload_address = self.i_cmd_payload_address,
240 i_debug_bus_cmd_payload_data = self.i_cmd_payload_data,
241 o_debug_bus_cmd_ready = self.o_cmd_ready,
242 o_debug_bus_rsp_data = self.o_rsp_data,
243 o_debug_resetOut = self.o_resetOut
244 )
245
246 def set_reset_address(self, reset_address):
247 assert not hasattr(self, "reset_address")
248 self.reset_address = reset_address
249 self.cpu_params.update(i_externalResetVector=Signal(32, reset=reset_address))
250
251 def add_timer(self):
252 self.submodules.timer = VexRiscvTimer()
253 self.cpu_params.update(i_timerInterrupt=self.timer.interrupt)
254
255 @staticmethod
256 def add_sources(platform, variant="standard"):
257 cpu_filename = CPU_VARIANTS[variant] + ".v"
258 vdir = get_data_mod("cpu", "vexriscv").data_location
259 platform.add_source(os.path.join(vdir, cpu_filename))
260
261 def use_external_variant(self, variant_filename):
262 self.external_variant = True
263 self.platform.add_source(variant_filename)
264
265 def do_finalize(self):
266 assert hasattr(self, "reset_address")
267 if not self.external_variant:
268 self.add_sources(self.platform, self.variant)
269 self.specials += Instance("VexRiscv", **self.cpu_params)