Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 1 | # 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 Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 7 | from typing import Dict, List, Optional, Tuple, Union |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 8 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 9 | from .ip_block import IpBlock |
Philipp Wagner | 78194c8 | 2021-03-10 10:08:17 +0000 | [diff] [blame] | 10 | from .params import ReggenParams |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 11 | from .reg_block import RegBlock |
| 12 | from .window import Window |
| 13 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 14 | _IFName = Tuple[str, Optional[str]] |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 15 | _Triple = Tuple[int, str, IpBlock] |
| 16 | |
| 17 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 18 | class 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 28 | def __init__(self, |
| 29 | regwidth: int, |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 30 | blocks: Dict[str, IpBlock], |
| 31 | instances: Dict[str, str], |
| 32 | if_addrs: Dict[Tuple[str, Optional[str]], int], |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 33 | windows: List[Window]): |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 34 | '''Class initializer. |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 35 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 36 | 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 55 | self.regwidth = regwidth |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 56 | self.blocks = blocks |
| 57 | self.instances = instances |
| 58 | self.if_addrs = if_addrs |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 59 | |
Philipp Wagner | 78194c8 | 2021-03-10 10:08:17 +0000 | [diff] [blame] | 60 | self.window_block = RegBlock(regwidth, ReggenParams()) |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 61 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 62 | # 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 68 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 69 | inst_name, if_name = full_if_name |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 70 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 71 | # 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 76 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 77 | # 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 81 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 82 | for window in sorted(windows, key=lambda w: w.offset): |
| 83 | merged.append((window.offset, window)) |
| 84 | self.window_block.add_window(window) |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 85 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 86 | # 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 95 | offset = 0 |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 96 | 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 99 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 100 | if isinstance(item, Window): |
| 101 | addrsep = (regwidth + 7) // 8 |
| 102 | offset = item.next_offset(addrsep) |
| 103 | continue |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 104 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 105 | inst_name, if_name = item |
| 106 | block_name = instances[inst_name] |
| 107 | block = blocks[block_name] |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 108 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 109 | lst = self.block_instances.setdefault(block_name, []) |
| 110 | if inst_name not in lst: |
| 111 | lst.append(inst_name) |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 112 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 113 | # 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 Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 117 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 118 | offset = base_addr + reg_block.offset |