| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| """This contains a class which is used to help generate top level SW tests. |
| |
| We maintain as a separate class rather than merge implementation with c.py, |
| because both serve different purposes and need to capture the information |
| differently. |
| """ |
| |
| import logging as log |
| import sys |
| from typing import Dict |
| |
| from reggen.ip_block import IpBlock |
| |
| from .c import TopGenC |
| from .lib import Name |
| |
| |
| class TestPeripheral: |
| """Captures a peripheral instance's attributes for use in SW tests. |
| |
| It encapsulates the settings for each peripheral's instance in the design. |
| These settings are captured as identifiers that are already defined in |
| other autogenerated / hand-edited sources such as top_{name}.h and the DIF |
| headers, rather than hard-coded constants. This is done to ensure that a |
| single source of truth is referenced in all of the tests. |
| """ |
| def __init__(self, name: str, inst_name: str, base_addr_name: str, |
| is_templated: bool): |
| self.name = name |
| self.inst_name = inst_name |
| self.base_addr_name = base_addr_name |
| self.is_templated = is_templated |
| |
| |
| class IrqTestPeripheral(TestPeripheral): |
| """Captures a peripheral instance's attributes for use in IRQ test.""" |
| def __init__(self, name: str, inst_name: str, base_addr_name: str, |
| is_templated: bool, plic_name: str, start_irq: str, |
| end_irq: str, plic_start_irq: str): |
| super().__init__(name, inst_name, base_addr_name, is_templated) |
| self.plic_name = plic_name |
| self.start_irq = start_irq |
| self.end_irq = end_irq |
| self.plic_start_irq = plic_start_irq |
| |
| |
| class AlertTestPeripheral(TestPeripheral): |
| """Captures a peripheral instance's attributes for use in IRQ test.""" |
| def __init__(self, name: str, inst_name: str, base_addr_name: str, |
| is_templated: bool, top_alert_name: str, |
| dif_alert_name: str, num_alerts: int): |
| super().__init__(name, inst_name, base_addr_name, is_templated) |
| self.top_alert_name = top_alert_name |
| self.dif_alert_name = dif_alert_name |
| self.num_alerts = num_alerts |
| |
| |
| class TopGenCTest(TopGenC): |
| def __init__(self, top_info, name_to_block: Dict[str, IpBlock]): |
| super().__init__(top_info, name_to_block) |
| |
| self.irq_peripherals = self._get_irq_peripherals() |
| self.alert_peripherals = self._get_alert_peripherals() |
| |
| def _get_irq_peripherals(self): |
| irq_peripherals = [] |
| self.devices() |
| for entry in self.top['module']: |
| inst_name = entry['name'] |
| if inst_name not in self.top["interrupt_module"]: |
| continue |
| |
| name = entry['type'] |
| plic_name = (self._top_name + Name(["plic", "peripheral"]) + |
| Name.from_snake_case(inst_name)) |
| plic_name = plic_name.as_c_enum() |
| |
| # Device regions may have multiple TL interfaces. Pick the region |
| # associated with the 'core' interface. |
| if_name = None if len( |
| self.device_regions[inst_name]) == 1 else 'core' |
| try: |
| region = self.device_regions[inst_name][if_name] |
| except KeyError: |
| log.error(f"The 'base_addrs' dict for {name} needs to have " |
| "one entry keyed with 'None' or 'core'.") |
| sys.exit(1) |
| |
| base_addr_name = region.base_addr_name().as_c_define() |
| is_templated = 'attr' in entry and entry['attr'] == 'templated' |
| |
| plic_name = (self._top_name + Name(["plic", "peripheral"]) + |
| Name.from_snake_case(inst_name)) |
| plic_name = plic_name.as_c_enum() |
| |
| start_irq = self.device_irqs[inst_name][0] |
| end_irq = self.device_irqs[inst_name][-1] |
| plic_start_irq = (self._top_name + Name(["plic", "irq", "id"]) + |
| Name.from_snake_case(start_irq)) |
| plic_start_irq = plic_start_irq.as_c_enum() |
| |
| # Get DIF compliant, instance-agnostic IRQ names. |
| start_irq = start_irq.replace(inst_name, f"dif_{name}_irq", 1) |
| start_irq = Name.from_snake_case(start_irq).as_c_enum() |
| end_irq = end_irq.replace(inst_name, f"dif_{name}_irq", 1) |
| end_irq = Name.from_snake_case(end_irq).as_c_enum() |
| |
| irq_peripheral = IrqTestPeripheral(name, inst_name, base_addr_name, |
| is_templated, plic_name, start_irq, |
| end_irq, plic_start_irq) |
| irq_peripherals.append(irq_peripheral) |
| |
| irq_peripherals.sort(key=lambda p: p.inst_name) |
| return irq_peripherals |
| |
| def _get_alert_peripherals(self): |
| alert_peripherals = [] |
| self.devices() |
| for entry in self.top['module']: |
| inst_name = entry['name'] |
| if inst_name not in self.top["alert_module"]: |
| continue |
| |
| # RV_DM module does not have DIF. |
| if inst_name == "rv_dm": |
| continue |
| |
| for item in self.top['module']: |
| if item['name'] == inst_name: |
| name = item['type'] |
| |
| regions = self.device_regions[inst_name] |
| if "core" in regions: |
| if_name = "core" |
| elif "regs" in regions: |
| if_name = "regs" |
| elif "cfg" in regions: |
| if_name = "cfg" |
| else: |
| if_name = None |
| region = regions[if_name] |
| base_addr_name = region.base_addr_name().as_c_define() |
| break |
| |
| is_templated = 'attr' in entry and entry['attr'] == 'templated' |
| dif_alert_name = self.device_alerts[inst_name][0] |
| num_alerts = len(self.device_alerts[inst_name]) |
| |
| top_alert_name = (self._top_name + |
| Name(["Alert", "Id"]) + |
| Name.from_snake_case(dif_alert_name)) |
| top_alert_name = top_alert_name.as_c_enum() |
| |
| # Get DIF compliant, instance-agnostic alert names. |
| dif_alert_name = dif_alert_name.replace(inst_name, f"dif_{name}_alert", 1) |
| dif_alert_name = Name.from_snake_case(dif_alert_name).as_c_enum() |
| |
| alert_peripheral = AlertTestPeripheral(name, inst_name, base_addr_name, is_templated, |
| top_alert_name, dif_alert_name, num_alerts) |
| alert_peripherals.append(alert_peripheral) |
| |
| alert_peripherals.sort(key=lambda p: p.inst_name) |
| return alert_peripherals |