soc: add add_csr_bridge 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 # SoCRegion ----------------------------------------------------------------------------------------
44
45 class SoCRegion:
46 def __init__(self, origin=None, size=None, mode="rw", cached=True):
47 self.logger = logging.getLogger("SoCRegion")
48 self.origin = origin
49 self.size = size
50 self.mode = mode
51 self.cached = cached
52
53 def decoder(self):
54 origin = self.origin
55 size = self.size
56 origin &= ~0x80000000
57 size = 2**log2_int(size, False)
58 if (origin & (size - 1)) != 0:
59 self.logger.error("Origin needs to be aligned on size:")
60 self.logger.error(self)
61 raise
62 origin >>= 2 # bytes to words aligned
63 size >>= 2 # bytes to words aligned
64 return lambda a: (a[log2_int(size):-1] == (origin >> log2_int(size)))
65
66 def __str__(self):
67 r = ""
68 if self.origin is not None:
69 r += "Origin: {}, ".format(colorer("0x{:08x}".format(self.origin)))
70 if self.size is not None:
71 r += "Size: {}, ".format(colorer("0x{:08x}".format(self.size)))
72 r += "Mode: {}, ".format(colorer(self.mode.upper()))
73 r += "Cached: {}".format(colorer(self.cached))
74 return r
75
76
77 class SoCLinkerRegion(SoCRegion):
78 pass
79
80 # SoCBusHandler ------------------------------------------------------------------------------------
81
82 class SoCBusHandler(Module):
83 supported_standard = ["wishbone"]
84 supported_data_width = [32, 64]
85 supported_address_width = [32]
86
87 # Creation -------------------------------------------------------------------------------------
88 def __init__(self, standard, data_width=32, address_width=32, timeout=1e6, reserved_regions={}):
89 self.logger = logging.getLogger("SoCBusHandler")
90 self.logger.info(colorer("Creating new Bus Handler...", color="cyan"))
91
92 # Check Standard
93 if standard not in self.supported_standard:
94 self.logger.error("Unsupported Standard: {} supporteds: {:s}".format(
95 colorer(standard, color="red"),
96 colorer(", ".join(self.supported_standard), color="green")))
97 raise
98
99 # Check Data Width
100 if data_width not in self.supported_data_width:
101 self.logger.error("Unsupported Data_Width: {} supporteds: {:s}".format(
102 colorer(data_width, color="red"),
103 colorer(", ".join(str(x) for x in self.supported_data_width), color="green")))
104 raise
105
106 # Check Address Width
107 if address_width not in self.supported_address_width:
108 self.logger.error("Unsupported Address Width: {} supporteds: {:s}".format(
109 colorer(data_width, color="red"),
110 colorer(", ".join(str(x) for x in self.supported_address_width), color="green")))
111 raise
112
113 # Create Bus
114 self.standard = standard
115 self.data_width = data_width
116 self.address_width = address_width
117 self.masters = {}
118 self.slaves = {}
119 self.regions = {}
120 self.timeout = timeout
121 self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
122 colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
123
124 # Adding reserved regions
125 self.logger.info("Adding {} Regions...".format(colorer("reserved")))
126 for name, region in reserved_regions.items():
127 if isinstance(region, int):
128 region = SoCRegion(origin=region, size=0x1000000)
129 self.add_region(name, region)
130
131 self.logger.info(colorer("Bus Handler created.", color="cyan"))
132
133 # Add/Allog/Check Regions ----------------------------------------------------------------------
134 def add_region(self, name, region):
135 allocated = False
136 # Check if SoCLinkerRegion
137 if isinstance(region, SoCLinkerRegion):
138 self.logger.info("FIXME: SoCLinkerRegion")
139 # Check if SoCRegion
140 elif isinstance(region, SoCRegion):
141 # If no origin specified, allocate region.
142 if region.origin is None:
143 allocated = True
144 region = self.alloc_region(region.size, region.cached)
145 self.regions[name] = region
146 # Else add region and check for overlaps.
147 else:
148 self.regions[name] = region
149 overlap = self.check_region(self.regions)
150 if overlap is not None:
151 self.logger.error("Region overlap between {} and {}:".format(
152 colorer(overlap[0], color="red"),
153 colorer(overlap[1], color="red")))
154 self.logger.error(str(self.regions[overlap[0]]))
155 self.logger.error(str(self.regions[overlap[1]]))
156 raise
157 self.logger.info("{} Region {} {}.".format(
158 colorer(name, color="underline"),
159 colorer("allocated" if allocated else "added", color="yellow" if allocated else "green"),
160 str(region)))
161 else:
162 self.logger.error("{} is not a supported Region".format(colorer(name, color="red")))
163 raise
164
165 def alloc_region(self, size, cached=True):
166 self.logger.info("Allocating {} Region of size {}...".format(
167 colorer("Cached" if cached else "IO"),
168 colorer("0x{:08x}".format(size))))
169
170 # Limit Search Regions
171 uncached_regions = {}
172 for _, region in self.regions.items():
173 if region.cached == False:
174 uncached_regions[name] = region
175 if cached == False:
176 search_regions = uncached_regions
177 else:
178 search_regions = {"main": SoCRegion(origin=0x00000000, size=2**self.address_width-1)}
179
180 # Iterate on Search_Regions to find a Candidate
181 for _, search_region in search_regions.items():
182 origin = search_region.origin
183 while (origin + size) < (search_region.origin + search_region.size):
184 # Create a Candicate.
185 candidate = SoCRegion(origin=origin, size=size, cached=cached)
186 overlap = False
187 # Check Candidate does not overlap with allocated existing regions
188 for _, allocated in self.regions.items():
189 if self.check_region({"0": allocated, "1": candidate}) is not None:
190 origin = allocated.origin + allocated.size
191 overlap = True
192 break
193 if not overlap:
194 # If no overlap, the Candidate is selected
195 return candidate
196
197 self.logger.error("Not enough Address Space to allocate Region")
198 raise
199
200 def check_region(self, regions):
201 i = 0
202 while i < len(regions):
203 n0 = list(regions.keys())[i]
204 r0 = regions[n0]
205 for n1 in list(regions.keys())[i+1:]:
206 r1 = regions[n1]
207 if isinstance(r0, SoCLinkerRegion) or isinstance(r1, SoCLinkerRegion):
208 continue
209 if r0.origin >= (r1.origin + r1.size):
210 continue
211 if r1.origin >= (r0.origin + r0.size):
212 continue
213 return (n0, n1)
214 i += 1
215 return None
216
217 # Add Master/Slave -----------------------------------------------------------------------------
218 def add_master(self, name=None, master=None, io_regions={}):
219 if name is None:
220 name = "master{:d}".format(len(self.masters))
221 if name in self.masters.keys():
222 self.logger.error("{} already declared as Bus Master:".format(colorer(name, color="red")))
223 self.logger.error(self)
224 raise
225 if master.data_width != self.data_width:
226 self.logger.error("{} Bus Master {} from {}-bit to {}-bit.".format(
227 colorer(name),
228 colorer("converted", color="yellow"),
229 colorer(master.data_width),
230 colorer(self.data_width)))
231 new_master = wishbone.Interface(data_width=self.data_width)
232 self.submodules += wishbone.Converter(master, new_master)
233 master = new_master
234 self.masters[name] = master
235 self.logger.info("{} {} as Bus Master.".format(colorer(name, color="underline"), colorer("added", color="green")))
236 # FIXME: handle IO regions
237
238 def add_slave(self, name=None, slave=None, region=None):
239 no_name = name is None
240 no_region = region is None
241 if no_name and no_region:
242 self.logger.error("Please specify at least {} or {} of Bus Slave".format(
243 colorer("name", color="red"),
244 colorer("region", color="red")))
245 raise
246 if no_name:
247 name = "slave{:d}".format(len(self.slaves))
248 if no_region:
249 region = self.regions.get(name, None)
250 if region is None:
251 self.logger.error("Unable to find Region {}".format(colorer(name, color="red")))
252 raise
253 else:
254 self.add_region(name, region)
255 if name in self.slaves.keys():
256 self.logger.error("{} already declared as Bus Slave:".format(colorer(name, color="red")))
257 self.logger.error(self)
258 raise
259 if slave.data_width != self.data_width:
260 self.logger.error("{} Bus Slave {} from {}-bit to {}-bit.".format(
261 colorer(name),
262 colorer("converted", color="yellow"),
263 colorer(slave.data_width),
264 colorer(self.data_width)))
265 new_slave = wishbone.Interface(data_width=self.data_width)
266 self.submodules += wishbone.Converter(slave, new_slave)
267 slave = new_slave
268 self.slaves[name] = slave
269 self.logger.info("{} {} as Bus Slave.".format(
270 colorer(name, color="underline"),
271 colorer("added", color="green")))
272
273 # Str ------------------------------------------------------------------------------------------
274 def __str__(self):
275 r = "{}-bit {} Bus, {}GiB Address Space.\n".format(
276 colorer(self.data_width), colorer(self.standard), colorer(2**self.address_width/2**30))
277 r += "Bus Regions: ({})\n".format(len(self.regions.keys())) if len(self.regions.keys()) else ""
278 for name, region in self.regions.items():
279 r += colorer(name, color="underline") + " "*(20-len(name)) + ": " + str(region) + "\n"
280 r += "Bus Masters: ({})\n".format(len(self.masters.keys())) if len(self.masters.keys()) else ""
281 for name in self.masters.keys():
282 r += "- {}\n".format(colorer(name, color="underline"))
283 r += "Bus Slaves: ({})\n".format(len(self.slaves.keys())) if len(self.slaves.keys()) else ""
284 for name in self.slaves.keys():
285 r += "- {}\n".format(colorer(name, color="underline"))
286 r = r[:-1]
287 return r
288
289 # SoCLocHandler --------------------------------------------------------------------------------------
290
291 class SoCLocHandler(Module):
292 # Creation -------------------------------------------------------------------------------------
293 def __init__(self, name, n_locs):
294 self.name = name
295 self.locs = {}
296 self.n_locs = n_locs
297
298 # Add ------------------------------------------------------------------------------------------
299 def add(self, name, n=None, use_loc_if_exists=False):
300 allocated = False
301 if not (use_loc_if_exists and name in self.locs.keys()):
302 if name in self.locs.keys():
303 self.logger.error("{} {} name already used.".format(colorer(name, "red"), self.name))
304 self.logger.error(self)
305 raise
306 if n in self.locs.values():
307 self.logger.error("{} {} Location already used.".format(colorer(n, "red"), self.name))
308 self.logger.error(self)
309 raise
310 if n is None:
311 allocated = True
312 n = self.alloc(name)
313 else:
314 if n < 0:
315 self.logger.error("{} {} Location should be positive.".format(
316 colorer(n, color="red"),
317 self.name))
318 raise
319 if n > self.n_locs:
320 self.logger.error("{} {} Location too high (Up to {}).".format(
321 colorer(n, color="red"),
322 self.name,
323 colorer(self.n_csrs, color="green")))
324 raise
325 self.locs[name] = n
326 else:
327 n = self.locs[name]
328 self.logger.info("{} {} {} at Location {}.".format(
329 colorer(name, color="underline"),
330 self.name,
331 colorer("allocated" if allocated else "added", color="yellow" if allocated else "green"),
332 colorer(n)))
333
334 # Alloc ----------------------------------------------------------------------------------------
335 def alloc(self, name):
336 for n in range(self.n_locs):
337 if n not in self.locs.values():
338 return n
339 self.logger.error("Not enough Locations.")
340 self.logger.error(self)
341 raise
342
343 # Str ------------------------------------------------------------------------------------------
344 def __str__(self):
345 r = "{} Locations: ({})\n".format(self.name, len(self.locs.keys())) if len(self.locs.keys()) else ""
346 for name in self.locs.keys():
347 r += "- {}{}: {}\n".format(colorer(name, color="underline"), " "*(20-len(name)), colorer(self.locs[name]))
348 return r
349
350 # SoCCSRHandler ------------------------------------------------------------------------------------
351
352 class SoCCSRHandler(SoCLocHandler):
353 supported_data_width = [8, 32]
354 supported_address_width = [14, 15]
355 supported_alignment = [32, 64]
356 supported_paging = [0x800]
357
358 # Creation -------------------------------------------------------------------------------------
359 def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, reserved_csrs={}):
360 SoCLocHandler.__init__(self, "CSR", n_locs=4*2**address_width//paging) # FIXME
361 self.logger = logging.getLogger("SoCCSRHandler")
362 self.logger.info(colorer("Creating new CSR Handler...", color="cyan"))
363
364 # Check Data Width
365 if data_width not in self.supported_data_width:
366 self.logger.error("Unsupported data_width: {} supporteds: {:s}".format(
367 colorer(data_width, color="red"),
368 colorer(", ".join(str(x) for x in self.supported_data_width)), color="green"))
369 raise
370
371 # Check Address Width
372 if address_width not in self.supported_address_width:
373 self.logger.error("Unsupported address_width: {} supporteds: {:s}".format(
374 colorer(address_width, color="red"),
375 colorer(", ".join(str(x) for x in self.supported_address_width), color="green")))
376 raise
377
378 # Check Alignment
379 if alignment not in self.supported_alignment:
380 self.logger.error("Unsupported alignment: {} supporteds: {:s}".format(
381 colorer(alignment, color="red"),
382 colorer(", ".join(str(x) for x in self.supported_alignment), color="green")))
383 raise
384 if data_width > alignment:
385 self.logger.error("Alignment ({}) should be >= data_width ({})".format(
386 colorer(alignment, color="red"),
387 colorer(data_width, color="red")))
388 raise
389
390 # Check Paging
391 if paging not in self.supported_paging:
392 self.logger.error("Unsupported paging: {} supporteds: {:s}".format(
393 colorer(paging, color="red"),
394 colorer(", ".join(str(x) for x in self.supported_paging), color="green")))
395 raise
396
397 # Create CSR Handler
398 self.data_width = data_width
399 self.address_width = address_width
400 self.alignment = alignment
401 self.paging = paging
402 self.logger.info("{}-bit CSR Bus, {}KiB Address Space, {}B Paging (Up to {} Locations).\n".format(
403 colorer(self.data_width),
404 colorer(2**self.address_width/2**10),
405 colorer(self.paging),
406 colorer(self.n_locs)))
407
408 # Adding reserved CSRs
409 self.logger.info("Adding {} CSRs...".format(colorer("reserved")))
410 for name, n in reserved_csrs.items():
411 self.add(name, n)
412
413 self.logger.info(colorer("CSR Bus Handler created.", color="cyan"))
414
415 # Str ------------------------------------------------------------------------------------------
416 def __str__(self):
417 r = "{}-bit CSR Bus, {}KiB Address Space, {}B Paging (Up to {} Locations).\n".format(
418 colorer(self.data_width),
419 colorer(2**self.address_width/2**10),
420 colorer(self.paging),
421 colorer(self.n_locs))
422 r += SoCLocHandler.__str__(self)
423 r = r[:-1]
424 return r
425
426 # SoCIRQHandler ------------------------------------------------------------------------------------
427
428 class SoCIRQHandler(SoCLocHandler):
429 # Creation -------------------------------------------------------------------------------------
430 def __init__(self, n_irqs=32, reserved_irqs={}):
431 SoCLocHandler.__init__(self, "IRQ", n_locs=n_irqs)
432 self.logger = logging.getLogger("SoCIRQHandler")
433 self.logger.info(colorer("Creating new SoC IRQ Handler...", color="cyan"))
434
435 # Check IRQ Number
436 if n_irqs > 32:
437 self.logger.error("Unsupported IRQs number: {} supporteds: {:s}".format(
438 colorer(n, color="red"), colorer("Up to 32", color="green")))
439 raise
440
441 # Create IRQ Handler
442 self.logger.info("IRQ Handler (up to {} Locations).".format(colorer(n_irqs)))
443
444 # Adding reserved IRQs
445 self.logger.info("Adding {} IRQs...".format(colorer("reserved")))
446 for name, n in reserved_irqs.items():
447 self.add(name, n)
448
449 self.logger.info(colorer("IRQ Handler created.", color="cyan"))
450
451 # Str ------------------------------------------------------------------------------------------
452 def __str__(self):
453 r ="IRQ Handler (up to {} Locations).\n".format(colorer(self.n_locs))
454 r += SoCLocHandler.__str__(self)
455 r = r[:-1]
456 return r
457
458 # SoCController ------------------------------------------------------------------------------------
459
460 class SoCController(Module, AutoCSR):
461 def __init__(self):
462 self._reset = CSRStorage(1, description="""
463 Write a ``1`` to this register to reset the SoC.""")
464 self._scratch = CSRStorage(32, reset=0x12345678, description="""
465 Use this register as a scratch space to verify that software read/write accesses
466 to the Wishbone/CSR bus are working correctly. The initial reset value of 0x1234578
467 can be used to verify endianness.""")
468 self._bus_errors = CSRStatus(32, description="""
469 Total number of Wishbone bus errors (timeouts) since last reset.""")
470
471 # # #
472
473 # Reset
474 self.reset = Signal()
475 self.comb += self.reset.eq(self._reset.re)
476
477 # Bus errors
478 self.bus_error = Signal()
479 bus_errors = Signal(32)
480 self.sync += \
481 If(bus_errors != (2**len(bus_errors)-1),
482 If(self.bus_error, bus_errors.eq(bus_errors + 1))
483 )
484 self.comb += self._bus_errors.status.eq(bus_errors)
485
486 # SoC ----------------------------------------------------------------------------------------------
487
488 class SoC(Module):
489 def __init__(self,
490 bus_standard = "wishbone",
491 bus_data_width = 32,
492 bus_address_width = 32,
493 bus_timeout = 1e6,
494 bus_reserved_regions = {},
495
496 csr_data_width = 32,
497 csr_address_width = 14,
498 csr_alignment = 32,
499 csr_paging = 0x800,
500 csr_reserved_csrs = {},
501
502 irq_n_irqs = 32,
503 irq_reserved_irqs = {},
504 ):
505
506 self.logger = logging.getLogger("SoC")
507 self.logger.info(colorer(" __ _ __ _ __ ", color="bright"))
508 self.logger.info(colorer(" / / (_) /____ | |/_/ ", color="bright"))
509 self.logger.info(colorer(" / /__/ / __/ -_)> < ", color="bright"))
510 self.logger.info(colorer(" /____/_/\\__/\\__/_/|_| ", color="bright"))
511 self.logger.info(colorer(" Build your hardware, easily!", color="bright"))
512
513 self.logger.info(colorer("-"*80, color="bright"))
514 self.logger.info(colorer("Creating new SoC... ({})".format(build_time()), color="cyan"))
515 self.logger.info(colorer("-"*80, color="bright"))
516
517 # SoC Bus Handler --------------------------------------------------------------------------
518 self.submodules.bus = SoCBusHandler(
519 standard = bus_standard,
520 data_width = bus_data_width,
521 address_width = bus_address_width,
522 timeout = bus_timeout,
523 reserved_regions = bus_reserved_regions,
524 )
525
526 # SoC Bus Handler --------------------------------------------------------------------------
527 self.submodules.csr = SoCCSRHandler(
528 data_width = csr_data_width,
529 address_width = csr_address_width,
530 alignment = csr_alignment,
531 paging = csr_paging,
532 reserved_csrs = csr_reserved_csrs,
533 )
534
535 # SoC IRQ Handler --------------------------------------------------------------------------
536 self.submodules.irq = SoCIRQHandler(
537 n_irqs = irq_n_irqs,
538 reserved_irqs = irq_reserved_irqs
539 )
540
541 self.logger.info(colorer("-"*80, color="bright"))
542 self.logger.info(colorer("Initial SoC:", color="cyan"))
543 self.logger.info(colorer("-"*80, color="bright"))
544 self.logger.info(self.bus)
545 self.logger.info(self.csr)
546 self.logger.info(self.irq)
547 self.logger.info(colorer("-"*80, color="bright"))
548
549
550 # SoC Helpers ----------------------------------------------------------------------------------
551 def check_if_exists(self, name):
552 if hasattr(self, name):
553 self.logger.error("{} SubModule already declared.".format(colorer(name, "red")))
554 raise
555
556 # SoC Main components --------------------------------------------------------------------------
557 def add_ram(self, name, origin, size, contents=[], mode="rw"):
558 ram_bus = wishbone.Interface(data_width=self.bus.data_width)
559 ram = wishbone.SRAM(size, bus=ram_bus, init=contents, read_only=(mode == "r"))
560 self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
561 self.check_if_exists(name)
562 self.logger.info("RAM {} {} {}.".format(
563 colorer(name),
564 colorer("added", "green"),
565 self.bus.regions[name]))
566 setattr(self.submodules, name, ram)
567
568 def add_rom(self, name, origin, size, contents=[]):
569 self.add_ram(name, origin, size, contents, mode="r")
570
571 def add_controller(self, name="ctrl"):
572 self.check_if_exists(name)
573 setattr(self.submodules, name, SoCController())
574 self.csr.add(name, use_loc_if_exists=True)
575
576 def add_identifier(self, name="identifier", identifier="LiteX SoC", with_build_time=True):
577 self.check_if_exists(name)
578 if with_build_time:
579 identifier += " " + build_time()
580 setattr(self.submodules, name, Identifier(ident))
581 self.csr.add(name + "_mem", use_loc_if_exists=True)
582
583 def add_timer(self, name="timer0"):
584 self.check_if_exists(name)
585 setattr(self.submodules, name, Timer())
586 self.csr.add(name, use_loc_if_exists=True)
587 self.irq.add(name, use_loc_if_exists=True)
588
589 def add_csr_bridge(self, origin):
590 self.submodules.csr_bridge = wishbone2csr.WB2CSR(
591 bus_csr = csr_bus.Interface(
592 address_width = self.csr.address_width,
593 data_width = self.csr.data_width))
594 csr_size = 2**(self.csr.address_width + 2)
595 self.bus.add_slave("csr", self.csr_bridge.wishbone, SoCRegion(origin=origin, size=csr_size))
596
597 # SoC finalization -----------------------------------------------------------------------------
598 def do_finalize(self):
599 self.logger.info(colorer("-"*80, color="bright"))
600 self.logger.info(colorer("Finalized SoC:", color="cyan"))
601 self.logger.info(colorer("-"*80, color="bright"))
602 self.logger.info(self.bus)
603 self.logger.info(self.csr)
604 self.logger.info(self.irq)
605 self.logger.info(colorer("-"*80, color="bright"))
606
607 # SoC Bus Interconnect ---------------------------------------------------------------------
608 bus_masters = self.bus.masters.values()
609 bus_slaves = [(self.bus.regions[n].decoder(), s) for n, s in self.bus.slaves.items()]
610 if len(bus_masters) and len(bus_slaves):
611 self.submodules.bus_interconnect = wishbone.InterconnectShared(
612 masters = bus_masters,
613 slaves = bus_slaves,
614 register = True,
615 timeout_cycles = self.bus.timeout)
616
617 #exit()
618
619 # Test (FIXME: move to litex/text and improve) -----------------------------------------------------
620
621 if __name__ == "__main__":
622 bus = SoCBusHandler("wishbone", reserved_regions={
623 "rom": SoCRegion(origin=0x00000100, size=1024),
624 "ram": SoCRegion(size=512),
625 }
626 )
627 bus.add_master("cpu", None)
628 bus.add_slave("rom", None, SoCRegion(size=1024))
629 bus.add_slave("ram", None, SoCRegion(size=1024))
630
631
632 csr = SoCCSRHandler(reserved_csrs={"ctrl": 0, "uart": 1})
633 csr.add("csr0")
634 csr.add("csr1", 0)
635 #csr.add("csr2", 46)
636 csr.add("csr3", -1)
637 print(bus)
638 print(csr)
639
640 irq = SoCIRQHandler(reserved_irqs={"uart": 1})
641
642 soc = SoC()