blob: 253013bbe35bd578c1d1a360819b5b0c58f247ba [file] [log] [blame]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +00001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4
5'''Code representing the entire chip for reggen'''
6
Rupert Swarbrick200d8b42021-03-08 12:32:11 +00007from typing import Dict, List, Optional, Tuple, Union
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +00008
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +00009from .ip_block import IpBlock
Philipp Wagner78194c82021-03-10 10:08:17 +000010from .params import ReggenParams
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000011from .reg_block import RegBlock
12from .window import Window
13
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000014_IFName = Tuple[str, Optional[str]]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000015_Triple = Tuple[int, str, IpBlock]
16
17
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000018class Top:
19 '''An object representing the entire chip, as seen by reggen.
20
21 This contains instances of some blocks (possibly multiple instances of each
22 block), starting at well-defined base addresses. It may also contain some
23 windows. These are memories that don't have their own comportable IP (so
24 aren't defined in a block), but still take up address space.
25
26 '''
27
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000028 def __init__(self,
29 regwidth: int,
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000030 blocks: Dict[str, IpBlock],
31 instances: Dict[str, str],
32 if_addrs: Dict[Tuple[str, Optional[str]], int],
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000033 windows: List[Window]):
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000034 '''Class initializer.
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000035
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000036 regwidth is the width of the registers (which must match for all the
37 blocks) in bits.
38
39 blocks is a map from block name to IpBlock object.
40
41 instances is a map from instance name to the name of the block it
42 instantiates. Every block name that appears in instances must be a key
43 of blocks.
44
45 if_addrs is a dictionary that maps the name of a device interface on
46 some instance of some block to its base address. A key of the form (n,
47 i) means "the device interface called i on an instance called n". If i
48 is None, this is an unnamed device interface. Every instance name (n)
49 that appears in connections must be a key of instances.
50
51 windows is a list of windows (these contain base addresses already).
52
53 '''
54
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000055 self.regwidth = regwidth
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000056 self.blocks = blocks
57 self.instances = instances
58 self.if_addrs = if_addrs
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000059
Philipp Wagner78194c82021-03-10 10:08:17 +000060 self.window_block = RegBlock(regwidth, ReggenParams())
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000061
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000062 # Generate one list of base addresses and objects (with each object
63 # either a block name and interface name or a window). While we're at
64 # it, construct inst_to_block_name and if_addrs.
65 merged = [] # type: List[Tuple[int, Union[_IFName, Window]]]
66 for full_if_name, addr in if_addrs.items():
67 merged.append((addr, full_if_name))
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000068
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000069 inst_name, if_name = full_if_name
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000070
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000071 # The instance name must match some key in instances, whose value
72 # should in turn match some key in blocks.
73 assert inst_name in instances
74 block_name = instances[inst_name]
75 assert block_name in blocks
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000076
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000077 # Check that if_name is indeed the name of a device interface for
78 # that block.
79 block = blocks[block_name]
80 assert block.bus_interfaces.has_interface(False, if_name)
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000081
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000082 for window in sorted(windows, key=lambda w: w.offset):
83 merged.append((window.offset, window))
84 self.window_block.add_window(window)
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000085
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000086 # A map from block name to the list of its instances. These instances
87 # are listed in increasing order of the lowest base address of one of
88 # their interfaces. The entries are added into the dict in the same
89 # order, so an iteration over items() will give blocks ordered by their
90 # first occurrence in the address map.
91 self.block_instances = {} # type: Dict[str, List[str]]
92
93 # Walk the merged list in order of increasing base address. Check for
94 # overlaps and construct block_instances.
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000095 offset = 0
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000096 for base_addr, item in sorted(merged, key=lambda pr: pr[0]):
97 # Make sure that this item doesn't overlap with the previous one
98 assert offset <= base_addr, item
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000099
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000100 if isinstance(item, Window):
101 addrsep = (regwidth + 7) // 8
102 offset = item.next_offset(addrsep)
103 continue
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000104
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000105 inst_name, if_name = item
106 block_name = instances[inst_name]
107 block = blocks[block_name]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000108
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000109 lst = self.block_instances.setdefault(block_name, [])
110 if inst_name not in lst:
111 lst.append(inst_name)
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000112
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000113 # This should be guaranteed by the fact that we've already checked
114 # the existence of a device interface.
115 assert if_name in block.reg_blocks
116 reg_block = block.reg_blocks[if_name]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000117
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000118 offset = base_addr + reg_block.offset