soc: add add_uart method
[litex.git] / litex / soc / integration / soc.py
1 #!/usr/bin/env python3
2
3 # This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
4 # License: BSD
5
6 import logging
7 import time
8 import datetime
9
10 from migen import *
11
12 from litex.soc.cores.identifier import Identifier
13 from litex.soc.cores.timer import Timer
14
15 from litex.soc.interconnect.csr import *
16 from litex.soc.interconnect import csr_bus
17 from litex.soc.interconnect import wishbone
18 from litex.soc.interconnect import wishbone2csr
19
20 # TODO:
21 # - replace raise with exit on logging error.
22 # - add configurable CSR paging.
23 # - manage IO/Linker regions.
24
25 logging.basicConfig(level=logging.INFO)
26
27 # Helpers ------------------------------------------------------------------------------------------
28 def colorer(s, color="bright"):
29 header = {
30 "bright": "\x1b[1m",
31 "green": "\x1b[32m",
32 "cyan": "\x1b[36m",
33 "red": "\x1b[31m",
34 "yellow": "\x1b[33m",
35 "underline": "\x1b[4m"}[color]
36 trailer = "\x1b[0m"
37 return header + str(s) + trailer
38
39 def build_time(with_time=True):
40 fmt = "%Y-%m-%d %H:%M:%S" if with_time else "%Y-%m-%d"
41 return datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S")
42
43 # SoCConstant --------------------------------------------------------------------------------------
44
45 def SoCConstant(value):
46 return value
47
48 # SoCRegion ----------------------------------------------------------------------------------------
49
50 class SoCRegion:
51 def __init__(self, origin=None, size=None, mode="rw", cached=True):
52 self.logger = logging.getLogger("SoCRegion")
53 self.origin = origin
54 self.size = size
55 self.mode = mode
56 self.cached = cached
57
58 def decoder(self):
59 origin = self.origin
60 size = self.size
61 origin &= ~0x80000000
62 size = 2**log2_int(size, False)
63 if (origin & (size - 1)) != 0:
64 self.logger.error("Origin needs to be aligned on size:")
65 self.logger.error(self)
66 raise
67 origin >>= 2 # bytes to words aligned
68 size >>= 2 # bytes to words aligned
69 return lambda a: (a[log2_int(size):-1] == (origin >> log2_int(size)))
70
71 def __str__(self):
72 r = ""
73 if self.origin is not None:
74 r += "Origin: {}, ".format(colorer("0x{:08x}".format(self.origin)))
75 if self.size is not None:
76 r += "Size: {}, ".format(colorer("0x{:08x}".format(self.size)))
77 r += "Mode: {}, ".format(colorer(self.mode.upper()))
78 r += "Cached: {}".format(colorer(self.cached))
79 return r
80
81
82 class SoCLinkerRegion(SoCRegion):
83 pass
84
85 # SoCBusHandler ------------------------------------------------------------------------------------
86
87 class SoCBusHandler(Module):
88 supported_standard = ["wishbone"]
89 supported_data_width = [32, 64]
90 supported_address_width = [32]
91
92 # Creation -------------------------------------------------------------------------------------
93 def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
94 self.logger = logging.getLogger("SoCBusHandler")
95 self.logger.info(colorer("Creating new Bus Handler...", color="cyan"))
96
97 # Check Standard
98 if standard not in self.supported_standard:
99 self.logger.error("Unsupported Standard: {} supporteds: {:s}".format(
100 colorer(standard, color="red"),
101 colorer(", ".join(self.supported_standard), color="green")))
102 raise
103
104 # Check Data Width
105 if data_width not in self.supported_data_width:
106 self.logger.error("Unsupported Data_Width: {} supporteds: {:s}".format(
107 colorer(data_width, color="red"),
108 colorer(", ".join(str(x) for x in self.supported_data_width), color="green")))
109 raise
110
111 # Check Address Width
112 if address_width not in self.supported_address_width:
113 self.logger.error("Unsupported Address Width: {} supporteds: {:s}".format(
114 colorer(data_width, color="red"),
115 colorer(", ".join(str(x) for x in self.supported_address_width), color="green")))
116 raise
117
118 # Create Bus
119 self.standard = standard
120 self.data_width = data_width
121 self.address_width = address_width
122 self.masters = {}
123 self.slaves = {}
124 self.regions = {}
125 self.timeout = timeout
126 self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
127 colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
128
129 # Adding reserved regions
130 self.logger.info("Adding {} Regions...".format(colorer("reserved")))
131 for name, region in reserved_regions.items():
132 if isinstance(region, int):
133 region = SoCRegion(origin=region, size=0x1000000)
134 self.add_region(name, region)
135
136 self.logger.info(colorer("Bus Handler created.", color="cyan"))
137
138 # Add/Allog/Check Regions ----------------------------------------------------------------------
139 def add_region(self, name, region):
140 allocated = False
141 # Check if SoCLinkerRegion
142 if isinstance(region, SoCLinkerRegion):
143 self.logger.info("FIXME: SoCLinkerRegion")
144 # Check if SoCRegion
145 elif isinstance(region, SoCRegion):
146 # If no origin specified, allocate region.
147 if region.origin is None:
148 allocated = True
149 region = self.alloc_region(region.size, region.cached)
150 self.regions[name] = region
151 # Else add region and check for overlaps.
152 else:
153 self.regions[name] = region
154 overlap = self.check_region(self.regions)
155 if overlap is not None:
156 self.logger.error("Region overlap between {} and {}:".format(
157 colorer(overlap[0], color="red"),
158 colorer(overlap[1], color="red")))
159 self.logger.error(str(self.regions[overlap[0]]))
160 self.logger.error(str(self.regions[overlap[1]]))
161 raise
162 self.logger.info("{} Region {} {}.".format(
163 colorer(name, color="underline"),
164 colorer("allocated" if allocated else "added", color="yellow" if allocated else "green"),
165 str(region)))
166 else:
167 self.logger.error("{} is not a supported Region".format(colorer(name, color="red")))
168 raise
169
170 def alloc_region(self, size, cached=True):
171 self.logger.info("Allocating {} Region of size {}...".format(
172 colorer("Cached" if cached else "IO"),
173 colorer("0x{:08x}".format(size))))
174
175 # Limit Search Regions
176 uncached_regions = {}
177 for _, region in self.regions.items():
178 if region.cached == False:
179 uncached_regions[name] = region
180 if cached == False:
181 search_regions = uncached_regions
182 else:
183 search_regions = {"main": SoCRegion(origin=0x00000000, size=2**self.address_width-1)}
184
185 # Iterate on Search_Regions to find a Candidate
186 for _, search_region in search_regions.items():
187 origin = search_region.origin
188 while (origin + size) < (search_region.origin + search_region.size):
189 # Create a Candicate.
190 candidate = SoCRegion(origin=origin, size=size, cached=cached)
191 overlap = False
192 # Check Candidate does not overlap with allocated existing regions
193 for _, allocated in self.regions.items():
194 if self.check_region({"0": allocated, "1": candidate}) is not None:
195 origin = allocated.origin + allocated.size
196 overlap = True
197 break
198 if not overlap:
199 # If no overlap, the Candidate is selected
200 return candidate
201
202 self.logger.error("Not enough Address Space to allocate Region")
203 raise
204
205 def check_region(self, regions):
206 i = 0
207 while i < len(regions):
208 n0 = list(regions.keys())[i]
209 r0 = regions[n0]
210 for n1 in list(regions.keys())[i+1:]:
211 r1 = regions[n1]
212 if isinstance(r0, SoCLinkerRegion) or isinstance(r1, SoCLinkerRegion):
213 continue
214 if r0.origin >= (r1.origin + r1.size):
215 continue
216 if r1.origin >= (r0.origin + r0.size):
217 continue
218 return (n0, n1)
219 i += 1
220 return None
221
222 # Add Master/Slave -----------------------------------------------------------------------------
223 def add_master(self, name=None, master=None, io_regions={}):
224 if name is None:
225 name = "master{:d}".format(len(self.masters))
226 if name in self.masters.keys():
227 self.logger.error("{} already declared as Bus Master:".format(colorer(name, color="red")))
228 self.logger.error(self)
229 raise
230 if master.data_width != self.data_width:
231 self.logger.info("{} Bus Master {} from {}-bit to {}-bit.".format(
232 colorer(name),
233 colorer("converted", color="yellow"),
234 colorer(master.data_width),
235 colorer(self.data_width)))
236 new_master = wishbone.Interface(data_width=self.data_width)
237 self.submodules += wishbone.Converter(master, new_master)
238 master = new_master
239 self.masters[name] = master
240 self.logger.info("{} {} as Bus Master.".format(
241 colorer(name, color="underline"),
242 colorer("added", color="green")))
243 # FIXME: handle IO regions
244
245 def add_slave(self, name=None, slave=None, region=None):
246 no_name = name is None
247 no_region = region is None
248 if no_name and no_region:
249 self.logger.error("Please specify at least {} or {} of Bus Slave".format(
250 colorer("name", color="red"),
251 colorer("region", color="red")))
252 raise
253 if no_name:
254 name = "slave{:d}".format(len(self.slaves))
255 if no_region:
256 region = self.regions.get(name, None)
257 if region is None:
258 self.logger.error("Unable to find Region {}".format(colorer(name, color="red")))
259 raise
260 else:
261 self.add_region(name, region)
262 if name in self.slaves.keys():
263 self.logger.error("{} already declared as Bus Slave:".format(colorer(name, color="red")))
264 self.logger.error(self)
265 raise
266 if slave.data_width != self.data_width:
267 self.logger.error("{} Bus Slave {} from {}-bit to {}-bit.".format(
268 colorer(name),
269 colorer("converted", color="yellow"),
270 colorer(slave.data_width),
271 colorer(self.data_width)))
272 new_slave = wishbone.Interface(data_width=self.data_width)
273 self.submodules += wishbone.Converter(slave, new_slave)
274 slave = new_slave
275 self.slaves[name] = slave
276 self.logger.info("{} {} as Bus Slave.".format(
277 colorer(name, color="underline"),
278 colorer("added", color="green")))
279
280 # Str ------------------------------------------------------------------------------------------
281 def __str__(self):
282 r = "{}-bit {} Bus, {}GiB Address Space.\n".format(
283 colorer(self.data_width), colorer(self.standard), colorer(2**self.address_width/2**30))
284 r += "Bus Regions: ({})\n".format(len(self.regions.keys())) if len(self.regions.keys()) else ""
285 for name, region in self.regions.items():
286 r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
287 r += "Bus Masters: ({})\n".format(len(self.masters.keys())) if len(self.masters.keys()) else ""
288 for name in self.masters.keys():
289 r += "- {}\n".format(colorer(name, color="underline"))
290 r += "Bus Slaves: ({})\n".format(len(self.slaves.keys())) if len(self.slaves.keys()) else ""
291 for name in self.slaves.keys():
292 r += "- {}\n".format(colorer(name, color="underline"))
293 r = r[:-1]
294 return r
295
296 # SoCLocHandler --------------------------------------------------------------------------------------
297
298 class SoCLocHandler(Module):
299 # Creation -------------------------------------------------------------------------------------
300 def __init__(self, name, n_locs):
301 self.name = name
302 self.locs = {}
303 self.n_locs = n_locs
304
305 # Add ------------------------------------------------------------------------------------------
306 def add(self, name, n=None, use_loc_if_exists=False):
307 allocated = False
308 if not (use_loc_if_exists and name in self.locs.keys()):
309 if name in self.locs.keys():
310 self.logger.error("{} {} name already used.".format(colorer(name, "red"), self.name))
311 self.logger.error(self)
312 raise
313 if n in self.locs.values():
314 self.logger.error("{} {} Location already used.".format(colorer(n, "red"), self.name))
315 self.logger.error(self)
316 raise
317 if n is None:
318 allocated = True
319 n = self.alloc(name)
320 else:
321 if n < 0:
322 self.logger.error("{} {} Location should be positive.".format(
323 colorer(n, color="red"),
324 self.name))
325 raise
326 if n > self.n_locs:
327 self.logger.error("{} {} Location too high (Up to {}).".format(
328 colorer(n, color="red"),
329 self.name,
330 colorer(self.n_csrs, color="green")))
331 raise
332 self.locs[name] = n
333 else:
334 n = self.locs[name]
335 self.logger.info("{} {} {} at Location {}.".format(
336 colorer(name, color="underline"),
337 self.name,
338 colorer("allocated" if allocated else "added", color="yellow" if allocated else "green"),
339 colorer(n)))
340
341 # Alloc ----------------------------------------------------------------------------------------
342 def alloc(self, name):
343 for n in range(self.n_locs):
344 if n not in self.locs.values():
345 return n
346 self.logger.error("Not enough Locations.")
347 self.logger.error(self)
348 raise
349
350 # Str ------------------------------------------------------------------------------------------
351 def __str__(self):
352 r = "{} Locations: ({})\n".format(self.name, len(self.locs.keys())) if len(self.locs.keys()) else ""
353 for name in self.locs.keys():
354 r += "- {}{}: {}\n".format(colorer(name, color="underline"), " "*(20-len(name)), colorer(self.locs[name]))
355 return r
356
357 # SoCCSRHandler ------------------------------------------------------------------------------------
358
359 class SoCCSRHandler(SoCLocHandler):
360 supported_data_width = [8, 32]
361 supported_address_width = [14, 15]
362 supported_alignment = [32, 64]
363 supported_paging = [0x800]
364
365 # Creation -------------------------------------------------------------------------------------
366 def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, reserved_csrs={}):
367 SoCLocHandler.__init__(self, "CSR", n_locs=4*2**address_width//paging) # FIXME
368 self.logger = logging.getLogger("SoCCSRHandler")
369 self.logger.info(colorer("Creating new CSR Handler...", color="cyan"))
370
371 # Check Data Width
372 if data_width not in self.supported_data_width:
373 self.logger.error("Unsupported data_width: {} supporteds: {:s}".format(
374 colorer(data_width, color="red"),
375 colorer(", ".join(str(x) for x in self.supported_data_width)), color="green"))
376 raise
377
378 # Check Address Width
379 if address_width not in self.supported_address_width:
380 self.logger.error("Unsupported address_width: {} supporteds: {:s}".format(
381 colorer(address_width, color="red"),
382 colorer(", ".join(str(x) for x in self.supported_address_width), color="green")))
383 raise
384
385 # Check Alignment
386 if alignment not in self.supported_alignment:
387 self.logger.error("Unsupported alignment: {} supporteds: {:s}".format(
388 colorer(alignment, color="red"),
389 colorer(", ".join(str(x) for x in self.supported_alignment), color="green")))
390 raise
391 if data_width > alignment:
392 self.logger.error("Alignment ({}) should be >= data_width ({})".format(
393 colorer(alignment, color="red"),
394 colorer(data_width, color="red")))
395 raise
396
397 # Check Paging
398 if paging not in self.supported_paging:
399 self.logger.error("Unsupported paging: {} supporteds: {:s}".format(
400 colorer(paging, color="red"),
401 colorer(", ".join(str(x) for x in self.supported_paging), color="green")))
402 raise
403
404 # Create CSR Handler
405 self.data_width = data_width
406 self.address_width = address_width
407 self.alignment = alignment
408 self.paging = paging
409 self.masters = {}
410 self.logger.info("{}-bit CSR Bus, {}KiB Address Space, {}B Paging (Up to {} Locations).\n".format(
411 colorer(self.data_width),
412 colorer(2**self.address_width/2**10),
413 colorer(self.paging),
414 colorer(self.n_locs)))
415
416 # Adding reserved CSRs
417 self.logger.info("Adding {} CSRs...".format(colorer("reserved")))
418 for name, n in reserved_csrs.items():
419 self.add(name, n)
420
421 self.logger.info(colorer("CSR Handler created.", color="cyan"))
422
423 # Add Master -----------------------------------------------------------------------------------
424 def add_master(self, name=None, master=None):
425 if name is None:
426 name = "master{:d}".format(len(self.masters))
427 if name in self.masters.keys():
428 self.logger.error("{} already declared as CSR Master:".format(colorer(name, color="red")))
429 self.logger.error(self)
430 raise
431 print(master)
432 if master.data_width != self.data_width:
433 self.logger.error("{} Master/Handler data_width {} ({} vs {}).".format(
434 colorer(name),
435 colorer("missmatch"),
436 colorer(master.data_width, color="red"),
437 colorer(self.data_width, color="red")))
438 raise
439 self.masters[name] = master
440 self.logger.info("{} {} as CSR Master.".format(
441 colorer(name, color="underline"),
442 colorer("added", color="green")))
443 # FIXME: handle IO regions
444
445 # Address map ----------------------------------------------------------------------------------
446 def address_map(self, name, memory):
447 if memory is not None:
448 name = name + "_" + memory.name_override
449 if self.locs.get(name, None) is None:
450 self.logger.error("Undefined {} CSR.".format(colorer(name, color="red")))
451 raise
452 return self.locs[name]
453
454 # Str ------------------------------------------------------------------------------------------
455 def __str__(self):
456 r = "{}-bit CSR Bus, {}KiB Address Space, {}B Paging (Up to {} Locations).\n".format(
457 colorer(self.data_width),
458 colorer(2**self.address_width/2**10),
459 colorer(self.paging),
460 colorer(self.n_locs))
461 r += SoCLocHandler.__str__(self)
462 r = r[:-1]
463 return r
464
465 # SoCIRQHandler ------------------------------------------------------------------------------------
466
467 class SoCIRQHandler(SoCLocHandler):
468 # Creation -------------------------------------------------------------------------------------
469 def __init__(self, n_irqs=32, reserved_irqs={}):
470 SoCLocHandler.__init__(self, "IRQ", n_locs=n_irqs)
471 self.logger = logging.getLogger("SoCIRQHandler")
472 self.logger.info(colorer("Creating new SoC IRQ Handler...", color="cyan"))
473
474 # Check IRQ Number
475 if n_irqs > 32:
476 self.logger.error("Unsupported IRQs number: {} supporteds: {:s}".format(
477 colorer(n, color="red"), colorer("Up to 32", color="green")))
478 raise
479
480 # Create IRQ Handler
481 self.logger.info("IRQ Handler (up to {} Locations).".format(colorer(n_irqs)))
482
483 # Adding reserved IRQs
484 self.logger.info("Adding {} IRQs...".format(colorer("reserved")))
485 for name, n in reserved_irqs.items():
486 self.add(name, n)
487
488 self.logger.info(colorer("IRQ Handler created.", color="cyan"))
489
490 # Str ------------------------------------------------------------------------------------------
491 def __str__(self):
492 r ="IRQ Handler (up to {} Locations).\n".format(colorer(self.n_locs))
493 r += SoCLocHandler.__str__(self)
494 r = r[:-1]
495 return r
496
497 # SoCController ------------------------------------------------------------------------------------
498
499 class SoCController(Module, AutoCSR):
500 def __init__(self):
501 self._reset = CSRStorage(1, description="""
502 Write a ``1`` to this register to reset the SoC.""")
503 self._scratch = CSRStorage(32, reset=0x12345678, description="""
504 Use this register as a scratch space to verify that software read/write accesses
505 to the Wishbone/CSR bus are working correctly. The initial reset value of 0x1234578
506 can be used to verify endianness.""")
507 self._bus_errors = CSRStatus(32, description="""
508 Total number of Wishbone bus errors (timeouts) since last reset.""")
509
510 # # #
511
512 # Reset
513 self.reset = Signal()
514 self.comb += self.reset.eq(self._reset.re)
515
516 # Bus errors
517 self.bus_error = Signal()
518 bus_errors = Signal(32)
519 self.sync += \
520 If(bus_errors != (2**len(bus_errors)-1),
521 If(self.bus_error, bus_errors.eq(bus_errors + 1))
522 )
523 self.comb += self._bus_errors.status.eq(bus_errors)
524
525 # SoC ----------------------------------------------------------------------------------------------
526
527 class SoC(Module):
528 def __init__(self, platform, sys_clk_freq,
529
530 bus_standard = "wishbone",
531 bus_data_width = 32,
532 bus_address_width = 32,
533 bus_timeout = 1e6,
534 bus_reserved_regions = {},
535
536 csr_data_width = 32,
537 csr_address_width = 14,
538 csr_alignment = 32,
539 csr_paging = 0x800,
540 csr_reserved_csrs = {},
541
542 irq_n_irqs = 32,
543 irq_reserved_irqs = {},
544 ):
545
546 self.logger = logging.getLogger("SoC")
547 self.logger.info(colorer(" __ _ __ _ __ ", color="bright"))
548 self.logger.info(colorer(" / / (_) /____ | |/_/ ", color="bright"))
549 self.logger.info(colorer(" / /__/ / __/ -_)> < ", color="bright"))
550 self.logger.info(colorer(" /____/_/\\__/\\__/_/|_| ", color="bright"))
551 self.logger.info(colorer(" Build your hardware, easily!", color="bright"))
552
553 self.logger.info(colorer("-"*80, color="bright"))
554 self.logger.info(colorer("Creating new SoC... ({})".format(build_time()), color="cyan"))
555 self.logger.info(colorer("-"*80, color="bright"))
556
557 # SoC attributes ---------------------------------------------------------------------------
558 self.platform = platform
559 self.sys_clk_freq = sys_clk_freq
560 self.constants = {}
561
562 # SoC Bus Handler --------------------------------------------------------------------------
563 self.submodules.bus = SoCBusHandler(
564 standard = bus_standard,
565 data_width = bus_data_width,
566 address_width = bus_address_width,
567 timeout = bus_timeout,
568 reserved_regions = bus_reserved_regions,
569 )
570
571 # SoC Bus Handler --------------------------------------------------------------------------
572 self.submodules.csr = SoCCSRHandler(
573 data_width = csr_data_width,
574 address_width = csr_address_width,
575 alignment = csr_alignment,
576 paging = csr_paging,
577 reserved_csrs = csr_reserved_csrs,
578 )
579
580 # SoC IRQ Handler --------------------------------------------------------------------------
581 self.submodules.irq = SoCIRQHandler(
582 n_irqs = irq_n_irqs,
583 reserved_irqs = irq_reserved_irqs
584 )
585
586 self.logger.info(colorer("-"*80, color="bright"))
587 self.logger.info(colorer("Initial SoC:", color="cyan"))
588 self.logger.info(colorer("-"*80, color="bright"))
589 self.logger.info(self.bus)
590 self.logger.info(self.csr)
591 self.logger.info(self.irq)
592 self.logger.info(colorer("-"*80, color="bright"))
593
594
595 # SoC Helpers ----------------------------------------------------------------------------------
596 def check_if_exists(self, name):
597 if hasattr(self, name):
598 self.logger.error("{} SubModule already declared.".format(colorer(name, "red")))
599 raise
600
601 def add_constant(self, name, value=None):
602 name = name.upper()
603 if name in self.constants.keys():
604 self.logger.error("{} Constant already declared.".format(colorer(name, "red")))
605 raise
606 self.constants[name] = SoCConstant(value)
607
608 def add_config(self, name, value):
609 name = "CONFIG_" + name
610 if isinstance(value, str):
611 self.add_constant(name + "_" + value)
612 else:
613 self.add_constant(name, value)
614
615 # SoC Main components --------------------------------------------------------------------------
616 def add_ram(self, name, origin, size, contents=[], mode="rw"):
617 ram_bus = wishbone.Interface(data_width=self.bus.data_width)
618 ram = wishbone.SRAM(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
619 self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
620 self.check_if_exists(name)
621 self.logger.info("RAM {} {} {}.".format(
622 colorer(name),
623 colorer("added", color="green"),
624 self.bus.regions[name]))
625 setattr(self.submodules, name, ram)
626
627 def add_rom(self, name, origin, size, contents=[]):
628 self.add_ram(name, origin, size, contents, mode="r")
629
630 def add_controller(self, name="ctrl"):
631 self.check_if_exists(name)
632 setattr(self.submodules, name, SoCController())
633 self.csr.add(name, use_loc_if_exists=True)
634
635 def add_identifier(self, name="identifier", identifier="LiteX SoC", with_build_time=True):
636 self.check_if_exists(name)
637 if with_build_time:
638 identifier += " " + build_time()
639 setattr(self.submodules, name, Identifier(ident))
640 self.csr.add(name + "_mem", use_loc_if_exists=True)
641
642 def add_timer(self, name="timer0"):
643 self.check_if_exists(name)
644 setattr(self.submodules, name, Timer())
645 self.csr.add(name, use_loc_if_exists=True)
646 self.irq.add(name, use_loc_if_exists=True)
647
648 def add_csr_bridge(self, origin):
649 self.submodules.csr_bridge = wishbone2csr.WB2CSR(
650 bus_csr = csr_bus.Interface(
651 address_width = self.csr.address_width,
652 data_width = self.csr.data_width))
653 csr_size = 2**(self.csr.address_width + 2)
654 self.bus.add_slave("csr", self.csr_bridge.wishbone, SoCRegion(origin=origin, size=csr_size))
655 self.csr.add_master(name="bridge", master=self.csr_bridge.csr)
656
657 # SoC Peripherals ------------------------------------------------------------------------------
658 def add_uart(self, name, baudrate=115200):
659 from litex.soc.cores import uart
660 if name in ["stub", "stream"]:
661 self.submodules.uart = uart.UART()
662 if name == "stub":
663 self.comb += self.uart.sink.ready.eq(1)
664 elif name == "bridge":
665 self.submodules.uart = uart.UARTWishboneBridge(
666 pads = self.platform.request("serial"),
667 clk_freq = self.sys_clk_freq,
668 baudrate = baudrate)
669 self.bus.master(name="uart_bridge", master=self.uart.wishbone)
670 elif name == "crossover":
671 self.submodules.uart = uart.UARTCrossover()
672 else:
673 if name == "jtag_atlantic":
674 from litex.soc.cores.jtag import JTAGAtlantic
675 self.submodules.uart_phy = JTAGAtlantic()
676 elif name == "jtag_uart":
677 from litex.soc.cores.jtag import JTAGPHY
678 self.submodules.uart_phy = JTAGPHY(device=self.platform.device)
679 else:
680 self.submodules.uart_phy = uart.UARTPHY(
681 pads = self.platform.request(name),
682 clk_freq = self.sys_clk_freq,
683 baudrate = baudrate)
684 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy))
685 self.csr.add("uart_phy", use_loc_if_exists=True)
686 self.csr.add("uart", use_loc_if_exists=True)
687 self.irq.add("uart", use_loc_if_exists=True)
688
689 # SoC finalization -----------------------------------------------------------------------------
690 def do_finalize(self):
691 self.logger.info(colorer("-"*80, color="bright"))
692 self.logger.info(colorer("Finalized SoC:", color="cyan"))
693 self.logger.info(colorer("-"*80, color="bright"))
694 self.logger.info(self.bus)
695 self.logger.info(self.csr)
696 self.logger.info(self.irq)
697 self.logger.info(colorer("-"*80, color="bright"))
698
699 # SoC Bus Interconnect ---------------------------------------------------------------------
700 bus_masters = self.bus.masters.values()
701 bus_slaves = [(self.bus.regions[n].decoder(), s) for n, s in self.bus.slaves.items()]
702 if len(bus_masters) and len(bus_slaves):
703 self.submodules.bus_interconnect = wishbone.InterconnectShared(
704 masters = bus_masters,
705 slaves = bus_slaves,
706 register = True,
707 timeout_cycles = self.bus.timeout)
708 if hasattr(self, "ctrl") and self.bus.timeout is not None:
709 self.comb += self.ctrl.bus_error.eq(self.bus_interconnect.timeout.error)
710
711 # SoC CSR Interconnect ---------------------------------------------------------------------
712 self.submodules.csr_bankarray = csr_bus.CSRBankArray(self,
713 address_map = self.csr.address_map,
714 data_width = self.csr.data_width,
715 address_width = self.csr.address_width,
716 alignment = self.csr.alignment
717 )
718 if len(self.csr.masters):
719 self.submodules.csr_interconnect = csr_bus.InterconnectShared(
720 masters = list(self.csr.masters.values()),
721 slaves = self.csr_bankarray.get_buses())
722
723 # SoC IRQ Interconnect ---------------------------------------------------------------------
724 if hasattr(self, "cpu"):
725 if hasattr(self.cpu, "interrupt"):
726 for name, loc in sorted(self.irq.locs.items()):
727 if name in self.cpu.interrupts.keys():
728 continue
729 if hasattr(self, name):
730 module = getattr(self, name)
731 if not hasattr(module, "ev"):
732 self.logger.error("No EventManager found on {} SubModule".format(
733 colorer(name, color="red")))
734 self.comb += self.cpu.interrupt[loc].eq(module.ev.irq)
735 self.add_constant(name + "_INTERRUPT", loc)