Skip to content

Commit

Permalink
[topgen] Generically filter for MMIO region visible devices
Browse files Browse the repository at this point in the history
Remove hardcoded devices and interfaces for MMIO region filtering by
adding two new optional module attributes cpu_visible and cpu_not_visible.

Signed-off-by: Robert Schilling <[email protected]>
  • Loading branch information
Razer6 committed May 23, 2024
1 parent 3216fab commit 6cd511e
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 100 deletions.
10 changes: 10 additions & 0 deletions hw/top_darjeeling/data/autogen/top_darjeeling.gen.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -4082,6 +4082,10 @@
hart: 0x30600000
}
}
cpu_visible:
[
ram
]
memory:
{
ram:
Expand Down Expand Up @@ -4277,6 +4281,12 @@
soc_dbg: 0x00000000
}
}
cpu_not_visible:
[
mem
regs
dbg
]
param_decl:
{
SecVolatileRawUnlockEn: top_pkg::SecVolatileRawUnlockEn
Expand Down
2 changes: 2 additions & 0 deletions hw/top_darjeeling/data/top_darjeeling.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@
regs: {hart: "0x30500000"},
ram: {hart: "0x30600000"},
},
cpu_visible: ['ram']
// Memory regions must be associated with a dedicated
// TL-UL device interface.
memory: {
Expand All @@ -577,6 +578,7 @@
regs: {hart: "0x21200000"},
dbg: {soc_dbg: "0x00000000"},
},
cpu_not_visible: ["mem", "regs", "dbg"]
param_decl: {
// NOTE THAT THIS IS A FEATURE FOR TEST CHIPS ONLY TO MITIGATE
// THE RISK OF A BROKEN OTP MACRO. THIS WILL BE DISABLED FOR
Expand Down
2 changes: 1 addition & 1 deletion hw/top_darjeeling/sw/autogen/chip/top_darjeeling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2748,4 +2748,4 @@ pub enum TopDarjeelingHintableClocks {
/// configuration space, i.e. ROM, main SRAM, and flash are excluded but
/// retention SRAM, spi_device memory, or usbdev memory are included.
pub const TOP_DARJEELING_MMIO_BASE_ADDR: usize = 0x21100000;
pub const TOP_DARJEELING_MMIO_SIZE_BYTES: usize = 0xF400020;
pub const TOP_DARJEELING_MMIO_SIZE_BYTES: usize = 0xF501000;
2 changes: 1 addition & 1 deletion hw/top_darjeeling/sw/autogen/chip/top_darjeeling_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,4 +737,4 @@ pub const TOP_DARJEELING_RV_CORE_IBEX_CFG_SIZE_BYTES: usize = 0x800;
/// configuration space, i.e. ROM, main SRAM, and flash are excluded but
/// retention SRAM, spi_device memory, or usbdev memory are included.
pub const TOP_DARJEELING_MMIO_BASE_ADDR: usize = 0x21100000;
pub const TOP_DARJEELING_MMIO_SIZE_BYTES: usize = 0xF400020;
pub const TOP_DARJEELING_MMIO_SIZE_BYTES: usize = 0xF501000;
9 changes: 9 additions & 0 deletions hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -4814,6 +4814,10 @@
hart: 0x40600000
}
}
cpu_visible:
[
ram
]
memory:
{
ram:
Expand Down Expand Up @@ -5462,6 +5466,11 @@
hart: 0x41200000
}
}
cpu_not_visible:
[
mem
regs
]
generate_dif: false
clock_connections:
{
Expand Down
2 changes: 2 additions & 0 deletions hw/top_earlgrey/data/top_earlgrey.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@
regs: {hart: "0x40500000"},
ram: {hart: "0x40600000"},
}
cpu_visible: ["ram"]
// Memory regions must be associated with a dedicated
// TL-UL device interface.
memory: {
Expand Down Expand Up @@ -705,6 +706,7 @@
mem: {hart: "0x00010000"},
regs: {hart: "0x41200000"}
},
cpu_not_visible: ["mem", "regs"]
generate_dif: "False"
},
{ name: "rv_plic",
Expand Down
51 changes: 2 additions & 49 deletions util/topgen/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,11 @@
from mako.template import Template
from reggen.ip_block import IpBlock

from .lib import Name, get_base_and_size
from .lib import Name, get_base_and_size, MemoryRegion, init_mmio_region

C_FILE_EXTENSIONS = (".c", ".h", ".cc", ".inc")


class MemoryRegion(object):
def __init__(self, name: Name, base_addr: int, size_bytes: int):
assert isinstance(base_addr, int)
self.name = name
self.base_addr = base_addr
self.size_bytes = size_bytes
self.size_words = (size_bytes + 3) // 4

def base_addr_name(self):
return self.name + Name(["base", "addr"])

def offset_name(self):
return self.name + Name(["offset"])

def size_bytes_name(self):
return self.name + Name(["size", "bytes"])

def size_words_name(self):
return self.name + Name(["size", "words"])


class CEnum(object):
def __init__(self, name):
self.name = name
Expand Down Expand Up @@ -123,7 +102,7 @@ def __init__(self, top_info, name_to_block: Dict[str, IpBlock]):
self._init_rstmgr_sw_rsts()
self._init_pwrmgr_reset_requests()
self._init_clkmgr_clocks()
self._init_mmio_region()
self.mmio = init_mmio_region(self.top, self._top_name, self.memories(), self.devices())

def devices(self) -> List[Tuple[Tuple[str, Optional[str]], MemoryRegion]]:
'''Return a list of MemoryRegion objects for devices on the bus
Expand Down Expand Up @@ -511,29 +490,3 @@ def _init_clkmgr_clocks(self):
self.clkmgr_gateable_clocks = gateable_clocks
self.clkmgr_hintable_clocks = hintable_clocks

def _init_mmio_region(self):
"""
Computes the bounds of the MMIO region.
MMIO region excludes any memory that is separate from the module configuration
space, i.e. ROM, main SRAM, and flash are excluded but retention SRAM,
spi_device memory, or usbdev memory are included.
"""
memories = [region.base_addr for (_, region) in self.memories()]
# TODO(#14345): Remove the hardcoded "rv_dm" name check below.
# TODO: we need a cleaner way to define which buses are visible
# by the CPU and which ones are not. For now, exclude every
# interface with the name `dbg`, since that is attached to the
# debug bus which is not connected to the CPU LSU.
regions = [
region for ((dev_name, if_name), region) in self.devices()
if (dev_name == "sram_ctrl_ret_aon" and if_name == 'ram') or
(region.base_addr not in memories and dev_name != "rv_dm" and
(if_name is None or if_name != 'dbg'))
]
# Note: The memory interface of the retention RAM is in the MMIO address space,
# which we prefer since it reduces the number of ePMP regions we need.
mmio = range(min([r.base_addr for r in regions]),
max([r.base_addr + r.size_bytes for r in regions]))
self.mmio = MemoryRegion(self._top_name + Name(["mmio"]), mmio.start,
mmio.stop - mmio.start)
49 changes: 49 additions & 0 deletions util/topgen/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ def remove_part(self, part_to_remove: str) -> "Name":
return Name([p for p in self.parts if p != part_to_remove])


class MemoryRegion(object):
def __init__(self, name: Name, base_addr: int, size_bytes: int):
assert isinstance(base_addr, int)
self.name = name
self.base_addr = base_addr
self.size_bytes = size_bytes
self.size_words = (size_bytes + 3) // 4

def base_addr_name(self):
return self.name + Name(["base", "addr"])

def offset_name(self):
return self.name + Name(["offset"])

def size_bytes_name(self):
return self.name + Name(["size", "bytes"])

def size_words_name(self):
return self.name + Name(["size", "words"])


def is_ipcfg(ip: Path) -> bool: # return bool
log.info("IP Path: %s" % repr(ip))
ip_name = ip.parents[1].name
Expand Down Expand Up @@ -566,3 +587,31 @@ def is_lc_ctrl(modules):
return True

return False


def init_mmio_region(top, top_name, memories, devices):
"""
Computes the bounds of the MMIO region.
MMIO region excludes any memory that is separate from the module configuration
space, i.e. ROM, main SRAM, and flash are excluded but retention SRAM,
spi_device memory, or usbdev memory are included.
"""
memories = [region.base_addr for (_, region) in memories]
regions = []
for ((dev_name, if_name), region) in devices:
module = get_module_by_name(top, dev_name)

# Ignore interface if explicitly not visible to the CPU
if 'cpu_not_visible' in module and if_name in module['cpu_not_visible']:
continue
# Include interface if explicitly visible to the CPU
if (('cpu_visible' in module and if_name in module['cpu_visible']) or
region.base_addr not in memories):
regions.append(region)

# Note: The memory interface of the retention RAM is in the MMIO address space,
# which we prefer since it reduces the number of ePMP regions we need.
mmio = range(min([r.base_addr for r in regions]),
max([r.base_addr + r.size_bytes for r in regions]))
return MemoryRegion(top_name + Name(["mmio"]), mmio.start, mmio.stop - mmio.start)
51 changes: 2 additions & 49 deletions util/topgen/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,11 @@
from mako.template import Template
from reggen.ip_block import IpBlock

from .lib import Name, get_base_and_size
from .lib import Name, get_base_and_size, MemoryRegion, init_mmio_region

RUST_FILE_EXTENSIONS = (".rs")


class MemoryRegion(object):
def __init__(self, name: Name, base_addr: int, size_bytes: int):
assert isinstance(base_addr, int)
self.name = name
self.base_addr = base_addr
self.size_bytes = size_bytes
self.size_words = (size_bytes + 3) // 4

def base_addr_name(self):
return self.name + Name(["base", "addr"])

def offset_name(self):
return self.name + Name(["offset"])

def size_bytes_name(self):
return self.name + Name(["size", "bytes"])

def size_words_name(self):
return self.name + Name(["size", "words"])


class RustEnum(object):
def __init__(self, top_name, name, repr_type=None):
self.name = top_name + name
Expand Down Expand Up @@ -214,7 +193,7 @@ def __init__(self, top_info, name_to_block: Dict[str, IpBlock], version_stamp: D
self._init_rstmgr_sw_rsts()
self._init_pwrmgr_reset_requests()
self._init_clkmgr_clocks()
self._init_mmio_region()
self.mmio = init_mmio_region(self.top, self._top_name, self.memories(), self.devices())

def devices(self) -> List[Tuple[Tuple[str, Optional[str]], MemoryRegion]]:
'''Return a list of MemoryRegion objects for devices on the bus
Expand Down Expand Up @@ -597,29 +576,3 @@ def _init_clkmgr_clocks(self):

self.clkmgr_gateable_clocks = gateable_clocks
self.clkmgr_hintable_clocks = hintable_clocks

def _init_mmio_region(self):
"""
Computes the bounds of the MMIO region.
MMIO region excludes any memory that is separate from the module configuration
space, i.e. ROM, main SRAM, and flash are excluded but retention SRAM,
spi_device memory, or usbdev memory are included.
"""
memories = [region.base_addr for (_, region) in self.memories()]
# TODO(#14345): Remove the hardcoded "rv_dm" name check below.
# TODO: we need a cleaner way to define which buses are visible
# by the CPU and which ones are not. For now, exclude every
# interface with the name `dbg`, since that is attached to the
# debug bus which is not connected to the CPU LSU.
regions = [
region for ((dev_name, if_name), region) in self.devices()
if region.base_addr not in memories and dev_name != "rv_dm" and
(if_name is None or if_name != 'dbg')
]
# Note: The memory interface of the retention RAM is in the MMIO address space,
# which we prefer since it reduces the number of ePMP regions we need.
mmio = range(min([r.base_addr for r in regions]),
max([r.base_addr + r.size_bytes for r in regions]))
self.mmio = MemoryRegion(self._top_name + Name(["mmio"]), mmio.start,
mmio.stop - mmio.start)
2 changes: 2 additions & 0 deletions util/topgen/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@
'domain': ['l', 'optional list of power domains, defaults to Domain0'],
'clock_reset_export': ['l', 'optional list with prefixes for exported '
'clocks and resets at the chip level'],
'cpu_visible': ['list', 'List of address spaces visible to the CPU'],
'cpu_not_visible': ['list', 'List of address spaces not visible to the CPU'],
'attr': ['s', 'optional attribute indicating whether the IP is '
'"templated" or "reggen_only"'],
'base_addr': ['g', 'dict of address space mapped to the corresponding '
Expand Down

0 comments on commit 6cd511e

Please sign in to comment.