soc/integration/csr_bridge: use registered version only when SDRAM is present.
[litex.git] / litex / soc / integration / soc.py
1 # This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
2 # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
3 # This file is Copyright (c) 2019 Gabriel L. Somlo <somlo@cmu.edu>
4 # License: BSD
5
6 import logging
7 import time
8 import datetime
9 from math import log2, ceil
10
11 from migen import *
12
13 from litex.soc.cores import cpu
14 from litex.soc.cores.identifier import Identifier
15 from litex.soc.cores.timer import Timer
16 from litex.soc.cores.spi_flash import SpiFlash
17 from litex.soc.cores.spi import SPIMaster
18
19 from litex.soc.interconnect.csr import *
20 from litex.soc.interconnect import csr_bus
21 from litex.soc.interconnect import stream
22 from litex.soc.interconnect import wishbone
23 from litex.soc.interconnect import axi
24
25 logging.basicConfig(level=logging.INFO)
26
27 # Helpers ------------------------------------------------------------------------------------------
28
29 def auto_int(x):
30 return int(x, 0)
31
32 def colorer(s, color="bright"):
33 header = {
34 "bright": "\x1b[1m",
35 "green": "\x1b[32m",
36 "cyan": "\x1b[36m",
37 "red": "\x1b[31m",
38 "yellow": "\x1b[33m",
39 "underline": "\x1b[4m"}[color]
40 trailer = "\x1b[0m"
41 return header + str(s) + trailer
42
43 def build_time(with_time=True):
44 fmt = "%Y-%m-%d %H:%M:%S" if with_time else "%Y-%m-%d"
45 return datetime.datetime.fromtimestamp(time.time()).strftime(fmt)
46
47 # SoCConstant --------------------------------------------------------------------------------------
48
49 def SoCConstant(value):
50 return value
51
52 # SoCRegion ----------------------------------------------------------------------------------------
53
54 class SoCRegion:
55 def __init__(self, origin=None, size=None, mode="rw", cached=True, linker=False):
56 self.logger = logging.getLogger("SoCRegion")
57 self.origin = origin
58 self.size = size
59 if size != 2**log2_int(size, False):
60 self.logger.info("Region size {} internally from {} to {}.".format(
61 colorer("rounded", color="cyan"),
62 colorer("0x{:08x}".format(size)),
63 colorer("0x{:08x}".format(2**log2_int(size, False)))))
64 self.size_pow2 = 2**log2_int(size, False)
65 self.mode = mode
66 self.cached = cached
67 self.linker = linker
68
69 def decoder(self, bus):
70 origin = self.origin
71 size = self.size_pow2
72 if (origin & (size - 1)) != 0:
73 self.logger.error("Origin needs to be aligned on size:")
74 self.logger.error(self)
75 raise
76 if (origin == 0) and (size == 2**bus.address_width):
77 return lambda a : True
78 origin >>= int(log2(bus.data_width//8)) # bytes to words aligned
79 size >>= int(log2(bus.data_width//8)) # bytes to words aligned
80 return lambda a: (a[log2_int(size):] == (origin >> log2_int(size)))
81
82 def __str__(self):
83 r = ""
84 if self.origin is not None:
85 r += "Origin: {}, ".format(colorer("0x{:08x}".format(self.origin)))
86 if self.size is not None:
87 r += "Size: {}, ".format(colorer("0x{:08x}".format(self.size)))
88 r += "Mode: {}, ".format(colorer(self.mode.upper()))
89 r += "Cached: {} ".format(colorer(self.cached))
90 r += "Linker: {}".format(colorer(self.linker))
91 return r
92
93 class SoCIORegion(SoCRegion): pass
94
95 # SoCCSRRegion -------------------------------------------------------------------------------------
96
97 class SoCCSRRegion:
98 def __init__(self, origin, busword, obj):
99 self.origin = origin
100 self.busword = busword
101 self.obj = obj
102
103 # SoCBusHandler ------------------------------------------------------------------------------------
104
105 class SoCBusHandler(Module):
106 supported_standard = ["wishbone", "axi-lite"]
107 supported_data_width = [32, 64]
108 supported_address_width = [32]
109
110 # Creation -------------------------------------------------------------------------------------
111 def __init__(self, name="SoCBusHandler", standard="wishbone", data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
112 self.logger = logging.getLogger(name)
113 self.logger.info("Creating Bus Handler...")
114
115 # Check Standard
116 if standard not in self.supported_standard:
117 self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
118 colorer("Bus standard", color="red"),
119 colorer(standard),
120 colorer(", ".join(self.supported_standard))))
121 raise
122
123 # Check Data Width
124 if data_width not in self.supported_data_width:
125 self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
126 colorer("Data Width", color="red"),
127 colorer(data_width),
128 colorer(", ".join(str(x) for x in self.supported_data_width))))
129 raise
130
131 # Check Address Width
132 if address_width not in self.supported_address_width:
133 self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
134 colorer("Address Width", color="red"),
135 colorer(address_width),
136 colorer(", ".join(str(x) for x in self.supported_address_width))))
137 raise
138
139 # Create Bus
140 self.standard = standard
141 self.data_width = data_width
142 self.address_width = address_width
143 self.masters = {}
144 self.slaves = {}
145 self.regions = {}
146 self.io_regions = {}
147 self.timeout = timeout
148 self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
149 colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
150
151 # Adding reserved regions
152 self.logger.info("Adding {} Bus Regions...".format(colorer("reserved", color="cyan")))
153 for name, region in reserved_regions.items():
154 if isinstance(region, int):
155 region = SoCRegion(origin=region, size=0x1000000)
156 self.add_region(name, region)
157
158 self.logger.info("Bus Handler {}.".format(colorer("created", color="green")))
159
160 # Add/Allog/Check Regions ----------------------------------------------------------------------
161 def add_region(self, name, region):
162 allocated = False
163 if name in self.regions.keys() or name in self.io_regions.keys():
164 self.logger.error("{} already declared as Region:".format(colorer(name, color="red")))
165 self.logger.error(self)
166 raise
167 # Check if SoCIORegion
168 if isinstance(region, SoCIORegion):
169 self.io_regions[name] = region
170 overlap = self.check_regions_overlap(self.io_regions)
171 if overlap is not None:
172 self.logger.error("IO Region {} between {} and {}:".format(
173 colorer("overlap", color="red"),
174 colorer(overlap[0]),
175 colorer(overlap[1])))
176 self.logger.error(str(self.io_regions[overlap[0]]))
177 self.logger.error(str(self.io_regions[overlap[1]]))
178 raise
179 self.logger.info("{} Region {} at {}.".format(
180 colorer(name, color="underline"),
181 colorer("added", color="green"),
182 str(region)))
183 # Check if SoCRegion
184 elif isinstance(region, SoCRegion):
185 # If no origin specified, allocate region.
186 if region.origin is None:
187 allocated = True
188 region = self.alloc_region(name, region.size, region.cached)
189 self.regions[name] = region
190 # Else add region and check for overlaps.
191 else:
192 if not region.cached:
193 if not self.check_region_is_io(region):
194 self.logger.error("{} Region {}: {}.".format(
195 colorer(name),
196 colorer("not in IO region", color="red"),
197 str(region)))
198 self.logger.error(self)
199 raise
200 self.regions[name] = region
201 overlap = self.check_regions_overlap(self.regions)
202 if overlap is not None:
203 self.logger.error("Region {} between {} and {}:".format(
204 colorer("overlap", color="red"),
205 colorer(overlap[0]),
206 colorer(overlap[1])))
207 self.logger.error(str(self.regions[overlap[0]]))
208 self.logger.error(str(self.regions[overlap[1]]))
209 raise
210 self.logger.info("{} Region {} at {}.".format(
211 colorer(name, color="underline"),
212 colorer("allocated" if allocated else "added", color="cyan" if allocated else "green"),
213 str(region)))
214 else:
215 self.logger.error("{} is not a supported Region.".format(colorer(name, color="red")))
216 raise
217
218 def alloc_region(self, name, size, cached=True):
219 self.logger.info("Allocating {} Region of size {}...".format(
220 colorer("Cached" if cached else "IO"),
221 colorer("0x{:08x}".format(size))))
222
223 # Limit Search Regions
224 if cached == False:
225 search_regions = self.io_regions
226 else:
227 search_regions = {"main": SoCRegion(origin=0x00000000, size=2**self.address_width-1)}
228
229 # Iterate on Search_Regions to find a Candidate
230 for _, search_region in search_regions.items():
231 origin = search_region.origin
232 while (origin + size) < (search_region.origin + search_region.size_pow2):
233 # Create a Candicate.
234 candidate = SoCRegion(origin=origin, size=size, cached=cached)
235 overlap = False
236 # Check Candidate does not overlap with allocated existing regions
237 for _, allocated in self.regions.items():
238 if self.check_regions_overlap({"0": allocated, "1": candidate}) is not None:
239 origin = allocated.origin + allocated.size_pow2
240 overlap = True
241 break
242 if not overlap:
243 # If no overlap, the Candidate is selected
244 return candidate
245
246 self.logger.error("Not enough Address Space to allocate Region.")
247 raise
248
249 def check_regions_overlap(self, regions, check_linker=False):
250 i = 0
251 while i < len(regions):
252 n0 = list(regions.keys())[i]
253 r0 = regions[n0]
254 for n1 in list(regions.keys())[i+1:]:
255 r1 = regions[n1]
256 if r0.linker or r1.linker:
257 if not check_linker:
258 continue
259 if r0.origin >= (r1.origin + r1.size_pow2):
260 continue
261 if r1.origin >= (r0.origin + r0.size_pow2):
262 continue
263 return (n0, n1)
264 i += 1
265 return None
266
267 def check_region_is_in(self, region, container):
268 is_in = True
269 if not (region.origin >= container.origin):
270 is_in = False
271 if not ((region.origin + region.size) < (container.origin + container.size)):
272 is_in = False
273 return is_in
274
275 def check_region_is_io(self, region):
276 is_io = False
277 for _, io_region in self.io_regions.items():
278 if self.check_region_is_in(region, io_region):
279 is_io = True
280 return is_io
281
282 # Add Master/Slave -----------------------------------------------------------------------------
283 def add_adapter(self, name, interface, direction="m2s"):
284 assert direction in ["m2s", "s2m"]
285
286 # Data width conversion
287 if interface.data_width != self.data_width:
288 interface_cls = type(interface)
289 converter_cls = {
290 wishbone.Interface: wishbone.Converter,
291 axi.AXILiteInterface: axi.AXILiteConverter,
292 }[interface_cls]
293 converted_interface = interface_cls(data_width=self.data_width)
294 if direction == "m2s":
295 master, slave = interface, converted_interface
296 elif direction == "s2m":
297 master, slave = converted_interface, interface
298 converter = converter_cls(master=master, slave=slave)
299 self.submodules += converter
300 else:
301 converted_interface = interface
302
303 # Wishbone <-> AXILite bridging
304 main_bus_cls = {
305 "wishbone": wishbone.Interface,
306 "axi-lite": axi.AXILiteInterface,
307 }[self.standard]
308 if isinstance(converted_interface, main_bus_cls):
309 bridged_interface = converted_interface
310 else:
311 bridged_interface = main_bus_cls(data_width=self.data_width)
312 if direction == "m2s":
313 master, slave = converted_interface, bridged_interface
314 elif direction == "s2m":
315 master, slave = bridged_interface, converted_interface
316 bridge_cls = {
317 (wishbone.Interface, axi.AXILiteInterface): axi.Wishbone2AXILite,
318 (axi.AXILiteInterface, wishbone.Interface): axi.AXILite2Wishbone,
319 }[type(master), type(slave)]
320 bridge = bridge_cls(master, slave)
321 self.submodules += bridge
322
323 if type(interface) != type(bridged_interface) or interface.data_width != bridged_interface.data_width:
324 fmt = "{name} Bus {converted} from {frombus} {frombits}-bit to {tobus} {tobits}-bit."
325 bus_names = {
326 wishbone.Interface: "Wishbone",
327 axi.AXILiteInterface: "AXI Lite",
328 }
329 self.logger.info(fmt.format(
330 name = colorer(name),
331 converted = colorer("converted", color="cyan"),
332 frombus = colorer(bus_names[type(interface)]),
333 frombits = colorer(interface.data_width),
334 tobus = colorer(bus_names[type(bridged_interface)]),
335 tobits = colorer(bridged_interface.data_width)))
336 return bridged_interface
337
338 def add_master(self, name=None, master=None):
339 if name is None:
340 name = "master{:d}".format(len(self.masters))
341 if name in self.masters.keys():
342 self.logger.error("{} {} as Bus Master:".format(
343 colorer(name),
344 colorer("already declared", color="red")))
345 self.logger.error(self)
346 raise
347 master = self.add_adapter(name, master, "m2s")
348 self.masters[name] = master
349 self.logger.info("{} {} as Bus Master.".format(
350 colorer(name, color="underline"),
351 colorer("added", color="green")))
352
353 def add_slave(self, name=None, slave=None, region=None):
354 no_name = name is None
355 no_region = region is None
356 if no_name and no_region:
357 self.logger.error("Please {} {} or/and {} of Bus Slave.".format(
358 colorer("specify", color="red"),
359 colorer("name"),
360 colorer("region")))
361 raise
362 if no_name:
363 name = "slave{:d}".format(len(self.slaves))
364 if no_region:
365 region = self.regions.get(name, None)
366 if region is None:
367 self.logger.error("{} Region {}.".format(
368 colorer(name),
369 colorer("not found", color="red")))
370 raise
371 else:
372 self.add_region(name, region)
373 if name in self.slaves.keys():
374 self.logger.error("{} {} as Bus Slave:".format(
375 colorer(name),
376 colorer("already declared", color="red")))
377 self.logger.error(self)
378 raise
379 slave = self.add_adapter(name, slave, "s2m")
380 self.slaves[name] = slave
381 self.logger.info("{} {} as Bus Slave.".format(
382 colorer(name, color="underline"),
383 colorer("added", color="green")))
384
385 # Str ------------------------------------------------------------------------------------------
386 def __str__(self):
387 r = "{}-bit {} Bus, {}GiB Address Space.\n".format(
388 colorer(self.data_width), colorer(self.standard), colorer(2**self.address_width/2**30))
389 r += "IO Regions: ({})\n".format(len(self.io_regions.keys())) if len(self.io_regions.keys()) else ""
390 io_regions = {k: v for k, v in sorted(self.io_regions.items(), key=lambda item: item[1].origin)}
391 for name, region in io_regions.items():
392 r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
393 r += "Bus Regions: ({})\n".format(len(self.regions.keys())) if len(self.regions.keys()) else ""
394 regions = {k: v for k, v in sorted(self.regions.items(), key=lambda item: item[1].origin)}
395 for name, region in regions.items():
396 r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
397 r += "Bus Masters: ({})\n".format(len(self.masters.keys())) if len(self.masters.keys()) else ""
398 for name in self.masters.keys():
399 r += "- {}\n".format(colorer(name, color="underline"))
400 r += "Bus Slaves: ({})\n".format(len(self.slaves.keys())) if len(self.slaves.keys()) else ""
401 for name in self.slaves.keys():
402 r += "- {}\n".format(colorer(name, color="underline"))
403 r = r[:-1]
404 return r
405
406 # SoCLocHandler --------------------------------------------------------------------------------------
407
408 class SoCLocHandler(Module):
409 # Creation -------------------------------------------------------------------------------------
410 def __init__(self, name, n_locs):
411 self.name = name
412 self.locs = {}
413 self.n_locs = n_locs
414
415 # Add ------------------------------------------------------------------------------------------
416 def add(self, name, n=None, use_loc_if_exists=False):
417 allocated = False
418 if not (use_loc_if_exists and name in self.locs.keys()):
419 if name in self.locs.keys():
420 self.logger.error("{} {} name {}.".format(
421 colorer(name), self.name, colorer("already used", color="red")))
422 self.logger.error(self)
423 raise
424 if n in self.locs.values():
425 self.logger.error("{} {} Location {}.".format(
426 colorer(n), self.name, colorer("already used", color="red")))
427 self.logger.error(self)
428 raise
429 if n is None:
430 allocated = True
431 n = self.alloc(name)
432 else:
433 if n < 0:
434 self.logger.error("{} {} Location should be {}.".format(
435 colorer(n),
436 self.name,
437 colorer("positive", color="red")))
438 raise
439 if n > self.n_locs:
440 self.logger.error("{} {} Location {} than maximum: {}.".format(
441 colorer(n),
442 self.name,
443 colorer("higher", color="red"),
444 colorer(self.n_locs)))
445 raise
446 self.locs[name] = n
447 else:
448 n = self.locs[name]
449 self.logger.info("{} {} {} at Location {}.".format(
450 colorer(name, color="underline"),
451 self.name,
452 colorer("allocated" if allocated else "added", color="cyan" if allocated else "green"),
453 colorer(n)))
454
455 # Alloc ----------------------------------------------------------------------------------------
456 def alloc(self, name):
457 for n in range(self.n_locs):
458 if n not in self.locs.values():
459 return n
460 self.logger.error("Not enough Locations.")
461 self.logger.error(self)
462 raise
463
464 # Str ------------------------------------------------------------------------------------------
465 def __str__(self):
466 r = "{} Locations: ({})\n".format(self.name, len(self.locs.keys())) if len(self.locs.keys()) else ""
467 locs = {k: v for k, v in sorted(self.locs.items(), key=lambda item: item[1])}
468 length = 0
469 for name in locs.keys():
470 if len(name) > length: length = len(name)
471 for name in locs.keys():
472 r += "- {}{}: {}\n".format(colorer(name, color="underline"), " "*(length + 1 - len(name)), colorer(self.locs[name]))
473 return r
474
475 # SoCCSRHandler ------------------------------------------------------------------------------------
476
477 class SoCCSRHandler(SoCLocHandler):
478 supported_data_width = [8, 32]
479 supported_address_width = [14+i for i in range(4)]
480 supported_alignment = [32]
481 supported_paging = [0x800*2**i for i in range(4)]
482 supported_ordering = ["big", "little"]
483
484 # Creation -------------------------------------------------------------------------------------
485 def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, ordering="big", reserved_csrs={}):
486 SoCLocHandler.__init__(self, "CSR", n_locs=alignment//8*(2**address_width)//paging)
487 self.logger = logging.getLogger("SoCCSRHandler")
488 self.logger.info("Creating CSR Handler...")
489
490 # Check Data Width
491 if data_width not in self.supported_data_width:
492 self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
493 colorer("Data Width", color="red"),
494 colorer(data_width),
495 colorer(", ".join(str(x) for x in self.supported_data_width))))
496 raise
497
498 # Check Address Width
499 if address_width not in self.supported_address_width:
500 self.logger.error("Unsupported {} {} supporteds: {:s}".format(
501 colorer("Address Width", color="red"),
502 colorer(address_width),
503 colorer(", ".join(str(x) for x in self.supported_address_width))))
504 raise
505
506 # Check Alignment
507 if alignment not in self.supported_alignment:
508 self.logger.error("Unsupported {}: {} supporteds: {:s}".format(
509 colorer("Alignment", color="red"),
510 colorer(alignment),
511 colorer(", ".join(str(x) for x in self.supported_alignment))))
512 raise
513 if data_width > alignment:
514 self.logger.error("Alignment ({}) {} Data Width ({})".format(
515 colorer(alignment),
516 colorer("should be >=", color="red"),
517 colorer(data_width)))
518 raise
519
520 # Check Paging
521 if paging not in self.supported_paging:
522 self.logger.error("Unsupported {} 0x{}, supporteds: {:s}".format(
523 colorer("Paging", color="red"),
524 colorer("{:x}".format(paging)),
525 colorer(", ".join("0x{:x}".format(x) for x in self.supported_paging))))
526 raise
527
528 # Check Ordering
529 if ordering not in self.supported_ordering:
530 self.logger.error("Unsupported {} {}, supporteds: {:s}".format(
531 colorer("Ordering", color="red"),
532 colorer("{}".format(paging)),
533 colorer(", ".join("{}".format(x) for x in self.supported_ordering))))
534 raise
535
536 # Create CSR Handler
537 self.data_width = data_width
538 self.address_width = address_width
539 self.alignment = alignment
540 self.paging = paging
541 self.ordering = ordering
542 self.masters = {}
543 self.regions = {}
544 self.logger.info("{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging, {} Ordering (Up to {} Locations).".format(
545 colorer(self.data_width),
546 colorer(self.alignment),
547 colorer(2**self.address_width/2**10),
548 colorer(self.paging),
549 colorer(self.ordering),
550 colorer(self.n_locs)))
551
552 # Adding reserved CSRs
553 self.logger.info("Adding {} CSRs...".format(colorer("reserved", color="cyan")))
554 for name, n in reserved_csrs.items():
555 self.add(name, n)
556
557 self.logger.info("CSR Handler {}.".format(colorer("created", color="green")))
558
559 # Add Master -----------------------------------------------------------------------------------
560 def add_master(self, name=None, master=None):
561 if name is None:
562 name = "master{:d}".format(len(self.masters))
563 if name in self.masters.keys():
564 self.logger.error("{} {} as CSR Master:".format(
565 colorer(name),
566 colorer("already declared", color="red")))
567 self.logger.error(self)
568 raise
569 if master.data_width != self.data_width:
570 self.logger.error("{} Master/Handler Data Width {} ({} vs {}).".format(
571 colorer(name),
572 colorer("missmatch", color="red"),
573 colorer(master.data_width),
574 colorer(self.data_width)))
575 raise
576 self.masters[name] = master
577 self.logger.info("{} {} as CSR Master.".format(
578 colorer(name, color="underline"),
579 colorer("added", color="green")))
580
581 # Add Region -----------------------------------------------------------------------------------
582 def add_region(self, name, region):
583 # FIXME: add checks
584 self.regions[name] = region
585
586 # Address map ----------------------------------------------------------------------------------
587 def address_map(self, name, memory):
588 if memory is not None:
589 name = name + "_" + memory.name_override
590 if self.locs.get(name, None) is None:
591 self.logger.error("CSR {} {}.".format(
592 colorer(name),
593 colorer("not found", color="red")))
594 self.logger.error(self)
595 raise
596 return self.locs[name]
597
598 # Str ------------------------------------------------------------------------------------------
599 def __str__(self):
600 r = "{}-bit CSR Bus, {}-bit Aligned, {}KiB Address Space, {}B Paging, {} Ordering (Up to {} Locations).\n".format(
601 colorer(self.data_width),
602 colorer(self.alignment),
603 colorer(2**self.address_width/2**10),
604 colorer(self.paging),
605 colorer(self.ordering),
606 colorer(self.n_locs))
607 r += SoCLocHandler.__str__(self)
608 r = r[:-1]
609 return r
610
611 # SoCIRQHandler ------------------------------------------------------------------------------------
612
613 class SoCIRQHandler(SoCLocHandler):
614 # Creation -------------------------------------------------------------------------------------
615 def __init__(self, n_irqs=32, reserved_irqs={}):
616 SoCLocHandler.__init__(self, "IRQ", n_locs=n_irqs)
617 self.logger = logging.getLogger("SoCIRQHandler")
618 self.logger.info("Creating IRQ Handler...")
619
620 # Check IRQ Number
621 if n_irqs > 32:
622 self.logger.error("Unsupported IRQs number: {} supporteds: {:s}".format(
623 colorer(n, color="red"), colorer("Up to 32", color="green")))
624 raise
625
626 # Create IRQ Handler
627 self.logger.info("IRQ Handler (up to {} Locations).".format(colorer(n_irqs)))
628
629 # Adding reserved IRQs
630 self.logger.info("Adding {} IRQs...".format(colorer("reserved", color="cyan")))
631 for name, n in reserved_irqs.items():
632 self.add(name, n)
633
634 self.logger.info("IRQ Handler {}.".format(colorer("created", color="green")))
635
636 # Str ------------------------------------------------------------------------------------------
637 def __str__(self):
638 r ="IRQ Handler (up to {} Locations).\n".format(colorer(self.n_locs))
639 r += SoCLocHandler.__str__(self)
640 r = r[:-1]
641 return r
642
643 # SoCController ------------------------------------------------------------------------------------
644
645 class SoCController(Module, AutoCSR):
646 def __init__(self,
647 with_reset = True,
648 with_scratch = True,
649 with_errors = True):
650
651 if with_reset:
652 self._reset = CSRStorage(1, description="""Write a ``1`` to this register to reset the SoC.""")
653 if with_scratch:
654 self._scratch = CSRStorage(32, reset=0x12345678, description="""
655 Use this register as a scratch space to verify that software read/write accesses
656 to the Wishbone/CSR bus are working correctly. The initial reset value of 0x1234578
657 can be used to verify endianness.""")
658 if with_errors:
659 self._bus_errors = CSRStatus(32, description="Total number of Wishbone bus errors (timeouts) since start.")
660
661 # # #
662
663 # Reset
664 if with_reset:
665 self.reset = Signal()
666 self.comb += self.reset.eq(self._reset.re)
667
668 # Errors
669 if with_errors:
670 self.bus_error = Signal()
671 bus_errors = Signal(32)
672 self.sync += [
673 If(bus_errors != (2**len(bus_errors)-1),
674 If(self.bus_error, bus_errors.eq(bus_errors + 1))
675 )
676 ]
677 self.comb += self._bus_errors.status.eq(bus_errors)
678
679 # SoC ----------------------------------------------------------------------------------------------
680
681 class SoC(Module):
682 mem_map = {}
683 def __init__(self, platform, sys_clk_freq,
684 bus_standard = "wishbone",
685 bus_data_width = 32,
686 bus_address_width = 32,
687 bus_timeout = 1e6,
688 bus_reserved_regions = {},
689
690 csr_data_width = 32,
691 csr_address_width = 14,
692 csr_paging = 0x800,
693 csr_ordering = "big",
694 csr_reserved_csrs = {},
695
696 irq_n_irqs = 32,
697 irq_reserved_irqs = {},
698 ):
699
700 self.logger = logging.getLogger("SoC")
701 self.logger.info(colorer(" __ _ __ _ __ ", color="bright"))
702 self.logger.info(colorer(" / / (_) /____ | |/_/ ", color="bright"))
703 self.logger.info(colorer(" / /__/ / __/ -_)> < ", color="bright"))
704 self.logger.info(colorer(" /____/_/\\__/\\__/_/|_| ", color="bright"))
705 self.logger.info(colorer(" Build your hardware, easily!", color="bright"))
706
707 self.logger.info(colorer("-"*80, color="bright"))
708 self.logger.info(colorer("Creating SoC... ({})".format(build_time())))
709 self.logger.info(colorer("-"*80, color="bright"))
710 self.logger.info("FPGA device : {}.".format(platform.device))
711 self.logger.info("System clock: {:3.2f}MHz.".format(sys_clk_freq/1e6))
712
713 # SoC attributes ---------------------------------------------------------------------------
714 self.platform = platform
715 self.sys_clk_freq = sys_clk_freq
716 self.constants = {}
717 self.csr_regions = {}
718
719 # SoC Bus Handler --------------------------------------------------------------------------
720 self.submodules.bus = SoCBusHandler(
721 standard = bus_standard,
722 data_width = bus_data_width,
723 address_width = bus_address_width,
724 timeout = bus_timeout,
725 reserved_regions = bus_reserved_regions,
726 )
727
728 # SoC Bus Handler --------------------------------------------------------------------------
729 self.submodules.csr = SoCCSRHandler(
730 data_width = csr_data_width,
731 address_width = csr_address_width,
732 alignment = 32,
733 paging = csr_paging,
734 ordering = csr_ordering,
735 reserved_csrs = csr_reserved_csrs,
736 )
737
738 # SoC IRQ Handler --------------------------------------------------------------------------
739 self.submodules.irq = SoCIRQHandler(
740 n_irqs = irq_n_irqs,
741 reserved_irqs = irq_reserved_irqs
742 )
743
744 self.logger.info(colorer("-"*80, color="bright"))
745 self.logger.info(colorer("Initial SoC:"))
746 self.logger.info(colorer("-"*80, color="bright"))
747 self.logger.info(self.bus)
748 self.logger.info(self.csr)
749 self.logger.info(self.irq)
750 self.logger.info(colorer("-"*80, color="bright"))
751
752 self.add_config("CLOCK_FREQUENCY", int(sys_clk_freq))
753
754 # SoC Helpers ----------------------------------------------------------------------------------
755 def check_if_exists(self, name):
756 if hasattr(self, name):
757 self.logger.error("{} SubModule already {}.".format(
758 colorer(name),
759 colorer("declared", color="red")))
760 raise
761
762 def add_constant(self, name, value=None):
763 name = name.upper()
764 if name in self.constants.keys():
765 self.logger.error("{} Constant already {}.".format(
766 colorer(name),
767 colorer("declared", color="red")))
768 raise
769 self.constants[name] = SoCConstant(value)
770
771 def add_config(self, name, value=None):
772 name = "CONFIG_" + name
773 if isinstance(value, str):
774 self.add_constant(name + "_" + value)
775 else:
776 self.add_constant(name, value)
777
778 # SoC Main Components --------------------------------------------------------------------------
779 def add_controller(self, name="ctrl", **kwargs):
780 self.check_if_exists(name)
781 setattr(self.submodules, name, SoCController(**kwargs))
782 self.csr.add(name, use_loc_if_exists=True)
783
784 def add_ram(self, name, origin, size, contents=[], mode="rw"):
785 ram_cls = {
786 "wishbone": wishbone.SRAM,
787 "axi-lite": axi.AXILiteSRAM,
788 }[self.bus.standard]
789 interface_cls = {
790 "wishbone": wishbone.Interface,
791 "axi-lite": axi.AXILiteInterface,
792 }[self.bus.standard]
793 ram_bus = interface_cls(data_width=self.bus.data_width)
794 ram = ram_cls(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
795 self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
796 self.check_if_exists(name)
797 self.logger.info("RAM {} {} {}.".format(
798 colorer(name),
799 colorer("added", color="green"),
800 self.bus.regions[name]))
801 setattr(self.submodules, name, ram)
802
803 def add_rom(self, name, origin, size, contents=[]):
804 self.add_ram(name, origin, size, contents, mode="r")
805
806 def add_csr_bridge(self, origin, register=False):
807 csr_bridge_cls = {
808 "wishbone": wishbone.Wishbone2CSR,
809 "axi-lite": axi.AXILite2CSR,
810 }[self.bus.standard]
811 self.submodules.csr_bridge = csr_bridge_cls(
812 bus_csr = csr_bus.Interface(
813 address_width = self.csr.address_width,
814 data_width = self.csr.data_width),
815 register = register)
816 csr_size = 2**(self.csr.address_width + 2)
817 csr_region = SoCRegion(origin=origin, size=csr_size, cached=False)
818 bus = getattr(self.csr_bridge, self.bus.standard.replace('-', '_'))
819 self.bus.add_slave("csr", bus, csr_region)
820 self.csr.add_master(name="bridge", master=self.csr_bridge.csr)
821 self.add_config("CSR_DATA_WIDTH", self.csr.data_width)
822 self.add_config("CSR_ALIGNMENT", self.csr.alignment)
823
824 def add_cpu(self, name="vexriscv", variant="standard", cls=None, reset_address=None):
825 if name not in cpu.CPUS.keys():
826 self.logger.error("{} CPU {}, supporteds: {}.".format(
827 colorer(name),
828 colorer("not supported", color="red"),
829 colorer(", ".join(cpu.CPUS.keys()))))
830 raise
831 # Add CPU
832 if name == "external" and cls is None:
833 self.logger.error("{} CPU requires {} to be specified.".format(
834 colorer(name),
835 colorer("cpu_cls", color="red")))
836 raise
837 cpu_cls = cls if cls is not None else cpu.CPUS[name]
838 if variant not in cpu_cls.variants:
839 self.logger.error("{} CPU variant {}, supporteds: {}.".format(
840 colorer(variant),
841 colorer("not supported", color="red"),
842 colorer(", ".join(cpu_cls.variants))))
843 raise
844 self.submodules.cpu = cpu_cls(self.platform, variant)
845 # Update SoC with CPU constraints
846 for n, (origin, size) in enumerate(self.cpu.io_regions.items()):
847 self.bus.add_region("io{}".format(n), SoCIORegion(origin=origin, size=size, cached=False))
848 self.mem_map.update(self.cpu.mem_map) # FIXME
849 # Add Bus Masters/CSR/IRQs
850 if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
851 if reset_address is None:
852 reset_address = self.mem_map["rom"]
853 self.cpu.set_reset_address(reset_address)
854 for n, cpu_bus in enumerate(self.cpu.periph_buses):
855 self.bus.add_master(name="cpu_bus{}".format(n), master=cpu_bus)
856 self.csr.add("cpu", use_loc_if_exists=True)
857 if hasattr(self.cpu, "interrupt"):
858 for name, loc in self.cpu.interrupts.items():
859 self.irq.add(name, loc)
860 self.add_config("CPU_HAS_INTERRUPT")
861
862 # Create optional DMA Bus (for Cache Coherence)
863 if hasattr(self.cpu, "dma_bus"):
864 self.submodules.dma_bus = SoCBusHandler(
865 name = "SoCDMABusHandler",
866 standard = "wishbone",
867 data_width = self.bus.data_width,
868 address_width = self.bus.address_width,
869 )
870 dma_bus = wishbone.Interface(data_width=self.bus.data_width)
871 self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only
872 self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus)
873
874 # Connect SoCController's reset to CPU reset
875 if hasattr(self, "ctrl"):
876 if hasattr(self.ctrl, "reset"):
877 self.comb += self.cpu.reset.eq(self.ctrl.reset)
878 self.add_config("CPU_RESET_ADDR", reset_address)
879 # Add constants
880 self.add_config("CPU_TYPE", str(name))
881 self.add_config("CPU_VARIANT", str(variant.split('+')[0]))
882 self.add_constant("CONFIG_CPU_HUMAN_NAME", getattr(self.cpu, "human_name", "Unknown"))
883 if hasattr(self.cpu, "nop"):
884 self.add_constant("CONFIG_CPU_NOP", self.cpu.nop)
885
886 def add_timer(self, name="timer0"):
887 self.check_if_exists(name)
888 setattr(self.submodules, name, Timer())
889 self.csr.add(name, use_loc_if_exists=True)
890 if hasattr(self.cpu, "interrupt"):
891 self.irq.add(name, use_loc_if_exists=True)
892
893 # SoC finalization -----------------------------------------------------------------------------
894 def do_finalize(self):
895 self.logger.info(colorer("-"*80, color="bright"))
896 self.logger.info(colorer("Finalized SoC:"))
897 self.logger.info(colorer("-"*80, color="bright"))
898 self.logger.info(self.bus)
899 if hasattr(self, "dma_bus"):
900 self.logger.info(self.dma_bus)
901 self.logger.info(self.csr)
902 self.logger.info(self.irq)
903 self.logger.info(colorer("-"*80, color="bright"))
904
905 interconnect_p2p_cls = {
906 "wishbone": wishbone.InterconnectPointToPoint,
907 "axi-lite": axi.AXILiteInterconnectPointToPoint,
908 }[self.bus.standard]
909 interconnect_shared_cls = {
910 "wishbone": wishbone.InterconnectShared,
911 "axi-lite": axi.AXILiteInterconnectShared,
912 }[self.bus.standard]
913
914 # SoC CSR bridge ---------------------------------------------------------------------------
915 # FIXME: for now, use registered CSR bridge when SDRAM is present; find the best compromise.
916 self.add_csr_bridge(self.mem_map["csr"], register=hasattr(self, "sdram"))
917
918 # SoC Bus Interconnect ---------------------------------------------------------------------
919 if len(self.bus.masters) and len(self.bus.slaves):
920 # If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
921 if ((len(self.bus.masters) == 1) and
922 (len(self.bus.slaves) == 1) and
923 (next(iter(self.bus.regions.values())).origin == 0)):
924 self.submodules.bus_interconnect = interconnect_p2p_cls(
925 master = next(iter(self.bus.masters.values())),
926 slave = next(iter(self.bus.slaves.values())))
927 # Otherwise, use InterconnectShared.
928 else:
929 self.submodules.bus_interconnect = interconnect_shared_cls(
930 masters = self.bus.masters.values(),
931 slaves = [(self.bus.regions[n].decoder(self.bus), s) for n, s in self.bus.slaves.items()],
932 register = True,
933 timeout_cycles = self.bus.timeout)
934 if hasattr(self, "ctrl") and self.bus.timeout is not None:
935 if hasattr(self.ctrl, "bus_error"):
936 self.comb += self.ctrl.bus_error.eq(self.bus_interconnect.timeout.error)
937 self.bus.logger.info("Interconnect: {} ({} <-> {}).".format(
938 colorer(self.bus_interconnect.__class__.__name__),
939 colorer(len(self.bus.masters)),
940 colorer(len(self.bus.slaves))))
941 self.add_constant("CONFIG_BUS_STANDARD", self.bus.standard.upper())
942 self.add_constant("CONFIG_BUS_DATA_WIDTH", self.bus.data_width)
943 self.add_constant("CONFIG_BUS_ADDRESS_WIDTH", self.bus.address_width)
944
945 # SoC DMA Bus Interconnect (Cache Coherence) -----------------------------------------------
946 if hasattr(self, "dma_bus"):
947 if len(self.dma_bus.masters) and len(self.dma_bus.slaves):
948 # If 1 bus_master, 1 bus_slave and no address translation, use InterconnectPointToPoint.
949 if ((len(self.dma_bus.masters) == 1) and
950 (len(self.dma_bus.slaves) == 1) and
951 (next(iter(self.dma_bus.regions.values())).origin == 0)):
952 self.submodules.dma_bus_interconnect = wishbone.InterconnectPointToPoint(
953 master = next(iter(self.dma_bus.masters.values())),
954 slave = next(iter(self.dma_bus.slaves.values())))
955 # Otherwise, use InterconnectShared.
956 else:
957 self.submodules.dma_bus_interconnect = wishbone.InterconnectShared(
958 masters = self.dma_bus.masters.values(),
959 slaves = [(self.dma_bus.regions[n].decoder(self.dma_bus), s) for n, s in self.dma_bus.slaves.items()],
960 register = True)
961 self.bus.logger.info("DMA Interconnect: {} ({} <-> {}).".format(
962 colorer(self.dma_bus_interconnect.__class__.__name__),
963 colorer(len(self.dma_bus.masters)),
964 colorer(len(self.dma_bus.slaves))))
965 self.add_constant("CONFIG_CPU_HAS_DMA_BUS")
966
967 # SoC CSR Interconnect ---------------------------------------------------------------------
968 self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
969 address_map = self.csr.address_map,
970 data_width = self.csr.data_width,
971 address_width = self.csr.address_width,
972 alignment = self.csr.alignment,
973 paging = self.csr.paging,
974 ordering = self.csr.ordering,
975 soc_bus_data_width = self.bus.data_width)
976 if len(self.csr.masters):
977 self.submodules.csr_interconnect = csr_bus.InterconnectShared(
978 masters = list(self.csr.masters.values()),
979 slaves = self.csr_bankarray.get_buses())
980
981 # Add CSRs regions
982 for name, csrs, mapaddr, rmap in self.csr_bankarray.banks:
983 self.csr.add_region(name, SoCCSRRegion(
984 origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr),
985 busword = self.csr.data_width,
986 obj = csrs))
987
988 # Add Memory regions
989 for name, memory, mapaddr, mmap in self.csr_bankarray.srams:
990 self.csr.add_region(name + "_" + memory.name_override, SoCCSRRegion(
991 origin = (self.bus.regions["csr"].origin + self.csr.paging*mapaddr),
992 busword = self.csr.data_width,
993 obj = memory))
994
995 # Sort CSR regions by origin
996 self.csr.regions = {k: v for k, v in sorted(self.csr.regions.items(), key=lambda item: item[1].origin)}
997
998 # Add CSRs / Config items to constants
999 for name, constant in self.csr_bankarray.constants:
1000 self.add_constant(name + "_" + constant.name, constant.value.value)
1001
1002 # SoC CPU Check ----------------------------------------------------------------------------
1003 if not isinstance(self.cpu, (cpu.CPUNone, cpu.Zynq7000)):
1004 if "sram" not in self.bus.regions.keys():
1005 self.logger.error("CPU needs {} Region to be {} as Bus or Linker Region.".format(
1006 colorer("sram"),
1007 colorer("defined", color="red")))
1008 self.logger.error(self.bus)
1009 raise
1010 cpu_reset_address_valid = False
1011 for name, container in self.bus.regions.items():
1012 if self.bus.check_region_is_in(
1013 region = SoCRegion(origin=self.cpu.reset_address, size=self.bus.data_width//8),
1014 container = container):
1015 cpu_reset_address_valid = True
1016 if name == "rom":
1017 self.cpu.use_rom = True
1018 if not cpu_reset_address_valid:
1019 self.logger.error("CPU needs {} to be in a {} Region.".format(
1020 colorer("reset address 0x{:08x}".format(self.cpu.reset_address)),
1021 colorer("defined", color="red")))
1022 self.logger.error(self.bus)
1023 raise
1024
1025 # SoC IRQ Interconnect ---------------------------------------------------------------------
1026 if hasattr(self, "cpu"):
1027 if hasattr(self.cpu, "interrupt"):
1028 for name, loc in sorted(self.irq.locs.items()):
1029 if name in self.cpu.interrupts.keys():
1030 continue
1031 if hasattr(self, name):
1032 module = getattr(self, name)
1033 if not hasattr(module, "ev"):
1034 self.logger.error("EventManager {} in {} SubModule.".format(
1035 colorer("not found", color="red"),
1036 colorer(name)))
1037 raise
1038 self.comb += self.cpu.interrupt[loc].eq(module.ev.irq)
1039 self.add_constant(name + "_INTERRUPT", loc)
1040
1041 # SoC build ------------------------------------------------------------------------------------
1042 def build(self, *args, **kwargs):
1043 self.build_name = kwargs.pop("build_name", self.platform.name)
1044 kwargs.update({"build_name": self.build_name})
1045 return self.platform.build(self, *args, **kwargs)
1046
1047 # LiteXSoC -----------------------------------------------------------------------------------------
1048
1049 class LiteXSoC(SoC):
1050 # Add Identifier -------------------------------------------------------------------------------
1051 def add_identifier(self, name="identifier", identifier="LiteX SoC", with_build_time=True):
1052 self.check_if_exists(name)
1053 if with_build_time:
1054 identifier += " " + build_time()
1055 setattr(self.submodules, name, Identifier(identifier))
1056 self.csr.add(name + "_mem", use_loc_if_exists=True)
1057
1058 # Add UART -------------------------------------------------------------------------------------
1059 def add_uart(self, name, baudrate=115200, fifo_depth=16):
1060 from litex.soc.cores import uart
1061
1062 # Stub / Stream
1063 if name in ["stub", "stream"]:
1064 self.submodules.uart = uart.UART(tx_fifo_depth=0, rx_fifo_depth=0)
1065 if name == "stub":
1066 self.comb += self.uart.sink.ready.eq(1)
1067
1068 # UARTBone / Bridge
1069 elif name in ["uartbone", "bridge"]:
1070 self.add_uartbone(baudrate=baudrate)
1071
1072 # Crossover
1073 elif name in ["crossover"]:
1074 self.submodules.uart = uart.UARTCrossover()
1075
1076 # Model/Sim
1077 elif name in ["model", "sim"]:
1078 self.submodules.uart_phy = uart.RS232PHYModel(self.platform.request("serial"))
1079 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy,
1080 tx_fifo_depth = fifo_depth,
1081 rx_fifo_depth = fifo_depth))
1082
1083 # JTAG Atlantic
1084 elif name in ["jtag_atlantic"]:
1085 from litex.soc.cores.jtag import JTAGAtlantic
1086 self.submodules.uart_phy = JTAGAtlantic()
1087 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy,
1088 tx_fifo_depth = fifo_depth,
1089 rx_fifo_depth = fifo_depth))
1090
1091 # JTAG UART
1092 elif name in ["jtag_uart"]:
1093 from litex.soc.cores.jtag import JTAGPHY
1094 self.submodules.uart_phy = JTAGPHY(device=self.platform.device)
1095 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy,
1096 tx_fifo_depth = fifo_depth,
1097 rx_fifo_depth = fifo_depth))
1098
1099 # USB ACM (with ValentyUSB core)
1100 elif name in ["usb_acm"]:
1101 import valentyusb.usbcore.io as usbio
1102 import valentyusb.usbcore.cpu.cdc_eptri as cdc_eptri
1103 usb_pads = self.platform.request("usb")
1104 usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup)
1105 self.submodules.uart = cdc_eptri.CDCUsb(usb_iobuf)
1106
1107 # Classic UART
1108 else:
1109 self.submodules.uart_phy = uart.UARTPHY(
1110 pads = self.platform.request(name),
1111 clk_freq = self.sys_clk_freq,
1112 baudrate = baudrate)
1113 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy,
1114 tx_fifo_depth = fifo_depth,
1115 rx_fifo_depth = fifo_depth))
1116
1117 self.csr.add("uart_phy", use_loc_if_exists=True)
1118 self.csr.add("uart", use_loc_if_exists=True)
1119 if hasattr(self.cpu, "interrupt"):
1120 self.irq.add("uart", use_loc_if_exists=True)
1121 else:
1122 self.add_constant("UART_POLLING")
1123
1124 # Add UARTbone ---------------------------------------------------------------------------------
1125 def add_uartbone(self, name="serial", baudrate=115200):
1126 from litex.soc.cores import uart
1127 self.submodules.uartbone = uart.UARTBone(
1128 pads = self.platform.request(name),
1129 clk_freq = self.sys_clk_freq,
1130 baudrate = baudrate)
1131 self.bus.add_master(name="uartbone", master=self.uartbone.wishbone)
1132
1133 # Add SDRAM ------------------------------------------------------------------------------------
1134 def add_sdram(self, name, phy, module, origin, size=None, with_soc_interconnect=True,
1135 l2_cache_size = 8192,
1136 l2_cache_min_data_width = 128,
1137 l2_cache_reverse = True,
1138 l2_cache_full_memory_we = True,
1139 **kwargs):
1140
1141 # Imports
1142 from litedram.common import LiteDRAMNativePort
1143 from litedram.core import LiteDRAMCore
1144 from litedram.frontend.wishbone import LiteDRAMWishbone2Native
1145 from litedram.frontend.axi import LiteDRAMAXI2Native
1146
1147 # LiteDRAM core
1148 self.submodules.sdram = LiteDRAMCore(
1149 phy = phy,
1150 geom_settings = module.geom_settings,
1151 timing_settings = module.timing_settings,
1152 clk_freq = self.sys_clk_freq,
1153 **kwargs)
1154 self.csr.add("sdram")
1155
1156 # Save SPD data to be able to verify it at runtime
1157 if hasattr(module, "_spd_data"):
1158 # pack the data into words of bus width
1159 bytes_per_word = self.bus.data_width // 8
1160 mem = [0] * ceil(len(module._spd_data) / bytes_per_word)
1161 for i in range(len(mem)):
1162 for offset in range(bytes_per_word):
1163 mem[i] <<= 8
1164 if self.cpu.endianness == "little":
1165 offset = bytes_per_word - 1 - offset
1166 spd_byte = i * bytes_per_word + offset
1167 if spd_byte < len(module._spd_data):
1168 mem[i] |= module._spd_data[spd_byte]
1169 self.add_rom(
1170 name="spd",
1171 origin=self.mem_map.get("spd", None),
1172 size=len(module._spd_data),
1173 contents=mem,
1174 )
1175
1176 if not with_soc_interconnect: return
1177
1178 # Compute/Check SDRAM size
1179 sdram_size = 2**(module.geom_settings.bankbits +
1180 module.geom_settings.rowbits +
1181 module.geom_settings.colbits)*phy.settings.databits//8
1182 if size is not None:
1183 sdram_size = min(sdram_size, size)
1184
1185 # Add SDRAM region
1186 self.bus.add_region("main_ram", SoCRegion(origin=origin, size=sdram_size))
1187
1188 # Add CPU's direct memory buses (if not already declared) ----------------------------------
1189 if hasattr(self.cpu, "add_memory_buses"):
1190 self.cpu.add_memory_buses(
1191 address_width = 32,
1192 data_width = self.sdram.crossbar.controller.data_width
1193 )
1194
1195 # Connect CPU's direct memory buses to LiteDRAM --------------------------------------------
1196 if len(self.cpu.memory_buses):
1197 # When CPU has at least a direct memory bus, connect them directly to LiteDRAM.
1198 for mem_bus in self.cpu.memory_buses:
1199 # Request a LiteDRAM native port.
1200 port = self.sdram.crossbar.get_port()
1201 port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2.
1202
1203 # Check if bus is an AXI bus and connect it.
1204 if isinstance(mem_bus, axi.AXIInterface):
1205 # If same data_width, connect it directly.
1206 if port.data_width == mem_bus.data_width:
1207 self.logger.info("Matching AXI MEM data width ({})\n".format(port.data_width))
1208 self.submodules += LiteDRAMAXI2Native(
1209 axi = self.cpu.mem_axi,
1210 port = port,
1211 base_address = self.bus.regions["main_ram"].origin)
1212 # If different data_width, do the adaptation and connect it via Wishbone.
1213 else:
1214 self.logger.info("Converting MEM data width: {} to {} via Wishbone".format(
1215 port.data_width,
1216 self.cpu.mem_axi.data_width))
1217 # FIXME: replace WB data-width converter with native AXI converter!!!
1218 mem_wb = wishbone.Interface(
1219 data_width = self.cpu.mem_axi.data_width,
1220 adr_width = 32-log2_int(self.cpu.mem_axi.data_width//8))
1221 # NOTE: AXI2Wishbone FSMs must be reset with the CPU!
1222 mem_a2w = ResetInserter()(axi.AXI2Wishbone(
1223 axi = self.cpu.mem_axi,
1224 wishbone = mem_wb,
1225 base_address = 0))
1226 self.comb += mem_a2w.reset.eq(ResetSignal() | self.cpu.reset)
1227 self.submodules += mem_a2w
1228 litedram_wb = wishbone.Interface(port.data_width)
1229 self.submodules += LiteDRAMWishbone2Native(
1230 wishbone = litedram_wb,
1231 port = port,
1232 base_address = origin)
1233 self.submodules += wishbone.Converter(mem_wb, litedram_wb)
1234 # Check if bus is a Native bus and connect it.
1235 if isinstance(mem_bus, LiteDRAMNativePort):
1236 # If same data_width, connect it directly.
1237 if port.data_width == mem_bus.data_width:
1238 self.comb += mem_bus.cmd.connect(port.cmd)
1239 self.comb += mem_bus.wdata.connect(port.wdata)
1240 self.comb += port.rdata.connect(mem_bus.rdata)
1241 # Else raise Error.
1242 else:
1243 raise NotImplementedError
1244
1245 # Connect Main bus to LiteDRAM (with optional L2 Cache) ------------------------------------
1246 connect_main_bus_to_dram = (
1247 # No memory buses.
1248 (not len(self.cpu.memory_buses)) or
1249 # Memory buses but no DMA bus.
1250 (len(self.cpu.memory_buses) and not hasattr(self.cpu, "dma_bus"))
1251 )
1252 if connect_main_bus_to_dram:
1253 # Request a LiteDRAM native port.
1254 port = self.sdram.crossbar.get_port()
1255 port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2.
1256
1257 # Create Wishbone Slave.
1258 wb_sdram = wishbone.Interface()
1259 self.bus.add_slave("main_ram", wb_sdram)
1260
1261 # L2 Cache
1262 if l2_cache_size != 0:
1263 # Insert L2 cache inbetween Wishbone bus and LiteDRAM
1264 l2_cache_size = max(l2_cache_size, int(2*port.data_width/8)) # Use minimal size if lower
1265 l2_cache_size = 2**int(log2(l2_cache_size)) # Round to nearest power of 2
1266 l2_cache_data_width = max(port.data_width, l2_cache_min_data_width)
1267 l2_cache = wishbone.Cache(
1268 cachesize = l2_cache_size//4,
1269 master = wb_sdram,
1270 slave = wishbone.Interface(l2_cache_data_width),
1271 reverse = l2_cache_reverse)
1272 if l2_cache_full_memory_we:
1273 l2_cache = FullMemoryWE()(l2_cache)
1274 self.submodules.l2_cache = l2_cache
1275 litedram_wb = self.l2_cache.slave
1276 else:
1277 litedram_wb = wishbone.Interface(port.data_width)
1278 self.submodules += wishbone.Converter(wb_sdram, litedram_wb)
1279 self.add_config("L2_SIZE", l2_cache_size)
1280
1281 # Wishbone Slave <--> LiteDRAM bridge
1282 self.submodules.wishbone_bridge = LiteDRAMWishbone2Native(
1283 wishbone = litedram_wb,
1284 port = port,
1285 base_address = self.bus.regions["main_ram"].origin)
1286
1287 # Add Ethernet ---------------------------------------------------------------------------------
1288 def add_ethernet(self, name="ethmac", phy=None):
1289 # Imports
1290 from liteeth.mac import LiteEthMAC
1291 # MAC
1292 ethmac = LiteEthMAC(
1293 phy = phy,
1294 dw = 32,
1295 interface = "wishbone",
1296 endianness = self.cpu.endianness)
1297 setattr(self.submodules, name, ethmac)
1298 ethmac_region = SoCRegion(origin=self.mem_map.get(name, None), size=0x2000, cached=False)
1299 self.bus.add_slave(name=name, slave=ethmac.bus, region=ethmac_region)
1300 self.add_csr(name)
1301 self.add_interrupt(name)
1302 # Timing constraints
1303 if hasattr(phy, "crg"):
1304 eth_rx_clk = phy.crg.cd_eth_rx.clk
1305 eth_tx_clk = phy.crg.cd_eth_tx.clk
1306 else:
1307 eth_rx_clk = phy.cd_eth_rx.clk
1308 eth_tx_clk = phy.cd_eth_tx.clk
1309 self.platform.add_period_constraint(eth_rx_clk, 1e9/phy.rx_clk_freq)
1310 self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq)
1311 self.platform.add_false_path_constraints(
1312 self.crg.cd_sys.clk,
1313 eth_rx_clk,
1314 eth_tx_clk)
1315
1316 # Add Etherbone --------------------------------------------------------------------------------
1317 def add_etherbone(self, name="etherbone", phy=None,
1318 mac_address = 0x10e2d5000000,
1319 ip_address = "192.168.1.50",
1320 udp_port = 1234):
1321 # Imports
1322 from liteeth.core import LiteEthUDPIPCore
1323 from liteeth.frontend.etherbone import LiteEthEtherbone
1324 # Core
1325 ethcore = LiteEthUDPIPCore(
1326 phy = phy,
1327 mac_address = mac_address,
1328 ip_address = ip_address,
1329 clk_freq = self.clk_freq)
1330 ethcore = ClockDomainsRenamer("eth_tx")(ethcore)
1331 self.submodules.ethcore = ethcore
1332
1333 # Clock domain renaming
1334 self.clock_domains.cd_etherbone = ClockDomain("etherbone")
1335 self.comb += self.cd_etherbone.clk.eq(ClockSignal("sys"))
1336 self.comb += self.cd_etherbone.rst.eq(ResetSignal("sys"))
1337
1338 # Etherbone
1339 etherbone = LiteEthEtherbone(ethcore.udp, udp_port, cd="etherbone")
1340 setattr(self.submodules, name, etherbone)
1341 self.add_wb_master(etherbone.wishbone.bus)
1342 # Timing constraints
1343 if hasattr(phy, "crg"):
1344 eth_rx_clk = phy.crg.cd_eth_rx.clk
1345 eth_tx_clk = phy.crg.cd_eth_tx.clk
1346 else:
1347 eth_rx_clk = phy.cd_eth_rx.clk
1348 eth_tx_clk = phy.cd_eth_tx.clk
1349 self.platform.add_period_constraint(eth_rx_clk, 1e9/phy.rx_clk_freq)
1350 self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq)
1351 self.platform.add_false_path_constraints(
1352 self.crg.cd_sys.clk,
1353 eth_rx_clk,
1354 eth_tx_clk)
1355
1356 # Add SPI Flash --------------------------------------------------------------------------------
1357 def add_spi_flash(self, name="spiflash", mode="4x", dummy_cycles=None, clk_freq=None):
1358 assert dummy_cycles is not None # FIXME: Get dummy_cycles from SPI Flash
1359 assert mode in ["1x", "4x"]
1360 if clk_freq is None: clk_freq = self.clk_freq/2 # FIXME: Get max clk_freq from SPI Flash
1361 spiflash = SpiFlash(
1362 pads = self.platform.request(name if mode == "1x" else name + mode),
1363 dummy = dummy_cycles,
1364 div = ceil(self.clk_freq/clk_freq),
1365 with_bitbang = True,
1366 endianness = self.cpu.endianness)
1367 spiflash.add_clk_primitive(self.platform.device)
1368 setattr(self.submodules, name, spiflash)
1369 self.add_memory_region(name, self.mem_map[name], 0x1000000) # FIXME: Get size from SPI Flash
1370 self.add_wb_slave(self.mem_map[name], spiflash.bus)
1371 self.add_csr(name)
1372
1373 # Add SPI SDCard -------------------------------------------------------------------------------
1374 def add_spi_sdcard(self, name="spisdcard", spi_clk_freq=400e3):
1375 pads = self.platform.request(name)
1376 if hasattr(pads, "rst"):
1377 self.comb += pads.rst.eq(0)
1378 spisdcard = SPIMaster(pads, 8, self.sys_clk_freq, spi_clk_freq)
1379 spisdcard.add_clk_divider()
1380 setattr(self.submodules, name, spisdcard)
1381 self.add_csr(name)
1382
1383 # Add SDCard -----------------------------------------------------------------------------------
1384 def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False):
1385 assert mode in ["read", "write", "read+write"]
1386 # Imports
1387 from litesdcard.emulator import SDEmulator
1388 from litesdcard.phy import SDPHY
1389 from litesdcard.core import SDCore
1390 from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA
1391
1392 # Emulator / Pads
1393 if use_emulator:
1394 sdemulator = SDEmulator(self.platform)
1395 self.submodules += sdemulator
1396 sdcard_pads = sdemulator.pads
1397 else:
1398 sdcard_pads = self.platform.request(name)
1399
1400 # Core
1401 self.submodules.sdphy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq)
1402 self.submodules.sdcore = SDCore(self.sdphy)
1403 self.add_csr("sdphy")
1404 self.add_csr("sdcore")
1405
1406 # Block2Mem DMA
1407 if "read" in mode:
1408 bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
1409 self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness)
1410 self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
1411 dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
1412 dma_bus.add_master("sdblock2mem", master=bus)
1413 self.add_csr("sdblock2mem")
1414
1415 # Mem2Block DMA
1416 if "write" in mode:
1417 bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.address_width)
1418 self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness)
1419 self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
1420 dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
1421 dma_bus.add_master("sdmem2block", master=bus)
1422 self.add_csr("sdmem2block")