lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [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 |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 4 | import re |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 5 | import logging as log |
Eunchan Kim | 6a4b49e | 2020-02-18 10:33:39 -0800 | [diff] [blame] | 6 | from collections import OrderedDict |
Weicai Yang | 53b0d4d | 2020-11-30 15:28:33 -0800 | [diff] [blame] | 7 | from enum import Enum |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 8 | from typing import Dict, List |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 9 | |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 10 | from reggen.validate import check_keys |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 11 | from reggen.ip_block import IpBlock |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 12 | |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 13 | # For the reference |
| 14 | # val_types = { |
| 15 | # 'd': ["int", "integer (binary 0b, octal 0o, decimal, hex 0x)"], |
| 16 | # 'x': ["xint", "x for undefined otherwise int"], |
| 17 | # 'b': [ |
| 18 | # "bitrange", "bit number as decimal integer, \ |
| 19 | # or bit-range as decimal integers msb:lsb" |
| 20 | # ], |
| 21 | # 'l': ["list", "comma separated list enclosed in `[]`"], |
| 22 | # 'ln': ["name list", 'comma separated list enclosed in `[]` of '\ |
| 23 | # 'one or more groups that have just name and dscr keys.'\ |
| 24 | # ' e.g. `{ name: "name", desc: "description"}`'], |
| 25 | # 'lnw': ["name list+", 'name list that optionally contains a width'], |
| 26 | # 'lp': ["parameter list", 'parameter list having default value optionally'], |
| 27 | # 'g': ["group", "comma separated group of key:value enclosed in `{}`"], |
| 28 | # 's': ["string", "string, typically short"], |
| 29 | # 't': ["text", "string, may be multi-line enclosed in `'''` "\ |
| 30 | # "may use `**bold**`, `*italic*` or `!!Reg` markup"], |
| 31 | # 'T': ["tuple", "tuple enclosed in ()"], |
Philipp Wagner | 14a3fee | 2019-11-21 10:07:02 +0000 | [diff] [blame] | 32 | # 'pi': ["python int", "Native Python type int (generated)"], |
| 33 | # 'pb': ["python Bool", "Native Python type Bool (generated)"], |
| 34 | # 'pl': ["python list", "Native Python type list (generated)"], |
| 35 | # 'pe': ["python enum", "Native Python type enum (generated)"] |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 36 | # } |
| 37 | |
| 38 | # Required/optional field in top hjson |
| 39 | top_required = { |
| 40 | 'name': ['s', 'Top name'], |
| 41 | 'type': ['s', 'type of hjson. Shall be "top" always'], |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 42 | 'clocks': ['g', 'group of clock properties'], |
| 43 | 'resets': ['l', 'list of resets'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 44 | 'module': ['l', 'list of modules to instantiate'], |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 45 | 'memory': ['l', 'list of memories. At least one memory ' |
| 46 | 'is needed to run the software'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 47 | 'xbar': ['l', 'List of the xbar used in the top'], |
Michael Schaffner | 7b0807d | 2020-10-27 19:54:52 -0700 | [diff] [blame] | 48 | 'rnd_cnst_seed': ['int', "Seed for random netlist constant computation"], |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 49 | 'pinout': ['g', 'Pinout configuration'], |
| 50 | 'targets': ['l', ' Target configurations'], |
| 51 | 'pinmux': ['g', 'pinmux configuration'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | top_optional = { |
Michael Schaffner | 666dde1 | 2019-10-25 11:57:54 -0700 | [diff] [blame] | 55 | 'alert_async': ['l', 'async alerts (generated)'], |
Rupert Swarbrick | ddf0145 | 2021-02-02 09:28:01 +0000 | [diff] [blame] | 56 | 'alert': ['lnw', 'alerts (generated)'], |
| 57 | 'alert_module': [ |
| 58 | 'l', |
| 59 | 'list of the modules that connects to alert_handler' |
| 60 | ], |
Eunchan Kim | 1cf66af | 2020-04-30 11:31:53 -0700 | [diff] [blame] | 61 | 'datawidth': ['pn', "default data width"], |
Rupert Swarbrick | 26e304f | 2021-02-02 09:31:41 +0000 | [diff] [blame] | 62 | 'exported_clks': ['g', 'clock signal routing rules'], |
| 63 | 'host': ['g', 'list of host-only components in the system'], |
Rupert Swarbrick | ddf0145 | 2021-02-02 09:28:01 +0000 | [diff] [blame] | 64 | 'inter_module': ['g', 'define the signal connections between the modules'], |
| 65 | 'interrupt': ['lnw', 'interrupts (generated)'], |
| 66 | 'interrupt_module': ['l', 'list of the modules that connects to rv_plic'], |
| 67 | 'num_cores': ['pn', "number of computing units"], |
Rupert Swarbrick | 26e304f | 2021-02-02 09:31:41 +0000 | [diff] [blame] | 68 | 'power': ['g', 'power domains supported by the design'], |
Rupert Swarbrick | ef8cdad | 2021-02-18 14:41:38 +0000 | [diff] [blame] | 69 | 'port': ['g', 'assign special attributes to specific ports'] |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | top_added = {} |
| 73 | |
| 74 | pinmux_required = {} |
| 75 | pinmux_optional = { |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 76 | 'num_wkup_detect': [ |
| 77 | 'd', 'Number of wakeup detectors' |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 78 | ], |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 79 | 'wkup_cnt_width': [ |
| 80 | 'd', 'Number of bits in wakeup detector counters' |
| 81 | ], |
| 82 | 'signals': ['l', 'List of Dedicated IOs.'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 83 | } |
| 84 | pinmux_added = { |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 85 | 'ios': ['l', 'Full list of IO'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 86 | } |
| 87 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 88 | pinmux_sig_required = { |
| 89 | 'instance': ['s', 'Module instance name'], |
| 90 | 'connection': ['s', 'Specification of connection type, ' |
| 91 | 'can be direct, manual or muxed'], |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 92 | } |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 93 | pinmux_sig_optional = { |
| 94 | 'port': ['s', 'Port name of module'], |
| 95 | 'pad': ['s', 'Pad name for direct connections'], |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 96 | 'desc': ['s', 'Signal description'], |
| 97 | 'attr': ['s', 'Pad type for generating the correct attribute CSR'] |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 98 | } |
| 99 | pinmux_sig_added = {} |
| 100 | |
| 101 | pinout_required = { |
| 102 | 'banks': ['l', 'List of IO power banks'], |
| 103 | 'pads': ['l', 'List of pads'] |
| 104 | } |
| 105 | pinout_optional = { |
| 106 | } |
| 107 | pinout_added = {} |
| 108 | |
| 109 | pad_required = { |
| 110 | 'name': ['l', 'Pad name'], |
| 111 | 'type': ['s', 'Pad type'], |
| 112 | 'bank': ['s', 'IO power bank for the pad'], |
| 113 | 'connection': ['s', 'Specification of connection type, ' |
| 114 | 'can be direct, manual or muxed'], |
| 115 | } |
| 116 | pad_optional = { |
| 117 | 'desc': ['s', 'Pad description'], |
| 118 | } |
| 119 | pad_added = {} |
| 120 | |
| 121 | target_required = { |
| 122 | 'name': ['s', 'Name of target'], |
| 123 | 'pinout': ['g', 'Target-specific pinout configuration'], |
| 124 | 'pinmux': ['g', 'Target-specific pinmux configuration'] |
| 125 | } |
| 126 | target_optional = { |
| 127 | } |
| 128 | target_added = {} |
| 129 | |
| 130 | target_pinmux_required = { |
| 131 | 'special_signals': ['l', 'List of special signals and the pad they are mapped to.'], |
| 132 | } |
| 133 | target_pinmux_optional = {} |
| 134 | target_pinmux_added = {} |
| 135 | |
| 136 | target_pinout_required = { |
| 137 | 'remove_pads': ['l', 'List of pad names to remove and stub out'], |
| 138 | 'add_pads': ['l', 'List of manual pads to add'], |
| 139 | } |
| 140 | target_pinout_optional = {} |
| 141 | target_pinout_added = {} |
| 142 | |
| 143 | straps_required = { |
| 144 | 'tap0': ['s', 'Name of tap0 pad'], |
| 145 | 'tap1': ['s', 'Name of tap1 pad'], |
| 146 | 'dft0': ['s', 'Name of dft0 pad'], |
| 147 | 'dft1': ['s', 'Name of dft1 pad'], |
| 148 | } |
| 149 | straps_optional = {} |
| 150 | straps_added = {} |
| 151 | |
| 152 | straps_required = { |
| 153 | 'tap0': ['s', 'Name of tap0 pad'], |
| 154 | 'tap1': ['s', 'Name of tap1 pad'], |
| 155 | 'dft0': ['s', 'Name of dft0 pad'], |
| 156 | 'dft1': ['s', 'Name of dft1 pad'], |
| 157 | } |
| 158 | straps_optional = {} |
| 159 | straps_added = {} |
| 160 | |
| 161 | special_sig_required = { |
| 162 | 'name': ['s', 'DIO name'], |
| 163 | 'pad': ['s', 'Pad name'], |
| 164 | } |
| 165 | special_sig_optional = { |
| 166 | 'desc': ['s', 'Description of signal connection'], |
| 167 | } |
| 168 | special_sig_added = {} |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 169 | |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 170 | eflash_required = { |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 171 | 'type': ['s', 'string indicating type of memory'], |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 172 | 'banks': ['d', 'number of flash banks'], |
Rupert Swarbrick | 9a5b4e2 | 2021-02-02 09:38:09 +0000 | [diff] [blame] | 173 | 'pages_per_bank': ['d', 'number of data pages per flash bank'], |
| 174 | 'program_resolution': ['d', 'maximum number of flash words allowed to program'], |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 175 | } |
| 176 | |
| 177 | eflash_optional = {} |
| 178 | |
| 179 | eflash_added = {} |
| 180 | |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 181 | module_required = { |
| 182 | 'name': ['s', 'name of the instance'], |
| 183 | 'type': ['s', 'comportable IP type'], |
| 184 | 'clock_srcs': ['g', 'dict with clock sources'], |
| 185 | 'clock_group': ['s', 'clock group'], |
| 186 | 'reset_connections': ['g', 'dict with reset sources'], |
| 187 | } |
| 188 | |
| 189 | module_optional = { |
| 190 | 'domain': ['s', 'power domain, defaults to Domain0'], |
| 191 | 'clock_reset_export': ['l', 'optional list with prefixes for exported ' |
| 192 | 'clocks and resets at the chip level'], |
| 193 | 'attr': ['s', 'optional attribute indicating whether the IP is ' |
| 194 | '"templated" or "reggen_only"'], |
| 195 | 'base_addr': ['s', 'hex start address of the peripheral ' |
| 196 | '(if the IP has only a single TL-UL interface)'], |
| 197 | 'base_addrs': ['d', 'hex start addresses of the peripheral ' |
| 198 | ' (if the IP has multiple TL-UL interfaces)'], |
| 199 | 'memory': ['g', 'optional dict with memory region attributes'], |
| 200 | 'param_decl': ['g', 'optional dict that allows to override instantiation parameters'] |
| 201 | } |
| 202 | |
| 203 | module_added = { |
| 204 | 'clock_connections': ['g', 'generated clock connections'] |
| 205 | } |
| 206 | |
| 207 | memory_required = { |
| 208 | 'label': ['s', 'region label for the linker script'], |
Michael Schaffner | 0bedfa6 | 2021-07-27 15:54:15 -0700 | [diff] [blame] | 209 | 'swaccess': ['s', 'access attributes for the memory region (ro, rw)'], |
| 210 | 'exec': ['pb', 'executable region indication for the linker script'], |
| 211 | 'byte_write': ['pb', 'indicate whether the memory supports byte write accesses'], |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | memory_optional = { |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 215 | 'size': ['d', 'memory region size in bytes for the linker script, ' |
| 216 | 'xbar and RTL parameterisations'], |
| 217 | 'config': ['d', 'Extra configuration for a particular memory'], |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | memory_added = { |
| 221 | } |
| 222 | |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 223 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 224 | # Supported PAD types. |
| 225 | # Needs to coincide with enum definition in prim_pad_wrapper_pkg.sv |
| 226 | class PadType(Enum): |
| 227 | INPUT_STD = 'InputStd' |
| 228 | BIDIR_STD = 'BidirStd' |
| 229 | BIDIR_TOL = 'BidirTol' |
| 230 | BIDIR_OD = 'BidirOd' |
Michael Schaffner | 6c5f7a7 | 2021-04-09 11:51:10 -0700 | [diff] [blame] | 231 | ANALOG_IN0 = 'AnalogIn0' |
Arnon Sharlin | e48c001 | 2021-05-09 13:26:38 +0300 | [diff] [blame] | 232 | ANALOG_IN1 = 'AnalogIn1' |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 233 | |
| 234 | |
| 235 | def is_valid_pad_type(obj): |
| 236 | try: |
| 237 | PadType(obj) |
| 238 | except ValueError: |
| 239 | return False |
| 240 | return True |
| 241 | |
| 242 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 243 | class TargetType(Enum): |
| 244 | MODULE = "module" |
| 245 | XBAR = "xbar" |
| 246 | |
| 247 | |
| 248 | class Target: |
| 249 | """Target class informs the checkers if we are validating a module or xbar |
| 250 | """ |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 251 | def __init__(self, target_type): |
Weicai Yang | 88ced02 | 2020-11-30 15:34:56 -0800 | [diff] [blame] | 252 | # The type of this target |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 253 | self.target_type = target_type |
Weicai Yang | 88ced02 | 2020-11-30 15:34:56 -0800 | [diff] [blame] | 254 | # The key to search against |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 255 | if target_type == TargetType.MODULE: |
| 256 | self.key = "type" |
| 257 | else: |
| 258 | self.key = "name" |
| 259 | |
| 260 | |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 261 | class Flash: |
| 262 | """Flash class contains information regarding parameter defaults. |
| 263 | For now, only expose banks / pages_per_bank for user configuration. |
| 264 | For now, also enforce power of 2 requiremnt. |
| 265 | """ |
| 266 | max_banks = 4 |
| 267 | max_pages_per_bank = 1024 |
| 268 | |
Timothy Chen | 2479883 | 2021-08-20 16:12:12 -0700 | [diff] [blame^] | 269 | def __init__(self, mem, base_addr=0): |
| 270 | self.base_addr = int(base_addr, 16) |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 271 | self.banks = mem.get('banks', 2) |
| 272 | self.pages_per_bank = mem.get('pages_per_bank', 8) |
| 273 | self.program_resolution = mem.get('program_resolution', 128) |
Timothy Chen | e97e0b8 | 2020-12-11 17:18:43 -0800 | [diff] [blame] | 274 | self.words_per_page = 256 |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 275 | self.data_width = 64 |
| 276 | self.metadata_width = 12 |
Timothy Chen | e97e0b8 | 2020-12-11 17:18:43 -0800 | [diff] [blame] | 277 | self.info_types = 3 |
| 278 | self.infos_per_bank = [10, 1, 2] |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 279 | self.word_bytes = int(self.data_width / 8) |
| 280 | self.pgm_resolution_bytes = int(self.program_resolution * self.word_bytes) |
| 281 | self.check_values() |
| 282 | |
| 283 | # populate size variable |
| 284 | self.bytes_per_page = self.word_bytes * self.words_per_page |
| 285 | self.bytes_per_bank = self.bytes_per_page * self.pages_per_bank |
| 286 | self.total_bytes = self.bytes_per_bank * self.banks |
Timothy Chen | 2479883 | 2021-08-20 16:12:12 -0700 | [diff] [blame^] | 287 | |
| 288 | size_int = int(self.total_bytes) |
| 289 | self.size = hex(size_int) |
| 290 | self.end_addr = self.base_addr + size_int |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 291 | |
| 292 | def is_pow2(self, n): |
| 293 | return (n != 0) and (n & (n - 1) == 0) |
| 294 | |
| 295 | def check_values(self): |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 296 | pow2_check = (self.is_pow2(self.banks) and |
| 297 | self.is_pow2(self.pages_per_bank) and |
| 298 | self.is_pow2(self.program_resolution)) |
| 299 | limit_check = ((self.banks <= Flash.max_banks) and |
| 300 | (self.pages_per_bank <= Flash.max_pages_per_bank)) |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 301 | |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 302 | if not pow2_check: |
| 303 | raise ValueError(f'flash power of 2 check failed. A supplied parameter ' |
| 304 | 'is not power of 2') |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 305 | |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 306 | if not limit_check: |
| 307 | raise ValueError(f'flash number of banks and pages per bank too large') |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 308 | |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 309 | def _asdict(self): |
| 310 | return { |
| 311 | 'banks': self.banks, |
| 312 | 'pages_per_bank': self.pages_per_bank, |
| 313 | 'program_resolution': self.pgm_resolution_bytes, |
| 314 | 'bytes_per_page': self.bytes_per_page, |
| 315 | 'bytes_per_bank': self.bytes_per_bank, |
| 316 | 'size': self.size |
| 317 | } |
Timothy Chen | 9b113e5 | 2020-11-06 18:48:05 -0800 | [diff] [blame] | 318 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 319 | # Check to see if each module/xbar defined in top.hjson exists as ip/xbar.hjson |
| 320 | # Also check to make sure there are not multiple definitions of ip/xbar.hjson for each |
| 321 | # top level definition |
| 322 | # If it does, return a dictionary of instance names to index in ip/xbarobjs |
| 323 | def check_target(top, objs, tgtobj): |
| 324 | error = 0 |
Eunchan Kim | 6a4b49e | 2020-02-18 10:33:39 -0800 | [diff] [blame] | 325 | idxs = OrderedDict() |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 326 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 327 | # Collect up counts of object names. We support entries of objs that are |
| 328 | # either dicts (for top-levels) or IpBlock objects. |
| 329 | name_indices = {} |
| 330 | for idx, obj in enumerate(objs): |
| 331 | if isinstance(obj, IpBlock): |
| 332 | name = obj.name.lower() |
| 333 | else: |
| 334 | name = obj['name'].lower() |
| 335 | |
| 336 | log.info("%d Order is %s" % (idx, name)) |
| 337 | name_indices.setdefault(name, []).append(idx) |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 338 | |
| 339 | tgt_type = tgtobj.target_type.value |
| 340 | inst_key = tgtobj.key |
| 341 | |
| 342 | for cfg in top[tgt_type]: |
| 343 | cfg_name = cfg['name'].lower() |
| 344 | log.info("Checking target %s %s" % (tgt_type, cfg_name)) |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 345 | |
| 346 | indices = name_indices.get(cfg[inst_key], []) |
| 347 | if not indices: |
| 348 | log.error("Could not find %s.hjson" % cfg_name) |
| 349 | error += 1 |
| 350 | elif len(indices) > 1: |
| 351 | log.error("Duplicate %s.hjson" % cfg_name) |
| 352 | error += 1 |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 353 | else: |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 354 | idxs[cfg_name] = indices[0] |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 355 | |
| 356 | log.info("Current state %s" % idxs) |
| 357 | return error, idxs |
| 358 | |
| 359 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 360 | def check_pad(top: Dict, |
| 361 | pad: Dict, |
| 362 | known_pad_names: Dict, |
| 363 | valid_connections: List[str], |
| 364 | prefix: str) -> int: |
| 365 | error = 0 |
| 366 | error += check_keys(pad, pad_required, pad_optional, |
| 367 | pad_added, prefix) |
| 368 | |
| 369 | # check name uniqueness |
| 370 | if pad['name'] in known_pad_names: |
| 371 | log.warning('Pad name {} is not unique'.format(pad['name'])) |
| 372 | error += 1 |
| 373 | known_pad_names[pad['name']] = 1 |
| 374 | |
| 375 | if not is_valid_pad_type(pad['type']): |
| 376 | log.warning('Unkown pad type {}'.format(pad['type'])) |
| 377 | error += 1 |
| 378 | |
| 379 | if pad['bank'] not in top['pinout']['banks']: |
| 380 | log.warning('Unkown io power bank {}'.format(pad['bank'])) |
| 381 | error += 1 |
| 382 | |
| 383 | if pad['connection'] not in valid_connections: |
| 384 | log.warning('Connection type {} of pad {} is invalid' |
| 385 | .format(pad['connection'], pad['name'])) |
| 386 | error += 1 |
| 387 | |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 388 | return error |
| 389 | |
| 390 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 391 | def check_pinout(top: Dict, prefix: str) -> int: |
| 392 | error = check_keys(top['pinout'], pinout_required, pinout_optional, |
| 393 | pinout_added, prefix + ' Pinout') |
| 394 | |
| 395 | known_names = {} |
| 396 | for pad in top['pinout']['pads']: |
| 397 | error += check_keys(pad, pad_required, pad_optional, |
| 398 | pad_added, prefix + ' Pinout') |
| 399 | |
| 400 | error += check_pad(top, pad, known_names, |
| 401 | ['direct', 'manual', 'muxed'], |
| 402 | prefix + ' Pad') |
| 403 | |
| 404 | return error |
| 405 | |
| 406 | |
| 407 | def check_pinmux(top: Dict, prefix: str) -> int: |
| 408 | error = check_keys(top['pinmux'], pinmux_required, pinmux_optional, |
| 409 | pinmux_added, prefix + ' Pinmux') |
| 410 | |
| 411 | # This is used for the direct connection accounting below, |
| 412 | # where we tick off already connected direct pads. |
| 413 | known_direct_pads = {} |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 414 | direct_pad_attr = {} |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 415 | for pad in top['pinout']['pads']: |
| 416 | if pad['connection'] == 'direct': |
| 417 | known_direct_pads[pad['name']] = 1 |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 418 | direct_pad_attr[pad['name']] = pad['type'] |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 419 | |
| 420 | # Note: the actual signal crosscheck is deferred until the merge stage, |
| 421 | # since we have no idea at this point which IOs comportable IPs expose. |
| 422 | for sig in top['pinmux']['signals']: |
| 423 | error += check_keys(sig, pinmux_sig_required, pinmux_sig_optional, |
| 424 | pinmux_sig_added, prefix + ' Pinmux signal') |
| 425 | |
| 426 | if sig['connection'] not in ['direct', 'manual', 'muxed']: |
| 427 | log.warning('Invalid connection type {}'.format(sig['connection'])) |
| 428 | error += 1 |
| 429 | |
| 430 | # The pad needs to refer to a valid pad name in the pinout that is of |
| 431 | # connection type "direct". We tick off all direct pads that have been |
| 432 | # referenced in order to make sure there are no double connections |
| 433 | # and unconnected direct pads. |
| 434 | padname = sig.setdefault('pad', '') |
| 435 | if padname != '': |
| 436 | if padname in known_direct_pads: |
| 437 | if known_direct_pads[padname] == 1: |
| 438 | known_direct_pads[padname] = 0 |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 439 | padattr = direct_pad_attr[padname] |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 440 | else: |
| 441 | log.warning('Warning, direct pad {} is already connected' |
| 442 | .format(padname)) |
| 443 | error += 1 |
| 444 | else: |
| 445 | log.warning('Unknown direct pad {}'.format(padname)) |
| 446 | error += 1 |
| 447 | |
| 448 | # Check port naming scheme. |
| 449 | port = sig.setdefault('port', '') |
| 450 | pattern = r'^[a-zA-Z0-9_]*(\[[0-9]*\]){0,1}' |
| 451 | matches = re.match(pattern, port) |
| 452 | if matches is None: |
| 453 | log.warning('Port name {} has wrong format' |
| 454 | .format(port)) |
| 455 | error += 1 |
| 456 | |
| 457 | # Check that only direct connections have pad keys |
| 458 | if sig['connection'] == 'direct': |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 459 | if sig.setdefault('attr', '') != '': |
| 460 | log.warning('Direct connection of instance {} port {} ' |
| 461 | 'must not have an associated pad attribute field' |
| 462 | .format(sig['instance'], |
| 463 | sig['port'])) |
| 464 | error += 1 |
| 465 | # Since the signal is directly connected, we can automatically infer |
| 466 | # the pad type needed to instantiate the correct attribute CSR WARL |
| 467 | # module inside the pinmux. |
| 468 | sig['attr'] = padattr |
| 469 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 470 | if padname == '': |
| 471 | log.warning('Instance {} port {} connection is of direct type ' |
| 472 | 'and therefore must have an associated pad name.' |
| 473 | .format(sig['instance'], |
| 474 | sig['port'])) |
| 475 | error += 1 |
| 476 | if port == '': |
| 477 | log.warning('Instance {} port {} connection is of direct type ' |
| 478 | 'and therefore must have an associated port name.' |
| 479 | .format(sig['instance'], |
| 480 | sig['port'])) |
| 481 | error += 1 |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 482 | elif sig['connection'] == 'muxed': |
| 483 | # Muxed signals do not have a corresponding pad and attribute CSR, |
| 484 | # since they first go through the pinmux matrix. |
| 485 | if sig.setdefault('attr', '') != '': |
| 486 | log.warning('Muxed connection of instance {} port {} ' |
| 487 | 'must not have an associated pad attribute field' |
| 488 | .format(sig['instance'], |
| 489 | sig['port'])) |
| 490 | error += 1 |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 491 | if padname != '': |
Michael Schaffner | c7dc533 | 2021-04-09 16:30:26 -0700 | [diff] [blame] | 492 | log.warning('Muxed connection of instance {} port {} ' |
| 493 | 'must not have an associated pad' |
| 494 | .format(sig['instance'], |
| 495 | sig['port'])) |
| 496 | error += 1 |
| 497 | elif sig['connection'] == 'manual': |
| 498 | # This pad attr key is only allowed in the manual case, |
| 499 | # as there is no way to infer the pad type automatically. |
| 500 | sig.setdefault('attr', 'BidirStd') |
| 501 | if padname != '': |
| 502 | log.warning('Manual connection of instance {} port {} ' |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 503 | 'must not have an associated pad' |
| 504 | .format(sig['instance'], |
| 505 | sig['port'])) |
| 506 | error += 1 |
| 507 | |
| 508 | # At this point, all direct pads should have been ticked off. |
| 509 | for key, val in known_direct_pads.items(): |
| 510 | if val == 1: |
| 511 | log.warning('Direct pad {} has not been connected' |
| 512 | .format(key)) |
| 513 | error += 1 |
| 514 | |
| 515 | return error |
| 516 | |
| 517 | |
| 518 | def check_implementation_targets(top: Dict, prefix: str) -> int: |
| 519 | error = 0 |
| 520 | known_names = {} |
| 521 | for target in top['targets']: |
| 522 | error += check_keys(target, target_required, target_optional, |
| 523 | target_added, prefix + ' Targets') |
| 524 | |
| 525 | # check name uniqueness |
| 526 | if target['name'] in known_names: |
| 527 | log.warning('Target name {} is not unique'.format(target['name'])) |
| 528 | error += 1 |
| 529 | known_names[target['name']] = 1 |
| 530 | |
| 531 | error += check_keys(target['pinmux'], target_pinmux_required, target_pinmux_optional, |
| 532 | target_pinmux_added, prefix + ' Target pinmux') |
| 533 | |
| 534 | error += check_keys(target['pinout'], target_pinout_required, target_pinout_optional, |
| 535 | target_pinout_added, prefix + ' Target pinout') |
| 536 | |
| 537 | # Check special pad signals |
| 538 | known_entry_names = {} |
| 539 | for entry in target['pinmux']['special_signals']: |
| 540 | error += check_keys(entry, special_sig_required, special_sig_optional, |
| 541 | special_sig_added, prefix + ' Special signal') |
| 542 | |
| 543 | # check name uniqueness |
| 544 | if entry['name'] in known_entry_names: |
| 545 | log.warning('Special pad name {} is not unique'.format(entry['name'])) |
| 546 | error += 1 |
| 547 | known_entry_names[entry['name']] = 1 |
| 548 | |
| 549 | # The pad key needs to refer to a valid pad name. |
| 550 | is_muxed = False |
| 551 | for pad in top['pinout']['pads']: |
| 552 | if entry['pad'] == pad['name']: |
| 553 | is_muxed = pad['connection'] == 'muxed' |
| 554 | break |
| 555 | else: |
| 556 | log.warning('Unknown pad {}'.format(entry['pad'])) |
| 557 | error += 1 |
| 558 | |
| 559 | if not is_muxed: |
| 560 | # If this is not a muxed pad, we need to make sure this refers to |
| 561 | # DIO that is NOT a manual pad. |
| 562 | for sig in top['pinmux']['signals']: |
| 563 | if entry['pad'] == sig['pad']: |
| 564 | break |
| 565 | else: |
| 566 | log.warning('Special pad {} cannot refer to a manual pad'.format(entry['pad'])) |
| 567 | error += 1 |
| 568 | |
| 569 | # Check pads to remove and stub out |
| 570 | for entry in target['pinout']['remove_pads']: |
| 571 | # The pad key needs to refer to a valid pad name. |
| 572 | for pad in top['pinout']['pads']: |
| 573 | if entry == pad['name']: |
| 574 | break |
| 575 | else: |
| 576 | log.warning('Unknown pad {}'.format(entry)) |
| 577 | error += 1 |
| 578 | |
| 579 | # Check pads to add |
| 580 | known_pad_names = {} |
| 581 | for pad in top['pinout']['pads']: |
| 582 | known_pad_names.update({pad['name']: 1}) |
| 583 | |
| 584 | for pad in target['pinout']['add_pads']: |
| 585 | error += check_pad(top, pad, known_pad_names, ['manual'], |
| 586 | prefix + ' Additional Pad') |
| 587 | |
| 588 | return error |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 589 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 590 | |
| 591 | def check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs): |
Timothy Chen | 33b3b9d | 2020-05-08 10:14:17 -0700 | [diff] [blame] | 592 | |
Timothy Chen | b63f3b8 | 2020-06-30 17:10:57 -0700 | [diff] [blame] | 593 | error = 0 |
| 594 | |
Timothy Chen | 92b526e | 2021-02-01 21:23:42 -0800 | [diff] [blame] | 595 | # there should only be one each of pwrmgr/clkmgr/rstmgr |
| 596 | pwrmgrs = [m for m in top['module'] if m['type'] == 'pwrmgr'] |
| 597 | clkmgrs = [m for m in top['module'] if m['type'] == 'clkmgr'] |
| 598 | rstmgrs = [m for m in top['module'] if m['type'] == 'rstmgr'] |
| 599 | |
| 600 | if len(pwrmgrs) == 1 * len(clkmgrs) == 1 * len(rstmgrs) != 1: |
| 601 | log.error("Incorrect number of pwrmgr/clkmgr/rstmgr") |
| 602 | error += 1 |
| 603 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 604 | # all defined clock/reset nets |
Timothy Chen | c623393 | 2020-08-19 15:34:07 -0700 | [diff] [blame] | 605 | reset_nets = [reset['name'] for reset in top['resets']['nodes']] |
Rupert Swarbrick | 127b109 | 2021-07-16 17:10:39 +0100 | [diff] [blame] | 606 | clock_srcs = list(top['clocks'].all_srcs.keys()) |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 607 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 608 | # Check clock/reset port connection for all IPs |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 609 | for ipcfg in top['module']: |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 610 | ipcfg_name = ipcfg['name'].lower() |
| 611 | log.info("Checking clock/resets for %s" % ipcfg_name) |
| 612 | error += validate_reset(ipcfg, ipobjs[ip_idxs[ipcfg_name]], reset_nets) |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 613 | error += validate_clock(ipcfg, ipobjs[ip_idxs[ipcfg_name]], clock_srcs) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 614 | |
| 615 | if error: |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 616 | log.error("module clock/reset checking failed") |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 617 | break |
| 618 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 619 | # Check clock/reset port connection for all xbars |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 620 | for xbarcfg in top['xbar']: |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 621 | xbarcfg_name = xbarcfg['name'].lower() |
| 622 | log.info("Checking clock/resets for xbar %s" % xbarcfg_name) |
| 623 | error += validate_reset(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]], |
| 624 | reset_nets, "xbar") |
| 625 | error += validate_clock(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]], |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 626 | clock_srcs, "xbar") |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 627 | |
| 628 | if error: |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 629 | log.error("xbar clock/reset checking failed") |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 630 | break |
| 631 | |
| 632 | return error |
| 633 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 634 | |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 635 | # Checks the following |
| 636 | # For each defined reset connection in top*.hjson, there exists a defined port at the destination |
| 637 | # and defined reset net |
| 638 | # There are the same number of defined connections as there are ports |
| 639 | def validate_reset(top, inst, reset_nets, prefix=""): |
| 640 | # Gather inst port list |
| 641 | error = 0 |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 642 | |
| 643 | # Handle either an IpBlock (generated by reggen) or an OrderedDict |
| 644 | # (generated by topgen for a crossbar) |
| 645 | if isinstance(inst, IpBlock): |
| 646 | name = inst.name |
Rupert Swarbrick | d0cbfad | 2021-06-29 17:04:51 +0100 | [diff] [blame] | 647 | reset_signals = inst.clocking.reset_signals() |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 648 | else: |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 649 | name = inst['name'] |
| 650 | reset_signals = ([inst.get('reset_primary', 'rst_ni')] + |
| 651 | inst.get('other_reset_list', [])) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 652 | |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 653 | log.info("%s %s resets are %s" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 654 | (prefix, name, reset_signals)) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 655 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 656 | if len(top['reset_connections']) != len(reset_signals): |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 657 | error += 1 |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 658 | log.error("%s %s mismatched number of reset ports and nets" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 659 | (prefix, name)) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 660 | |
| 661 | missing_port = [ |
| 662 | port for port in top['reset_connections'].keys() |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 663 | if port not in reset_signals |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 664 | ] |
| 665 | |
| 666 | if missing_port: |
| 667 | error += 1 |
| 668 | log.error("%s %s Following reset ports do not exist:" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 669 | (prefix, name)) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 670 | [log.error("%s" % port) for port in missing_port] |
| 671 | |
| 672 | missing_net = [ |
| 673 | net for port, net in top['reset_connections'].items() |
| 674 | if net not in reset_nets |
| 675 | ] |
| 676 | |
| 677 | if missing_net: |
| 678 | error += 1 |
| 679 | log.error("%s %s Following reset nets do not exist:" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 680 | (prefix, name)) |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 681 | [log.error("%s" % net) for net in missing_net] |
| 682 | |
| 683 | return error |
| 684 | |
| 685 | |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 686 | # Checks the following |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 687 | # For each defined clock_src in top*.hjson, there exists a defined port at the destination |
| 688 | # and defined clock source |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 689 | # There are the same number of defined connections as there are ports |
Timothy Chen | 0550d69 | 2020-04-20 17:19:35 -0700 | [diff] [blame] | 690 | def validate_clock(top, inst, clock_srcs, prefix=""): |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 691 | # Gather inst port list |
| 692 | error = 0 |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 693 | |
| 694 | # Handle either an IpBlock (generated by reggen) or an OrderedDict |
| 695 | # (generated by topgen for a crossbar) |
| 696 | if isinstance(inst, IpBlock): |
| 697 | name = inst.name |
Rupert Swarbrick | d0cbfad | 2021-06-29 17:04:51 +0100 | [diff] [blame] | 698 | clock_signals = inst.clocking.clock_signals() |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 699 | else: |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 700 | name = inst['name'] |
| 701 | clock_signals = ([inst.get('clock_primary', 'rst_ni')] + |
| 702 | inst.get('other_clock_list', [])) |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 703 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 704 | if len(top['clock_srcs']) != len(clock_signals): |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 705 | error += 1 |
| 706 | log.error("%s %s mismatched number of clock ports and nets" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 707 | (prefix, name)) |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 708 | |
| 709 | missing_port = [ |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 710 | port for port in top['clock_srcs'].keys() |
| 711 | if port not in clock_signals |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 712 | ] |
| 713 | |
| 714 | if missing_port: |
| 715 | error += 1 |
| 716 | log.error("%s %s Following clock ports do not exist:" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 717 | (prefix, name)) |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 718 | [log.error("%s" % port) for port in missing_port] |
| 719 | |
| 720 | missing_net = [ |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 721 | net for port, net in top['clock_srcs'].items() if net not in clock_srcs |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 722 | ] |
| 723 | |
| 724 | if missing_net: |
| 725 | error += 1 |
| 726 | log.error("%s %s Following clock nets do not exist:" % |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 727 | (prefix, name)) |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 728 | [log.error("%s" % net) for net in missing_net] |
| 729 | |
| 730 | return error |
| 731 | |
| 732 | |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 733 | def check_flash(top): |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 734 | |
| 735 | for mem in top['memory']: |
| 736 | if mem['type'] == "eflash": |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 737 | |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 738 | raise ValueError(f'top level flash memory definition not supported. Please use ' |
| 739 | 'the flash embedded inside flash_ctrl instead. If there is a ' |
| 740 | 'need for top level flash memory, please file an issue.') |
Timothy Chen | 1daf582 | 2020-10-26 17:28:15 -0700 | [diff] [blame] | 741 | |
| 742 | |
Timothy Chen | 7f8cc8e | 2020-11-11 13:15:57 -0800 | [diff] [blame] | 743 | def check_power_domains(top): |
| 744 | error = 0 |
| 745 | |
| 746 | # check that the default domain is valid |
| 747 | if top['power']['default'] not in top['power']['domains']: |
| 748 | error += 1 |
| 749 | return error |
| 750 | |
Timothy Chen | 7f8cc8e | 2020-11-11 13:15:57 -0800 | [diff] [blame] | 751 | # Check that each module, xbar, memory has a power domain defined. |
| 752 | # If not, give it a default. |
| 753 | # If there is one defined, check that it is a valid definition |
| 754 | for end_point in top['module'] + top['memory'] + top['xbar']: |
| 755 | if 'domain' not in end_point: |
Timothy Chen | 7f8cc8e | 2020-11-11 13:15:57 -0800 | [diff] [blame] | 756 | end_point['domain'] = top['power']['default'] |
Rupert Swarbrick | 1b4bfc5 | 2021-02-02 11:32:29 +0000 | [diff] [blame] | 757 | |
| 758 | if end_point['domain'] not in top['power']['domains']: |
| 759 | log.error("{} defined invalid domain {}" |
| 760 | .format(end_point['name'], |
| 761 | end_point['domain'])) |
Timothy Chen | 7f8cc8e | 2020-11-11 13:15:57 -0800 | [diff] [blame] | 762 | error += 1 |
| 763 | return error |
| 764 | |
| 765 | # arrived without incident, return |
| 766 | return error |
| 767 | |
| 768 | |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 769 | def check_modules(top, prefix): |
| 770 | error = 0 |
| 771 | for m in top['module']: |
| 772 | modname = m.get("name", "unnamed module") |
| 773 | error += check_keys(m, module_required, module_optional, module_added, |
| 774 | prefix + " " + modname) |
| 775 | |
| 776 | # these fields are mutually exclusive |
| 777 | if 'base_addr' in m and 'base_addrs' in m: |
| 778 | log.error("{} {} a module cannot define both the 'base_addr' " |
| 779 | "and 'base_addrs' keys at the same time" |
| 780 | .format(prefix, modname)) |
| 781 | error += 1 |
| 782 | |
| 783 | if 'base_addrs' in m and 'memory' in m: |
| 784 | for intf, value in m['memory'].items(): |
| 785 | error += check_keys(value, memory_required, |
| 786 | memory_optional, memory_added, |
| 787 | prefix + " " + modname + " " + intf) |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 788 | |
| 789 | # if size is not declared, there must be extra config to determine it |
| 790 | if 'size' not in value and 'config' not in value: |
| 791 | raise ValueError(f'{m["name"]} memory declaration has neither size ' |
| 792 | 'nor extra configuration. Unable to determine ' |
| 793 | 'memory size') |
| 794 | |
| 795 | if 'size' not in value: |
| 796 | mem_type = value['config'].get('type', "") |
| 797 | |
| 798 | if mem_type == "flash": |
| 799 | check_keys(value['config'], eflash_required, eflash_optional, |
| 800 | eflash_added, "Eflash") |
Timothy Chen | 2479883 | 2021-08-20 16:12:12 -0700 | [diff] [blame^] | 801 | flash = Flash(value['config'], m['base_addrs'][intf]) |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 802 | value['size'] = flash.size |
| 803 | value['config'] = flash |
| 804 | else: |
| 805 | raise ValueError(f'{m["name"]} memory config declaration does not have ' |
| 806 | 'a valid type') |
| 807 | |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 808 | # make sure the memory regions correspond to the TL-UL interfaces |
| 809 | if intf not in m['base_addrs']: |
| 810 | log.error("{} {} memory region {} does not " |
| 811 | "correspond to any of the defined " |
| 812 | "TL-UL interfaces".format(prefix, modname, intf)) |
| 813 | error += 1 |
| 814 | # make sure the linker region access attribute is valid |
| 815 | attr = value.get('swaccess', 'unknown attribute') |
Michael Schaffner | 0bedfa6 | 2021-07-27 15:54:15 -0700 | [diff] [blame] | 816 | if attr not in ['ro', 'rw']: |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 817 | log.error('{} {} swaccess attribute {} of memory region {} ' |
| 818 | 'is not valid'.format(prefix, modname, attr, intf)) |
| 819 | error += 1 |
| 820 | return error |
| 821 | |
| 822 | |
Timothy Chen | 3193b00 | 2019-10-04 16:56:05 -0700 | [diff] [blame] | 823 | def validate_top(top, ipobjs, xbarobjs): |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 824 | # return as it is for now |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 825 | error = check_keys(top, top_required, top_optional, top_added, "top") |
| 826 | |
| 827 | if error != 0: |
| 828 | log.error("Top HJSON has top level errors. Aborting") |
| 829 | return top, error |
| 830 | |
| 831 | component = top['name'] |
| 832 | |
Michael Schaffner | 02e982f | 2021-07-09 17:40:34 -0700 | [diff] [blame] | 833 | # Check module instantiations |
| 834 | error += check_modules(top, component) |
| 835 | |
| 836 | # MODULE check |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 837 | err, ip_idxs = check_target(top, ipobjs, Target(TargetType.MODULE)) |
| 838 | error += err |
| 839 | |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 840 | # XBAR check |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 841 | err, xbar_idxs = check_target(top, xbarobjs, Target(TargetType.XBAR)) |
| 842 | error += err |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 843 | |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 844 | # MEMORY check |
Timothy Chen | fb8a784 | 2021-08-20 00:23:47 -0700 | [diff] [blame] | 845 | check_flash(top) |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 846 | |
Timothy Chen | 7f8cc8e | 2020-11-11 13:15:57 -0800 | [diff] [blame] | 847 | # Power domain check |
| 848 | error += check_power_domains(top) |
| 849 | |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 850 | # Clock / Reset check |
Timothy Chen | 80bd8aa | 2019-10-04 15:57:11 -0700 | [diff] [blame] | 851 | error += check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs) |
| 852 | |
Eunchan Kim | 529134b | 2020-04-24 09:51:06 -0700 | [diff] [blame] | 853 | # RV_PLIC check |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 854 | |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 855 | # Pinout, pinmux and target checks |
| 856 | # Note that these checks must happen in this order, as |
| 857 | # the pinmux and target configs depend on the pinout. |
| 858 | error += check_pinout(top, component) |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 859 | error += check_pinmux(top, component) |
Michael Schaffner | 74c4ff2 | 2021-03-30 15:43:46 -0700 | [diff] [blame] | 860 | error += check_implementation_targets(top, component) |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 861 | |
Eunchan Kim | 632c6f7 | 2019-09-30 11:11:51 -0700 | [diff] [blame] | 862 | return top, error |