blob: 7941957249eab18a23c6b94b5a06b38d5f4ea685 [file] [log] [blame]
# 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