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