python: Move the components lib to be compiled in the binary

There has been some debate on how best to distribute the components
library. This change builds the components library into the gem5 binary.
The components library will now function similar to the `m5` library.
There is no need for awkward imports or obtaining the library from some
third-party source.

Additional incorporated in this patch:
* Added `__init__.py` to the Python modules.
* Fixed a typo in the `abstract_ruby_cache_hierarchy.py` filename.
* Ensured that imports within the library are relative.

Issue-on: https://gem5.atlassian.net/browse/GEM5-1023
Change-Id: I3988c8710cda8dcf7b21109a2cf5c3f1608cc71a
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/49690
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Austin Harris <mail@austin-harris.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Bobby R. Bruce
2021-08-30 11:38:46 -07:00
parent 136809cc45
commit f775c4c4a7
88 changed files with 194 additions and 122 deletions

View File

@@ -28,6 +28,168 @@
Import('*')
PySource('components_library', 'components_library/__init__.py')
PySource('components_library', 'components_library/coherence_protocol.py')
PySource('components_library', 'components_library/isas.py')
PySource('components_library', 'components_library/runtime.py')
PySource('components_library.boards', 'components_library/boards/__init__.py')
PySource('components_library.boards',
'components_library/boards/abstract_board.py')
PySource('components_library.boards',
'components_library/boards/mem_mode.py')
PySource('components_library.boards',
'components_library/boards/riscv_board.py')
PySource('components_library.boards',
'components_library/boards/simple_board.py')
PySource('components_library.boards',
'components_library/boards/test_board.py')
PySource('components_library.boards', 'components_library/boards/x86_board.py')
PySource('components_library.cachehierarchies',
'components_library/cachehierarchies/__init__.py')
PySource('components_library.cachehierarchies',
'components_library/cachehierarchies/abstract_cache_hierarchy.py')
PySource('components_library.cachehierarchies',
'components_library/cachehierarchies/'
'abstract_two_level_cache_hierarchy.py')
PySource('components_library.cachehierarchies.classic',
'components_library/cachehierarchies/classic/__init__.py')
PySource('components_library.cachehierarchies.classic',
'components_library/cachehierarchies/classic/'
'abstract_classic_cache_hierarchy.py')
PySource('components_library.cachehierarchies.classic',
'components_library/cachehierarchies/classic/no_cache.py')
PySource('components_library.cachehierarchies.classic',
'components_library/cachehierarchies/classic/'
'private_l1_cache_hierarchy.py')
PySource('components_library.cachehierarchies.classic',
'components_library/cachehierarchies/classic/'
'private_l1_private_l2_cache_hierarchy.py')
PySource('components_library.cachehierarchies.classic.caches',
'components_library/cachehierarchies/classic/caches/__init__.py')
PySource('components_library.cachehierarchies.classic.caches',
'components_library/cachehierarchies/classic/caches/l1dcache.py')
PySource('components_library.cachehierarchies.classic.caches',
'components_library/cachehierarchies/classic/caches/l1icache.py')
PySource('components_library.cachehierarchies.classic.caches',
'components_library/cachehierarchies/classic/caches/l2cache.py')
PySource('components_library.cachehierarchies.classic.caches',
'components_library/cachehierarchies/classic/caches/mmu_cache.py')
PySource('components_library.cachehierarchies.ruby',
'components_library/cachehierarchies/ruby/__init__.py')
PySource('components_library.cachehierarchies.ruby',
'components_library/cachehierarchies/ruby/'
'abstract_ruby_cache_hierarchy.py')
PySource('components_library.cachehierarchies.ruby',
'components_library/cachehierarchies/ruby/'
'mesi_two_level_cache_hierarchy.py')
PySource('components_library.cachehierarchies.ruby',
'components_library/cachehierarchies/ruby/mi_example_cache_hierarchy.py')
PySource('components_library.cachehierarchies.ruby.caches',
'components_library/cachehierarchies/ruby/caches/__init__.py')
PySource('components_library.cachehierarchies.ruby.caches',
'components_library/cachehierarchies/ruby/caches/abstract_directory.py')
PySource('components_library.cachehierarchies.ruby.caches',
'components_library/cachehierarchies/ruby/caches/'
'abstract_dma_controller.py')
PySource('components_library.cachehierarchies.ruby.caches',
'components_library/cachehierarchies/ruby/caches/abstract_l1_cache.py')
PySource('components_library.cachehierarchies.ruby.caches',
'components_library/cachehierarchies/ruby/caches/abstract_l2_cache.py')
PySource('components_library.cachehierarchies.ruby.caches.mesi_two_level',
'components_library/cachehierarchies/ruby/caches/mesi_two_level/'
'__init__.py')
PySource('components_library.cachehierarchies.ruby.caches.mesi_two_level',
'components_library/cachehierarchies/ruby/caches/mesi_two_level/'
'directory.py')
PySource('components_library.cachehierarchies.ruby.caches.mesi_two_level',
'components_library/cachehierarchies/ruby/caches/mesi_two_level/'
'dma_controller.py')
PySource('components_library.cachehierarchies.ruby.caches.mesi_two_level',
'components_library/cachehierarchies/ruby/caches/mesi_two_level/'
'l1_cache.py')
PySource('components_library.cachehierarchies.ruby.caches.mesi_two_level',
'components_library/cachehierarchies/ruby/caches/mesi_two_level/'
'l2_cache.py')
PySource('components_library.cachehierarchies.ruby.caches.mi_example',
'components_library/cachehierarchies/ruby/caches/mi_example/__init__.py')
PySource('components_library.cachehierarchies.ruby.caches.mi_example',
'components_library/cachehierarchies/ruby/caches/mi_example/directory.py')
PySource('components_library.cachehierarchies.ruby.caches.mi_example',
'components_library/cachehierarchies/ruby/caches/mi_example/'
'dma_controller.py')
PySource('components_library.cachehierarchies.ruby.caches.mi_example',
'components_library/cachehierarchies/ruby/caches/mi_example/l1_cache.py')
PySource('components_library.cachehierarchies.ruby.topologies',
'components_library/cachehierarchies/ruby/topologies/__init__.py')
PySource('components_library.cachehierarchies.ruby.topologies',
'components_library/cachehierarchies/ruby/topologies/simple_pt2pt.py')
PySource('components_library.memory', 'components_library/memory/__init__.py')
PySource('components_library.memory',
'components_library/memory/abstract_memory_system.py')
PySource('components_library.memory', 'components_library/memory/dramsim_3.py')
PySource('components_library.memory',
'components_library/memory/single_channel.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/__init__.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/ddr3.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/ddr4.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/gddr.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/hbm.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/hmc.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/lpddr2.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/lpddr3.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/lpddr5.py')
PySource('components_library.memory.dram_interfaces',
'components_library/memory/dram_interfaces/wideio.py')
PySource('components_library.processors',
'components_library/processors/__init__.py')
PySource('components_library.processors',
'components_library/processors/abstract_core.py')
PySource('components_library.processors',
'components_library/processors/abstract_generator_core.py')
PySource('components_library.processors',
'components_library/processors/abstract_processor.py')
PySource('components_library.processors',
'components_library/processors/complex_generator_core.py')
PySource('components_library.processors',
'components_library/processors/complex_generator.py')
PySource('components_library.processors',
'components_library/processors/cpu_types.py')
PySource('components_library.processors',
'components_library/processors/linear_generator_core.py')
PySource('components_library.processors',
'components_library/processors/linear_generator.py')
PySource('components_library.processors',
'components_library/processors/random_generator_core.py')
PySource('components_library.processors',
'components_library/processors/random_generator.py')
PySource('components_library.processors',
'components_library/processors/simple_core.py')
PySource('components_library.processors',
'components_library/processors/simple_processor.py')
PySource('components_library.processors',
'components_library/processors/simple_switchable_processor.py')
PySource('components_library.processors',
'components_library/processors/switchable_processor.py')
PySource('components_library.resources',
'components_library/resources/__init__.py')
PySource('components_library.resources',
'components_library/resources/downloader.py')
PySource('components_library.resources',
'components_library/resources/resource.py')
PySource('components_library.utils', 'components_library/utils/__init__.py')
PySource('components_library.utils', 'components_library/utils/filelock.py')
PySource('components_library.utils', 'components_library/utils/override.py')
PySource('components_library.utils', 'components_library/utils/requires.py')
PySource('', 'importer.py')
PySource('m5', 'm5/__init__.py')
PySource('m5', 'm5/SimObject.py')

View File

@@ -0,0 +1,37 @@
# The gem5 Components Library
**IMPORTANT NOTE:** This is a Work-In-Process Documentation. This will be expanded and completed in later revisions of the components library.
This is a high-level overview of what this library is.
## Philosophy
Like the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), the gem5 Components Library has a set of guiding principles.
Note, these are note rules, and they are meant to be *bent* if needed (but maybe not broken).
### Components are extensible, not configurable
We prefer *extensibility* instead of *configurability*.
Instead of each component taking many different parameters, we have decided to make many different components.
For instance, instead of having one core component which takes a parameter of the type (e.g., in-order or out-of-order), we specify multiple different components, an `InOrderCPU` and an `OutOfOrder` CPU.
### Components use easy to remember names
We prefer longer and easier to remember names than shorter or jargon names.
## Structure of the components library
### Boards
### Processors
### Memories
### Cache hierarchies
## Contributing to the components library
### Code style
- Use [Black](https://black.readthedocs.io/en/stable/) to format your code.
- Docstring should follow the [ReST style and Sphinx](https://www.sphinx-doc.org/)

View File

@@ -0,0 +1,213 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from .mem_mode import MemMode
from m5.objects import System, Port, IOXBar, ClockDomain
from typing import List
class AbstractBoard(System):
"""The abstract board interface.
Boards are used as the object which can connect together all other
components. This abstract class defines the external interface that other
boards must provide. Boards can be specialized for different ISAs or system
designs (e.g., core counts, cache types, memory channels, I/O devices, etc)
In addition to providing the place that system components are connected,
the board also exposes an interface for the caches, processor, and memory
to interact.
The board also exposes an interface to set up I/O devices which needs to be
specialized for each ISA and/or platform.
Board inherits from System and can therefore be used as a System simobject
when required.
"""
__metaclass__ = ABCMeta
def __init__(
self,
processor: "AbstractProcessor",
memory: "AbstractMemory",
cache_hierarchy: "AbstractCacheHierarchy",
) -> None:
super(AbstractBoard, self).__init__()
"""
:param processor: The processor for this board.
:param memory: The memory for this board.
:param cache_hierarchy: The Cachie Hierarchy for this board.
"""
self.processor = processor
self.memory = memory
self.cache_hierarchy = cache_hierarchy
def get_processor(self) -> "AbstractProcessor":
"""Get the processor connected to the board.
:returns: The processor.
"""
return self.processor
def get_memory(self) -> "AbstractMemory":
"""Get the memory (RAM) connected to the board.
:returns: The memory system.
"""
return self.memory
def get_cache_hierarchy(self) -> "AbstractCacheHierarchy":
"""Get the cache hierarchy connected to the board.
:returns: The cache hierarchy.
"""
return self.cache_hierarchy
def get_cache_line_size(self) -> int:
"""Get the size of the cache line.
:returns: The size of the cache line size.
"""
return self.cache_line_size
# Technically `get_dma_ports` returns a list. This list could be empty to
# indicate the presense of dma ports. Though I quite like having this
# boolean to quickly check a board.
@abstractmethod
def has_dma_ports(self) -> bool:
"""Determine whether the board has DMA ports or not.
:returns: True if the board has DMA ports, otherwise False.
"""
raise NotImplementedError
@abstractmethod
def get_dma_ports(self) -> List[Port]:
"""Get the board's Direct Memory Access ports.
This abstract method must be implemented within the subclasses if they
support DMA and/or full system simulation.
:returns: A List of the Direct Memory Access ports.
"""
raise NotImplementedError
@abstractmethod
def has_io_bus(self) -> bool:
"""Determine whether the board has an IO bus or not.
:returns: True if the board has an IO bus, otherwise False.
"""
raise NotImplementedError
@abstractmethod
def get_io_bus(self) -> IOXBar:
"""Get the board's IO Bus.
This abstract method must be implemented within the subclasses if they
support DMA and/or full system simulation.
The I/O bus is a non-coherent bus (in the classic caches). On the CPU
side, it accepts requests meant for I/O devices. On the memory side, it
forwards these requests to the devices (e.g., the interrupt
controllers on each core).
:returns: The I/O Bus.
"""
raise NotImplementedError
@abstractmethod
def has_coherent_io(self) -> bool:
"""Determine whether the board needs coherent I/O
:returns: True if the board needs coherent I/O, false otherwise
"""
raise NotImplementedError
@abstractmethod
def get_mem_side_coherent_io_port(self):
"""Get the memory-side coherent I/O port.
This abstract method must be implemented if has_coherent_io is true.
This returns a *port* (not a bus) that should be connected to a
CPU-side port for which coherent I/O (DMA) is issued.
"""
raise NotImplementedError
@abstractmethod
def get_clock_domain(self) -> ClockDomain:
"""Get the clock domain.
:returns: The clock domain.
"""
raise NotImplementedError
@abstractmethod
def connect_system_port(self, port: Port) -> None:
raise NotImplementedError
@abstractmethod
def set_mem_mode(self, mem_mode: MemMode) -> None:
"""
Set the memory mode of the board.
:param mem_mode: The memory mode the board is to be set to.
"""
raise NotImplementedError
@abstractmethod
def setup_memory_ranges(self) -> None:
"""
Set the memory ranges for this board.
This is called by `connect_things`. It can query the board's memory
to determine the size and the set the memory ranges on the memory if
it needs to move the memory devices.
The simplest implementation just sets the board's memory range to be
the size of memory and memory's memory range to be the same as the
board. Full system implementations will likely need something more
complicated.
"""
raise NotImplementedError
@abstractmethod
def connect_things(self) -> None:
"""Connects all the components to the board.
This should be called after the constructor.
When implementing this function, derived boards should use this to
hook up the memory, process, and cache hierarchy as a *second* stage.
You should use this function to connect things together when you need
to know that everything has already been constructed.
"""
raise NotImplementedError

View File

@@ -0,0 +1,53 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Specifies the MemMode enum
"""
from enum import Enum
class MemMode(Enum):
TIMING = 1
ATOMIC = 2
ATOMIC_NONCACHING = 3
def mem_mode_to_string(mem_mode: MemMode) -> str:
"""
Returns the string form of the mem_mode, compatible with the gem5
simulator.
:returns: The string form of the mem_mode
"""
if mem_mode == MemMode.TIMING:
return "timing"
elif mem_mode == MemMode.ATOMIC:
return "atomic"
elif mem_mode == MemMode.ATOMIC_NONCACHING:
return "atomic_noncaching"
else:
return NotImplementedError

View File

@@ -0,0 +1,378 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
from typing import Optional
from ..utils.override import overrides
from .simple_board import SimpleBoard
from .abstract_board import AbstractBoard
from ..processors.abstract_processor import AbstractProcessor
from ..memory.abstract_memory_system import AbstractMemorySystem
from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from ..isas import ISA
from ..runtime import get_runtime_isa
import m5
from m5.objects import (
Bridge,
PMAChecker,
RiscvLinux,
AddrRange,
IOXBar,
RiscvRTC,
HiFive,
CowDiskImage,
RawDiskImage,
MmioVirtIO,
VirtIOBlock,
Frequency,
Port,
)
from m5.util.fdthelper import (
Fdt,
FdtNode,
FdtProperty,
FdtPropertyStrings,
FdtPropertyWords,
FdtState,
)
class RiscvBoard(SimpleBoard):
"""
A board capable of full system simulation for RISC-V
At a high-level, this is based on the HiFive Unmatched board from SiFive.
This board assumes that you will be booting Linux.
**Limitations**
* Only works with classic caches
"""
def __init__(
self,
clk_freq: str,
processor: AbstractProcessor,
memory: AbstractMemorySystem,
cache_hierarchy: AbstractCacheHierarchy,
) -> None:
super().__init__(clk_freq, processor, memory, cache_hierarchy)
if get_runtime_isa() != ISA.RISCV:
raise EnvironmentError(
"RiscvBoard will only work with the RISC-V ISA. Please"
" recompile gem5 with ISA=RISCV."
)
if cache_hierarchy.is_ruby():
raise EnvironmentError("RiscvBoard is not compatible with Ruby")
self.workload = RiscvLinux()
# Contains a CLINT, PLIC, UART, and some functions for the dtb, etc.
self.platform = HiFive()
# Note: This only works with single threaded cores.
self.platform.plic.n_contexts = self.processor.get_num_cores() * 2
self.platform.attachPlic()
self.platform.clint.num_threads = self.processor.get_num_cores()
# Add the RTC
# TODO: Why 100MHz? Does something else need to change when this does?
self.platform.rtc = RiscvRTC(frequency=Frequency("100MHz"))
self.platform.clint.int_pin = self.platform.rtc.int_pin
# Incoherent I/O bus
self.iobus = IOXBar()
# The virtio disk
self.disk = MmioVirtIO(
vio=VirtIOBlock(),
interrupt_id=0x8,
pio_size=4096,
pio_addr=0x10008000,
)
# Note: This overrides the platform's code because the platform isn't
# general enough.
self._on_chip_devices = [self.platform.clint, self.platform.plic]
self._off_chip_devices = [self.platform.uart, self.disk]
def _setup_io_devices(self) -> None:
"""Connect the I/O devices to the I/O bus"""
for device in self._off_chip_devices:
device.pio = self.iobus.mem_side_ports
for device in self._on_chip_devices:
device.pio = self.get_cache_hierarchy().get_mem_side_port()
self.bridge = Bridge(delay="10ns")
self.bridge.mem_side_port = self.iobus.cpu_side_ports
self.bridge.cpu_side_port = (
self.get_cache_hierarchy().get_mem_side_port()
)
self.bridge.ranges = [
AddrRange(dev.pio_addr, size=dev.pio_size)
for dev in self._off_chip_devices
]
def _setup_pma(self) -> None:
"""Set the PMA devices on each core"""
uncacheable_range = [
AddrRange(dev.pio_addr, size=dev.pio_size)
for dev in self._on_chip_devices + self._off_chip_devices
]
# TODO: Not sure if this should be done per-core like in the example
for cpu in self.get_processor().get_cores():
cpu.get_mmu().pma_checker = PMAChecker(
uncacheable=uncacheable_range
)
@overrides(AbstractBoard)
def has_io_bus(self) -> bool:
return True
@overrides(AbstractBoard)
def get_io_bus(self) -> IOXBar:
return self.iobus
def has_coherent_io(self) -> bool:
return True
def get_mem_side_coherent_io_port(self) -> Port:
return self.iobus.mem_side_ports
@overrides(AbstractBoard)
def setup_memory_ranges(self):
memory = self.get_memory()
mem_size = memory.get_size()
self.mem_ranges = [AddrRange(start=0x80000000, size=mem_size)]
memory.set_memory_range(self.mem_ranges)
def set_workload(
self, bootloader: str, disk_image: str, command: Optional[str] = None
):
"""Setup the full system files
See http://resources.gem5.org/resources/riscv-fs for the currently
tested kernels and OSes.
The command is an optional string to execute once the OS is fully
booted, assuming the disk image is setup to run `m5 readfile` after
booting.
After the workload is set up, this functino will generate the device
tree file and output it to the output directory.
**Limitations**
* Only supports a Linux kernel
* Disk must be configured correctly to use the command option
* This board doesn't support the command option
:param bootloader: The compiled bootloader with the kernel as a payload
:param disk_image: A disk image containing the OS data. The first
partition should be the root partition.
:param command: The command(s) to run with bash once the OS is booted
"""
self.workload.object_file = bootloader
image = CowDiskImage(
child=RawDiskImage(read_only=True), read_only=False
)
image.child.image_file = disk_image
self.disk.vio.image = image
self.workload.command_line = "console=ttyS0 root=/dev/vda ro"
# Note: This must be called after set_workload because it looks for an
# attribute named "disk" and connects
self._setup_io_devices()
self._setup_pma()
# Default DTB address if bbl is built with --with-dts option
self.workload.dtb_addr = 0x87E00000
# We need to wait to generate the device tree until after the disk is
# set up. Now that the disk and workload are set, we can generate the
# device tree file.
self.generate_device_tree(m5.options.outdir)
self.workload.dtb_filename = os.path.join(
m5.options.outdir, "device.dtb"
)
def generate_device_tree(self, outdir: str) -> None:
"""Creates the dtb and dts files.
Creates two files in the outdir: 'device.dtb' and 'device.dts'
:param outdir: Directory to output the files
"""
state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1)
root = FdtNode("/")
root.append(state.addrCellsProperty())
root.append(state.sizeCellsProperty())
root.appendCompatible(["riscv-virtio"])
for mem_range in self.mem_ranges:
node = FdtNode("memory@%x" % int(mem_range.start))
node.append(FdtPropertyStrings("device_type", ["memory"]))
node.append(
FdtPropertyWords(
"reg",
state.addrCells(mem_range.start)
+ state.sizeCells(mem_range.size()),
)
)
root.append(node)
# See Documentation/devicetree/bindings/riscv/cpus.txt for details.
cpus_node = FdtNode("cpus")
cpus_state = FdtState(addr_cells=1, size_cells=0)
cpus_node.append(cpus_state.addrCellsProperty())
cpus_node.append(cpus_state.sizeCellsProperty())
# Used by the CLINT driver to set the timer frequency. Value taken from
# RISC-V kernel docs (Note: freedom-u540 is actually 1MHz)
cpus_node.append(FdtPropertyWords("timebase-frequency", [10000000]))
for i, core in enumerate(self.get_processor().get_cores()):
node = FdtNode(f"cpu@{i}")
node.append(FdtPropertyStrings("device_type", "cpu"))
node.append(FdtPropertyWords("reg", state.CPUAddrCells(i)))
node.append(FdtPropertyStrings("mmu-type", "riscv,sv48"))
node.append(FdtPropertyStrings("status", "okay"))
node.append(FdtPropertyStrings("riscv,isa", "rv64imafdc"))
# TODO: Should probably get this from the core.
freq = self.clk_domain.clock[0].frequency
node.append(FdtPropertyWords("clock-frequency", freq))
node.appendCompatible(["riscv"])
int_phandle = state.phandle(f"cpu@{i}.int_state")
node.appendPhandle(f"cpu@{i}")
int_node = FdtNode("interrupt-controller")
int_state = FdtState(interrupt_cells=1)
int_phandle = int_state.phandle(f"cpu@{i}.int_state")
int_node.append(int_state.interruptCellsProperty())
int_node.append(FdtProperty("interrupt-controller"))
int_node.appendCompatible("riscv,cpu-intc")
int_node.append(FdtPropertyWords("phandle", [int_phandle]))
node.append(int_node)
cpus_node.append(node)
root.append(cpus_node)
soc_node = FdtNode("soc")
soc_state = FdtState(addr_cells=2, size_cells=2)
soc_node.append(soc_state.addrCellsProperty())
soc_node.append(soc_state.sizeCellsProperty())
soc_node.append(FdtProperty("ranges"))
soc_node.appendCompatible(["simple-bus"])
# CLINT node
clint = self.platform.clint
clint_node = clint.generateBasicPioDeviceNode(
soc_state, "clint", clint.pio_addr, clint.pio_size
)
int_extended = list()
for i, core in enumerate(self.get_processor().get_cores()):
phandle = soc_state.phandle(f"cpu@{i}.int_state")
int_extended.append(phandle)
int_extended.append(0x3)
int_extended.append(phandle)
int_extended.append(0x7)
clint_node.append(
FdtPropertyWords("interrupts-extended", int_extended)
)
clint_node.appendCompatible(["riscv,clint0"])
soc_node.append(clint_node)
# PLIC node
plic = self.platform.plic
plic_node = plic.generateBasicPioDeviceNode(
soc_state, "plic", plic.pio_addr, plic.pio_size
)
int_state = FdtState(addr_cells=0, interrupt_cells=1)
plic_node.append(int_state.addrCellsProperty())
plic_node.append(int_state.interruptCellsProperty())
phandle = int_state.phandle(plic)
plic_node.append(FdtPropertyWords("phandle", [phandle]))
plic_node.append(FdtPropertyWords("riscv,ndev", [plic.n_src - 1]))
int_extended = list()
for i, core in enumerate(self.get_processor().get_cores()):
phandle = state.phandle(f"cpu@{i}.int_state")
int_extended.append(phandle)
int_extended.append(0xB)
int_extended.append(phandle)
int_extended.append(0x9)
plic_node.append(FdtPropertyWords("interrupts-extended", int_extended))
plic_node.append(FdtProperty("interrupt-controller"))
plic_node.appendCompatible(["riscv,plic0"])
soc_node.append(plic_node)
# UART node
uart = self.platform.uart
uart_node = uart.generateBasicPioDeviceNode(
soc_state, "uart", uart.pio_addr, uart.pio_size
)
uart_node.append(
FdtPropertyWords("interrupts", [self.platform.uart_int_id])
)
uart_node.append(FdtPropertyWords("clock-frequency", [0x384000]))
uart_node.append(
FdtPropertyWords("interrupt-parent", soc_state.phandle(plic))
)
uart_node.appendCompatible(["ns8250"])
soc_node.append(uart_node)
# VirtIO MMIO disk node
disk = self.disk
disk_node = disk.generateBasicPioDeviceNode(
soc_state, "virtio_mmio", disk.pio_addr, disk.pio_size
)
disk_node.append(FdtPropertyWords("interrupts", [disk.interrupt_id]))
disk_node.append(
FdtPropertyWords("interrupt-parent", soc_state.phandle(plic))
)
disk_node.appendCompatible(["virtio,mmio"])
soc_node.append(disk_node)
root.append(soc_node)
fdt = Fdt()
fdt.add_rootnode(root)
fdt.writeDtsFile(os.path.join(outdir, "device.dts"))
fdt.writeDtbFile(os.path.join(outdir, "device.dtb"))

View File

@@ -0,0 +1,164 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..resources.resource import AbstractResource
from m5.objects import (
AddrRange,
SrcClockDomain,
VoltageDomain,
Process,
SEWorkload,
IOXBar,
Port,
ClockDomain,
)
from .abstract_board import AbstractBoard
from .mem_mode import MemMode, mem_mode_to_string
from ..processors.abstract_processor import AbstractProcessor
from ..memory.abstract_memory_system import AbstractMemorySystem
from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from ..utils.override import overrides
from typing import List
class SimpleBoard(AbstractBoard):
"""
This is an incredibly simple system. It contains no I/O, and will work only
with a classic cache hierarchy setup.
**Limitations**
* Only supports SE mode
You can run a binary executable via the `set_workload` function.
"""
def __init__(
self,
clk_freq: str,
processor: AbstractProcessor,
memory: AbstractMemorySystem,
cache_hierarchy: AbstractCacheHierarchy,
exit_on_work_items: bool = False,
) -> None:
super(SimpleBoard, self).__init__(
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
# Set up the clock domain and the voltage domain.
self.clk_domain = SrcClockDomain()
self.clk_domain.clock = clk_freq
self.clk_domain.voltage_domain = VoltageDomain()
self.exit_on_work_items = exit_on_work_items
@overrides(AbstractBoard)
def get_clock_domain(self) -> ClockDomain:
return self.clk_domain
@overrides(AbstractBoard)
def connect_system_port(self, port: Port) -> None:
self.system_port = port
@overrides(AbstractBoard)
def set_mem_mode(self, mem_mode: MemMode) -> None:
self.mem_mode = mem_mode_to_string(mem_mode=mem_mode)
@overrides(AbstractBoard)
def connect_things(self) -> None:
# Before incorporating the memory, set up the memory ranges
self.setup_memory_ranges()
# Incorporate the cache hierarchy for the motherboard.
self.get_cache_hierarchy().incorporate_cache(self)
# Incorporate the processor into the motherboard.
self.get_processor().incorporate_processor(self)
# Incorporate the memory into the motherboard.
self.get_memory().incorporate_memory(self)
@overrides(AbstractBoard)
def has_io_bus(self) -> bool:
return False
@overrides(AbstractBoard)
def get_io_bus(self) -> IOXBar:
raise NotImplementedError(
"SimpleBoard does not have an IO Bus. "
"Use `has_io_bus()` to check this."
)
@overrides(AbstractBoard)
def has_dma_ports(self) -> bool:
return False
@overrides(AbstractBoard)
def get_dma_ports(self) -> List[Port]:
raise NotImplementedError(
"SimpleBoard does not have DMA Ports. "
"Use `has_dma_ports()` to check this."
)
@overrides(AbstractBoard)
def has_coherent_io(self) -> bool:
return False
@overrides(AbstractBoard)
def get_mem_side_coherent_io_port(self) -> Port:
raise NotImplementedError(
"SimpleBoard does not have any I/O ports. Use has_coherent_io to "
"check this."
)
@overrides(AbstractBoard)
def setup_memory_ranges(self) -> None:
memory = self.get_memory()
# The simple board just has one memory range that is the size of the
# memory.
self.mem_ranges = [AddrRange(memory.get_size())]
memory.set_memory_range(self.mem_ranges)
def set_workload(self, binary: AbstractResource) -> None:
"""Set up the system to run a specific binary.
**Limitations**
* Only supports single threaded applications
* Dynamically linked executables are partially supported when the host
ISA and the simulated ISA are the same.
:param binary: The resource encapsulating the binary to be run.
"""
self.workload = SEWorkload.init_compatible(binary.get_local_path())
process = Process()
process.cmd = [binary.get_local_path()]
self.get_processor().get_cores()[0].set_workload(process)

View File

@@ -0,0 +1,130 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.objects import (
SrcClockDomain,
ClockDomain,
VoltageDomain,
Port,
IOXBar,
AddrRange,
)
from .mem_mode import MemMode, mem_mode_to_string
from ..utils.override import overrides
from .abstract_board import AbstractBoard
from ..processors.abstract_processor import AbstractProcessor
from ..memory.abstract_memory_system import AbstractMemorySystem
from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from typing import List
class TestBoard(AbstractBoard):
"""This is a Testing Board used to run traffic generators on a simple
architecture.
To work as a traffic generator board, pass a generator as a processor.
"""
def __init__(
self,
clk_freq: str,
processor: AbstractProcessor,
memory: AbstractMemorySystem,
cache_hierarchy: AbstractCacheHierarchy,
):
super(TestBoard, self).__init__(
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
)
self.clk_domain = SrcClockDomain(
clock=clk_freq, voltage_domain=VoltageDomain()
)
def connect_system_port(self, port: Port) -> None:
self.system_port = port
def connect_things(self) -> None:
self.setup_memory_ranges()
self.get_cache_hierarchy().incorporate_cache(self)
self.get_processor().incorporate_processor(self)
self.get_memory().incorporate_memory(self)
def get_clock_domain(self) -> ClockDomain:
return self.clk_domain
@overrides(AbstractBoard)
def has_io_bus(self) -> bool:
return False
@overrides(AbstractBoard)
def get_io_bus(self) -> IOXBar:
raise NotImplementedError(
"The TestBoard does not have an IO Bus. "
"Use `has_io_bus()` to check this."
)
@overrides(AbstractBoard)
def get_dma_ports(self) -> List[Port]:
return False
@overrides(AbstractBoard)
def get_dma_ports(self) -> List[Port]:
raise NotImplementedError(
"The TestBoard does not have DMA Ports. "
"Use `has_dma_ports()` to check this."
)
@overrides(AbstractBoard)
def has_coherent_io(self) -> bool:
return False
@overrides(AbstractBoard)
def get_mem_side_coherent_io_port(self):
raise NotImplementedError(
"SimpleBoard does not have any I/O ports. Use has_coherent_io to "
"check this."
)
@overrides(AbstractBoard)
def set_mem_mode(self, mem_mode: MemMode) -> None:
self.mem_mode = mem_mode_to_string(mem_mode=mem_mode)
@overrides(AbstractBoard)
def setup_memory_ranges(self) -> None:
memory = self.get_memory()
# The simple board just has one memory range that is the size of the
# memory.
self.mem_ranges = [AddrRange(memory.get_size())]
memory.set_memory_range(self.mem_ranges)

View File

@@ -0,0 +1,376 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..resources.resource import AbstractResource
from ..utils.override import overrides
from .abstract_board import AbstractBoard
from ..isas import ISA
import m5
from m5.objects import (
Cache,
Pc,
AddrRange,
X86FsLinux,
Addr,
X86SMBiosBiosInformation,
X86IntelMPProcessor,
X86IntelMPIOAPIC,
X86IntelMPBus,
X86IntelMPBusHierarchy,
X86IntelMPIOIntAssignment,
X86E820Entry,
Bridge,
IOXBar,
IdeDisk,
CowDiskImage,
RawDiskImage,
BaseXBar,
Port,
)
from m5.util.convert import toMemorySize
from .simple_board import SimpleBoard
from ..processors.abstract_processor import AbstractProcessor
from ..memory.abstract_memory_system import AbstractMemorySystem
from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from ..utils.requires import requires
import os
from typing import List, Optional, Sequence
class X86Board(SimpleBoard):
"""
A board capable of full system simulation for X86.
**Limitations**
* Currently, this board's memory is hardcoded to 3GB
* Much of the I/O subsystem is hard coded
"""
def __init__(
self,
clk_freq: str,
processor: AbstractProcessor,
memory: AbstractMemorySystem,
cache_hierarchy: AbstractCacheHierarchy,
exit_on_work_items: bool = False,
) -> None:
super(X86Board, self).__init__(
clk_freq=clk_freq,
processor=processor,
memory=memory,
cache_hierarchy=cache_hierarchy,
exit_on_work_items=exit_on_work_items,
)
requires(isa_required=ISA.X86)
self.pc = Pc()
self.workload = X86FsLinux()
# North Bridge
self.iobus = IOXBar()
def _setup_io_devices(self):
""" Sets up the x86 IO devices.
Note: This is mostly copy-paste from prior X86 FS setups. Some of it
may not be documented and there may be bugs.
"""
# Constants similar to x86_traits.hh
IO_address_space_base = 0x8000000000000000
pci_config_address_space_base = 0xC000000000000000
interrupts_address_space_base = 0xA000000000000000
APIC_range_size = 1 << 12
# Setup memory system specific settings.
if self.get_cache_hierarchy().is_ruby():
self.pc.attachIO(self.get_io_bus(), [self.pc.south_bridge.ide.dma])
else:
self.bridge = Bridge(delay="50ns")
self.bridge.mem_side_port = self.get_io_bus().cpu_side_ports
self.bridge.cpu_side_port = (
self.get_cache_hierarchy().get_mem_side_port()
)
# # Constants similar to x86_traits.hh
IO_address_space_base = 0x8000000000000000
pci_config_address_space_base = 0xC000000000000000
interrupts_address_space_base = 0xA000000000000000
APIC_range_size = 1 << 12
self.bridge.ranges = [
AddrRange(0xC0000000, 0xFFFF0000),
AddrRange(
IO_address_space_base, interrupts_address_space_base - 1
),
AddrRange(pci_config_address_space_base, Addr.max),
]
self.apicbridge = Bridge(delay="50ns")
self.apicbridge.cpu_side_port = self.get_io_bus().mem_side_ports
self.apicbridge.mem_side_port = (
self.get_cache_hierarchy().get_cpu_side_port()
)
self.apicbridge.ranges = [
AddrRange(
interrupts_address_space_base,
interrupts_address_space_base
+ self.get_processor().get_num_cores() * APIC_range_size
- 1,
)
]
self.pc.attachIO(self.get_io_bus())
# Add in a Bios information structure.
self.workload.smbios_table.structures = [X86SMBiosBiosInformation()]
# Set up the Intel MP table
base_entries = []
ext_entries = []
for i in range(self.get_processor().get_num_cores()):
bp = X86IntelMPProcessor(
local_apic_id=i,
local_apic_version=0x14,
enable=True,
bootstrap=(i == 0),
)
base_entries.append(bp)
io_apic = X86IntelMPIOAPIC(
id=self.get_processor().get_num_cores(),
version=0x11,
enable=True,
address=0xFEC00000,
)
self.pc.south_bridge.io_apic.apic_id = io_apic.id
base_entries.append(io_apic)
pci_bus = X86IntelMPBus(bus_id=0, bus_type="PCI ")
base_entries.append(pci_bus)
isa_bus = X86IntelMPBus(bus_id=1, bus_type="ISA ")
base_entries.append(isa_bus)
connect_busses = X86IntelMPBusHierarchy(
bus_id=1, subtractive_decode=True, parent_bus=0
)
ext_entries.append(connect_busses)
pci_dev4_inta = X86IntelMPIOIntAssignment(
interrupt_type="INT",
polarity="ConformPolarity",
trigger="ConformTrigger",
source_bus_id=0,
source_bus_irq=0 + (4 << 2),
dest_io_apic_id=io_apic.id,
dest_io_apic_intin=16,
)
base_entries.append(pci_dev4_inta)
def assignISAInt(irq, apicPin):
assign_8259_to_apic = X86IntelMPIOIntAssignment(
interrupt_type="ExtInt",
polarity="ConformPolarity",
trigger="ConformTrigger",
source_bus_id=1,
source_bus_irq=irq,
dest_io_apic_id=io_apic.id,
dest_io_apic_intin=0,
)
base_entries.append(assign_8259_to_apic)
assign_to_apic = X86IntelMPIOIntAssignment(
interrupt_type="INT",
polarity="ConformPolarity",
trigger="ConformTrigger",
source_bus_id=1,
source_bus_irq=irq,
dest_io_apic_id=io_apic.id,
dest_io_apic_intin=apicPin,
)
base_entries.append(assign_to_apic)
assignISAInt(0, 2)
assignISAInt(1, 1)
for i in range(3, 15):
assignISAInt(i, i)
self.workload.intel_mp_table.base_entries = base_entries
self.workload.intel_mp_table.ext_entries = ext_entries
entries = [
# Mark the first megabyte of memory as reserved
X86E820Entry(addr=0, size="639kB", range_type=1),
X86E820Entry(addr=0x9FC00, size="385kB", range_type=2),
# Mark the rest of physical memory as available
X86E820Entry(
addr=0x100000,
size=f"{self.mem_ranges[0].size() - 0x100000:d}B",
range_type=1,
),
]
# Reserve the last 16kB of the 32-bit address space for m5ops
entries.append(
X86E820Entry(addr=0xFFFF0000, size="64kB", range_type=2)
)
self.workload.e820_table.entries = entries
def connect_things(self) -> None:
# This board is a bit particular about the order that things are
# connected together.
# Before incorporating the memory or creating the I/O devices figure
# out the memory ranges.
self.setup_memory_ranges()
# Set up all of the I/O before we incorporate anything else.
self._setup_io_devices()
# Incorporate the cache hierarchy for the motherboard.
self.get_cache_hierarchy().incorporate_cache(self)
# Incorporate the processor into the motherboard.
self.get_processor().incorporate_processor(self)
# Incorporate the memory into the motherboard.
self.get_memory().incorporate_memory(self)
def set_workload(
self,
kernel: AbstractResource,
disk_image: AbstractResource,
command: Optional[str] = None,
kernel_args: Optional[List[str]] = [],
):
"""Setup the full system files
See <url> for the currently tested kernels and OSes.
The command is an optional string to execute once the OS is fully
booted, assuming the disk image is setup to run `m5 readfile` after
booting.
**Limitations**
* Only supports a Linux kernel
* Disk must be configured correctly to use the command option
:param kernel: The compiled kernel binary resource
:param disk_image: A disk image resource containing the OS data. The
first partition should be the root partition.
:param command: The command(s) to run with bash once the OS is booted
:param kernel_args: Additional arguments to be passed to the kernel.
`earlyprintk=ttyS0 console=ttyS0 lpj=7999923 root=/dev/hda1` are
already passed. This parameter is used to pass additional arguments.
"""
# Set the Linux kernel to use.
self.workload.object_file = kernel.get_local_path()
# Options specified on the kernel command line.
self.workload.command_line = " ".join(
[
"earlyprintk=ttyS0",
"console=ttyS0",
"lpj=7999923",
"root=/dev/hda1",
] + kernel_args
)
# Create the Disk image SimObject.
ide_disk = IdeDisk()
ide_disk.driveID = "device0"
ide_disk.image = CowDiskImage(
child=RawDiskImage(read_only=True), read_only=False
)
ide_disk.image.child.image_file = disk_image.get_local_path()
# Attach the SimObject to the system.
self.pc.south_bridge.ide.disks = [ide_disk]
# Set the script to be passed to the simulated system to execute after
# boot.
if command:
file_name = os.path.join(m5.options.outdir, "run")
bench_file = open(file_name, "w+")
bench_file.write(command)
bench_file.close()
# Set to the system readfile
self.readfile = file_name
@overrides(AbstractBoard)
def has_io_bus(self) -> bool:
return True
@overrides(AbstractBoard)
def get_io_bus(self) -> BaseXBar:
return self.iobus
@overrides(AbstractBoard)
def has_dma_ports(self) -> bool:
return True
@overrides(AbstractBoard)
def get_dma_ports(self) -> Sequence[Port]:
return [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports]
@overrides(AbstractBoard)
def has_coherent_io(self) -> bool:
return True
@overrides(AbstractBoard)
def get_mem_side_coherent_io_port(self) -> Port:
return self.iobus.mem_side_ports
@overrides(AbstractBoard)
def setup_memory_ranges(self):
memory = self.get_memory()
if memory.get_size() > toMemorySize("3GB"):
raise Exception(
"X86Board currently only supports memory sizes up "
"to 3GB because of the I/O hole."
)
data_range = AddrRange(memory.get_size())
memory.set_memory_range([data_range])
# Add the address range for the IO
self.mem_ranges = [
data_range, # All data
AddrRange(0xC0000000, size=0x100000), # For I/0
]

View File

@@ -0,0 +1,72 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from ..boards.abstract_board import AbstractBoard
from m5.objects import SubSystem
class AbstractCacheHierarchy(SubSystem):
__metaclass__ = ABCMeta
def __init__(self):
super(AbstractCacheHierarchy, self).__init__()
"""
A Cache Hierarchy incorporates any system components which manages
communicaton between the processor and memory. E.g., Caches, the MemBus,
MMU, and the MMU Cache.
All Cache Hierarchies must have this as a base class.
"""
@abstractmethod
def incorporate_cache(self, board: AbstractBoard) -> None:
"""
Incorporates the caches into a board.
Each specific hierarchy needs to implement this function and will be
unique for each setup.
:param board: The board in which the cache heirarchy is to be
incorporated.
:type board: AbstractBoard
"""
raise NotImplementedError
@abstractmethod
def is_ruby(self) -> bool:
"""
Specifies whether this cache hierarchy is using the Ruby memory system
or not.
:returns: True if the cache hierarchy is ruby. Otherwise False.
"""
raise NotImplementedError

View File

@@ -0,0 +1,75 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# from .abstract_cache_hierarchy import AbstractCacheHierarchy
class AbstractTwoLevelCacheHierarchy:
"""
An abstract two-level hierarchy with a configurable L1 and L2 size and
associativity.
"""
def __init__(
self,
l1i_size: str,
l1i_assoc: int,
l1d_size: str,
l1d_assoc: int,
l2_size: str,
l2_assoc: int,
):
"""
:param l1i_size: The size of the L1 Instruction cache (e.g. "32kB").
:type l1i_size: str
:param l1i_assoc:
:type l1i_assoc: int
:param l1dsize: The size of the LL1 Data cache (e.g. "32kB").
:type l1dsize: str
:param l1d_assoc:
:type l1d_assoc: int
:param l2_size: The size of the L2 cache (e.g., "256kB").
:type l2_size: str
:param l2_assoc:
:type l2_assoc: int
"""
self._l1i_size = l1i_size
self._l1i_assoc = l1i_assoc
self._l1d_size = l1d_size
self._l1d_assoc = l1d_assoc
self._l2_size = l2_size
self._l2_assoc = l2_assoc

View File

@@ -0,0 +1,54 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from ...utils.override import overrides
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
from m5.objects import Port
class AbstractClassicCacheHierarchy(AbstractCacheHierarchy):
"""
All classic cache hierarchies inherit from this class. This class
provides the shared infrastructure that all classic memory system
implementations need.
"""
def __init__(self):
super(AbstractClassicCacheHierarchy, self).__init__()
@overrides(AbstractCacheHierarchy)
def is_ruby(self) -> bool:
return False
@abstractmethod
def get_mem_side_port(self) -> Port:
raise NotImplementedError
@abstractmethod
def get_cpu_side_port(self) -> Port:
raise NotImplementedError

View File

@@ -0,0 +1,60 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ....utils.override import *
from m5.objects import Cache, BasePrefetcher, StridePrefetcher
from typing import Optional, Type
class L1DCache(Cache):
"""
A simple L1 data cache with default values.
"""
def __init__(
self,
size: str,
assoc: Optional[int] = 8,
tag_latency: Optional[int] = 1,
data_latency: Optional[int] = 1,
response_latency: Optional[int] = 1,
mshrs: Optional[int] = 16,
tgts_per_mshr: Optional[int] = 20,
writeback_clean: Optional[bool] = True,
PrefetcherCls: Type[BasePrefetcher] = StridePrefetcher,
):
super(L1DCache, self).__init__()
self.size = size
self.assoc = assoc
self.tag_latency = tag_latency
self.data_latency = data_latency
self.response_latency = response_latency
self.mshrs = mshrs
self.tgts_per_mshr = tgts_per_mshr
self.writeback_clean = writeback_clean
self.prefetcher = PrefetcherCls()

View File

@@ -0,0 +1,60 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from typing import Optional, Type
from m5.objects import Cache, BasePrefetcher, StridePrefetcher
from ....utils.override import *
class L1ICache(Cache):
"""
A simple L1 instruction cache with default values.
"""
def __init__(
self,
size: str,
assoc: Optional[int] = 8,
tag_latency: Optional[int] = 1,
data_latency: Optional[int] = 1,
response_latency: Optional[int] = 1,
mshrs: Optional[int] = 16,
tgts_per_mshr: Optional[int] = 20,
writeback_clean: Optional[bool] = True,
PrefetcherCls: Type[BasePrefetcher] = StridePrefetcher,
):
super(L1ICache, self).__init__()
self.size = size
self.assoc = assoc
self.tag_latency = tag_latency
self.data_latency = data_latency
self.response_latency = response_latency
self.mshrs = mshrs
self.tgts_per_mshr = tgts_per_mshr
self.writeback_clean = writeback_clean
self.prefetcher = PrefetcherCls()

View File

@@ -0,0 +1,60 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ....utils.override import *
from m5.objects import Cache, BasePrefetcher, StridePrefetcher
from typing import Optional, Type
class L2Cache(Cache):
"""
A simple L2 Cache with default values.
"""
def __init__(
self,
size: str,
assoc: Optional[int] = 16,
tag_latency: Optional[int] = 10,
data_latency: Optional[int] = 10,
response_latency: Optional[int] = 1,
mshrs: Optional[int] = 20,
tgts_per_mshr: Optional[int] = 12,
writeback_clean: Optional[bool] = True,
PrefetcherCls: Type[BasePrefetcher] = StridePrefetcher,
):
super(L2Cache, self).__init__()
self.size = size
self.assoc = assoc
self.tag_latency = tag_latency
self.data_latency = data_latency
self.response_latency = response_latency
self.mshrs = mshrs
self.tgts_per_mshr = tgts_per_mshr
self.writeback_clean = writeback_clean
self.prefetcher = PrefetcherCls()

View File

@@ -0,0 +1,58 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ....utils.override import *
from m5.objects import Cache, BasePrefetcher, StridePrefetcher
from typing import Optional
class MMUCache(Cache):
"""
A simple Memory Management Unit (MMU) cache with default values.
"""
def __init__(
self,
size: str,
assoc: Optional[int] = 4,
tag_latency: Optional[int] = 1,
data_latency: Optional[int] = 1,
response_latency: Optional[int] = 1,
mshrs: Optional[int] = 20,
tgts_per_mshr: Optional[int] = 12,
writeback_clean: Optional[bool] = True,
):
super(MMUCache, self).__init__()
self.size = size
self.assoc = assoc
self.tag_latency = tag_latency
self.data_latency = data_latency
self.response_latency = response_latency
self.mshrs = mshrs
self.tgts_per_mshr = tgts_per_mshr
self.writeback_clean = writeback_clean

View File

@@ -0,0 +1,129 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .abstract_classic_cache_hierarchy import AbstractClassicCacheHierarchy
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
from ...boards.abstract_board import AbstractBoard
from ...isas import ISA
from ...runtime import get_runtime_isa
from m5.objects import Bridge, BaseXBar, SystemXBar, BadAddr, Port
from typing import Optional
from ...utils.override import *
class NoCache(AbstractClassicCacheHierarchy):
"""
No cache hierarchy. The CPUs are connected straight to the memory bus.
By default a SystemXBar of width 64bit is used, though this can be
configured via the constructor.
NOTE: At present this does not work with FS. The following error is
received:
```
...
build/X86/mem/snoop_filter.cc:277: panic: panic condition
(sf_item.requested & req_mask).none() occurred: SF value
0000000000000000000000000000000000000000000000000000000000000000 ...
missing the original request
Memory Usage: 3554472 KBytes
Program aborted at tick 1668400099164
--- BEGIN LIBC BACKTRACE ---
...
```
"""
@staticmethod
def _get_default_membus() -> SystemXBar:
"""
A method used to obtain the default memory bus of 64 bit in width for
the NoCache CacheHierarchy.
:returns: The default memory bus for the NoCache CacheHierarchy.
:rtype: SystemXBar
"""
membus = SystemXBar(width=64)
membus.badaddr_responder = BadAddr()
membus.default = membus.badaddr_responder.pio
return membus
def __init__(
self, membus: Optional[BaseXBar] = _get_default_membus.__func__()
) -> None:
"""
:param membus: The memory bus for this setup. This parameter is
optional and will default toa 64 bit width SystemXBar is not specified.
:type membus: Optional[BaseXBar]
"""
super(NoCache, self).__init__()
self.membus = membus
@overrides(AbstractClassicCacheHierarchy)
def get_mem_side_port(self) -> Port:
return self.membus.mem_side_ports
@overrides(AbstractClassicCacheHierarchy)
def get_cpu_side_port(self) -> Port:
return self.membus.cpu_side_ports
@overrides(AbstractCacheHierarchy)
def incorporate_cache(self, board: AbstractBoard) -> None:
if board.has_coherent_io():
self._setup_coherent_io_bridge(board)
for core in board.get_processor().get_cores():
core.connect_icache(self.membus.cpu_side_ports)
core.connect_dcache(self.membus.cpu_side_ports)
core.connect_walker_ports(
self.membus.cpu_side_ports, self.membus.cpu_side_ports
)
if get_runtime_isa() == ISA.X86:
int_req_port = self.membus.mem_side_ports
int_resp_port = self.membus.cpu_side_ports
core.connect_interrupt(int_req_port, int_resp_port)
else:
core.connect_interrupt()
# Set up the system port for functional access from the simulator.
board.connect_system_port(self.membus.cpu_side_ports)
for cntr in board.get_memory().get_memory_controllers():
cntr.port = self.membus.mem_side_ports
def _setup_coherent_io_bridge(self, board: AbstractBoard) -> None:
"""Create a bridge from I/O back to membus"""
self.iobridge = Bridge(delay="10ns", ranges=board.mem_ranges)
self.iobridge.mem_side_port = self.membus.cpu_side_ports
self.iobridge.cpu_side_port = board.get_mem_side_coherent_io_port()

View File

@@ -0,0 +1,155 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
from .abstract_classic_cache_hierarchy import AbstractClassicCacheHierarchy
from .caches.l1dcache import L1DCache
from .caches.l1icache import L1ICache
from .caches.mmu_cache import MMUCache
from ...boards.abstract_board import AbstractBoard
from ...isas import ISA
from ...runtime import get_runtime_isa
from m5.objects import Cache, BaseXBar, SystemXBar, BadAddr, Port
from ...utils.override import *
from typing import Optional
class PrivateL1CacheHierarchy(AbstractClassicCacheHierarchy):
"""
A cache setup where each core has a private L1 data and instruction Cache.
"""
@staticmethod
def _get_default_membus() -> SystemXBar:
"""
A method used to obtain the default memory bus of 64 bit in width for
the PrivateL1CacheHierarchy.
:returns: The default memory bus for the PrivateL1PrivateL2
CacheHierarchy.
"""
membus = SystemXBar(width=64)
membus.badaddr_responder = BadAddr()
membus.default = membus.badaddr_responder.pio
return membus
def __init__(
self,
l1d_size: str,
l1i_size: str,
membus: Optional[BaseXBar] = _get_default_membus.__func__(),
) -> None:
"""
:param l1d_size: The size of the L1 Data Cache (e.g., "32kB").
:param l1i_size: The size of the L1 Instruction Cache (e.g., "32kB").
:param membus: The memory bus. This parameter is optional parameter and
will default to a 64 bit width SystemXBar is not specified.
"""
AbstractClassicCacheHierarchy.__init__(self=self)
self.membus = membus
self._l1d_size = l1d_size
self._l1i_size = l1i_size
@overrides(AbstractClassicCacheHierarchy)
def get_mem_side_port(self) -> Port:
return self.membus.mem_side_ports
@overrides(AbstractClassicCacheHierarchy)
def get_cpu_side_port(self) -> Port:
return self.membus.cpu_side_ports
@overrides(AbstractCacheHierarchy)
def incorporate_cache(self, board: AbstractBoard) -> None:
# Set up the system port for functional access from the simulator.
board.connect_system_port(self.membus.cpu_side_ports)
for cntr in board.get_memory().get_memory_controllers():
cntr.port = self.membus.mem_side_ports
self.l1icaches = [
L1ICache(size=self._l1i_size)
for i in range(board.get_processor().get_num_cores())
]
self.l1dcaches = [
L1DCache(size=self._l1i_size)
for i in range(board.get_processor().get_num_cores())
]
# ITLB Page walk caches
self.iptw_caches = [
MMUCache(size="8KiB") for _ in range(board.get_processor().get_num_cores())
]
# DTLB Page walk caches
self.dptw_caches = [
MMUCache(size="8KiB") for _ in range(board.get_processor().get_num_cores())
]
if board.has_coherent_io():
self._setup_io_cache(board)
for i, cpu in enumerate(board.get_processor().get_cores()):
cpu.connect_icache(self.l1icaches[i].cpu_side)
cpu.connect_dcache(self.l1dcaches[i].cpu_side)
self.l1icaches[i].mem_side = self.membus.cpu_side_ports
self.l1dcaches[i].mem_side = self.membus.cpu_side_ports
self.iptw_caches[i].mem_side = self.membus.cpu_side_ports
self.dptw_caches[i].mem_side = self.membus.cpu_side_ports
cpu.connect_walker_ports(
self.iptw_caches[i].cpu_side, self.dptw_caches[i].cpu_side
)
if get_runtime_isa() == ISA.X86:
int_req_port = self.membus.mem_side_ports
int_resp_port = self.membus.cpu_side_ports
cpu.connect_interrupt(int_req_port, int_resp_port)
else:
cpu.connect_interrupt()
def _setup_io_cache(self, board: AbstractBoard) -> None:
"""Create a cache for coherent I/O connections"""
self.iocache = Cache(
assoc=8,
tag_latency=50,
data_latency=50,
response_latency=50,
mshrs=20,
size="1kB",
tgts_per_mshr=12,
addr_ranges=board.mem_ranges,
)
self.iocache.mem_side = self.membus.cpu_side_ports
self.iocache.cpu_side = board.get_mem_side_coherent_io_port()

View File

@@ -0,0 +1,192 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
from .abstract_classic_cache_hierarchy import AbstractClassicCacheHierarchy
from ..abstract_two_level_cache_hierarchy import AbstractTwoLevelCacheHierarchy
from .caches.l1dcache import L1DCache
from .caches.l1icache import L1ICache
from .caches.l2cache import L2Cache
from .caches.mmu_cache import MMUCache
from ...boards.abstract_board import AbstractBoard
from ...isas import ISA
from ...runtime import get_runtime_isa
from m5.objects import Cache, L2XBar, BaseXBar, SystemXBar, BadAddr, Port
from ...utils.override import *
from typing import Optional
class PrivateL1PrivateL2CacheHierarchy(
AbstractClassicCacheHierarchy, AbstractTwoLevelCacheHierarchy
):
"""
A cache setup where each core has a private L1 Data and Instruction Cache,
and a private L2 cache.
"""
@staticmethod
def _get_default_membus() -> SystemXBar:
"""
A method used to obtain the default memory bus of 64 bit in width for
the PrivateL1PrivateL2 CacheHierarchy.
:returns: The default memory bus for the PrivateL1PrivateL2
CacheHierarchy.
:rtype: SystemXBar
"""
membus = SystemXBar(width=64)
membus.badaddr_responder = BadAddr()
membus.default = membus.badaddr_responder.pio
return membus
def __init__(
self,
l1d_size: str,
l1i_size: str,
l2_size: str,
membus: Optional[BaseXBar] = _get_default_membus.__func__(),
) -> None:
"""
:param l1d_size: The size of the L1 Data Cache (e.g., "32kB").
:type l1d_size: str
:param l1i_size: The size of the L1 Instruction Cache (e.g., "32kB").
:type l1i_size: str
:param l2_size: The size of the L2 Cache (e.g., "256kB").
:type l2_size: str
:param membus: The memory bus. This parameter is optional parameter and
will default to a 64 bit width SystemXBar is not specified.
:type membus: Optional[BaseXBar]
"""
AbstractClassicCacheHierarchy.__init__(self=self)
AbstractTwoLevelCacheHierarchy.__init__(
self,
l1i_size=l1i_size,
l1i_assoc=8,
l1d_size=l1d_size,
l1d_assoc=8,
l2_size=l2_size,
l2_assoc=4,
)
self.membus = membus
@overrides(AbstractClassicCacheHierarchy)
def get_mem_side_port(self) -> Port:
return self.membus.mem_side_ports
@overrides(AbstractClassicCacheHierarchy)
def get_cpu_side_port(self) -> Port:
return self.membus.cpu_side_ports
@overrides(AbstractCacheHierarchy)
def incorporate_cache(self, board: AbstractBoard) -> None:
# Set up the system port for functional access from the simulator.
board.connect_system_port(self.membus.cpu_side_ports)
for cntr in board.get_memory().get_memory_controllers():
cntr.port = self.membus.mem_side_ports
self.l1icaches = [
L1ICache(size=self._l1i_size)
for i in range(board.get_processor().get_num_cores())
]
self.l1dcaches = [
L1DCache(size=self._l1i_size)
for i in range(board.get_processor().get_num_cores())
]
self.l2buses = [
L2XBar() for i in range(board.get_processor().get_num_cores())
]
self.l2caches = [
L2Cache(size=self._l2_size)
for i in range(board.get_processor().get_num_cores())
]
# ITLB Page walk caches
self.iptw_caches = [
MMUCache(size='8KiB')
for _ in range(board.get_processor().get_num_cores())
]
# DTLB Page walk caches
self.dptw_caches = [
MMUCache(size='8KiB')
for _ in range(board.get_processor().get_num_cores())
]
if board.has_coherent_io():
self._setup_io_cache(board)
for i, cpu in enumerate(board.get_processor().get_cores()):
cpu.connect_icache(self.l1icaches[i].cpu_side)
cpu.connect_dcache(self.l1dcaches[i].cpu_side)
self.l1icaches[i].mem_side = self.l2buses[i].cpu_side_ports
self.l1dcaches[i].mem_side = self.l2buses[i].cpu_side_ports
self.iptw_caches[i].mem_side = self.l2buses[i].cpu_side_ports
self.dptw_caches[i].mem_side = self.l2buses[i].cpu_side_ports
self.l2buses[i].mem_side_ports = self.l2caches[i].cpu_side
self.membus.cpu_side_ports = self.l2caches[i].mem_side
cpu.connect_walker_ports(
self.iptw_caches[i].cpu_side, self.dptw_caches[i].cpu_side
)
if get_runtime_isa() == ISA.X86:
int_req_port = self.membus.mem_side_ports
int_resp_port = self.membus.cpu_side_ports
cpu.connect_interrupt(int_req_port, int_resp_port)
else:
cpu.connect_interrupt()
def _setup_io_cache(self, board: AbstractBoard) -> None:
"""Create a cache for coherent I/O connections"""
self.iocache = Cache(
assoc=8,
tag_latency=50,
data_latency=50,
response_latency=50,
mshrs=20,
size="1kB",
tgts_per_mshr=12,
addr_ranges=board.mem_ranges,
)
self.iocache.mem_side = self.membus.cpu_side_ports
self.iocache.cpu_side = board.get_mem_side_coherent_io_port()

View File

@@ -0,0 +1,42 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ...utils.override import overrides
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
class AbstractRubyCacheHierarchy(AbstractCacheHierarchy):
"""
All Ruby-based cache hierarchies inherit from this class. This class
provides the shared infrastructure that all Ruby protocols need.
"""
def __init__(self):
super(AbstractRubyCacheHierarchy, self).__init__()
@overrides(AbstractCacheHierarchy)
def is_ruby(self) -> bool:
return True

View File

@@ -0,0 +1,51 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from m5.objects import Directory_Controller
class AbstractDirectory(Directory_Controller):
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
def __init__(self, network, cache_line_size):
""" """
super(AbstractDirectory, self).__init__()
self.version = self.versionCount()
self._cache_line_size = cache_line_size
self.connectQueues(network)
@abstractmethod
def connectQueues(self, network):
"""Connect all of the queues for this controller."""
raise NotImplementedError

View File

@@ -0,0 +1,50 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from m5.objects import DMA_Controller
class AbstractDMAController(DMA_Controller):
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
def __init__(self, network, cache_line_size):
super(AbstractDMAController, self).__init__()
self.version = self.versionCount()
self._cache_line_size = cache_line_size
self.connectQueues(network)
@abstractmethod
def connectQueues(self, network):
"""Connect all of the queues for this controller."""
raise NotImplementedError

View File

@@ -0,0 +1,76 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from ....isas import ISA
from ....processors.cpu_types import CPUTypes
from ....processors.abstract_core import AbstractCore
from m5.objects import L1Cache_Controller
import math
class AbstractL1Cache(L1Cache_Controller):
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
# TODO: I don't love that we have to pass in the cache line size.
# However, we need some way to set the index bits
def __init__(self, network, cache_line_size):
""" """
super(AbstractL1Cache, self).__init__()
self.version = self.versionCount()
self._cache_line_size = cache_line_size
self.connectQueues(network)
def getBlockSizeBits(self):
bits = int(math.log(self._cache_line_size, 2))
if 2 ** bits != self._cache_line_size.value:
raise Exception("Cache line size not a power of 2!")
return bits
def sendEvicts(self, core: AbstractCore, target_isa: ISA):
"""True if the CPU model or ISA requires sending evictions from caches
to the CPU. Two scenarios warrant forwarding evictions to the CPU:
1. The O3 model must keep the LSQ coherent with the caches
2. The x86 mwait instruction is built on top of coherence
3. The local exclusive monitor in ARM systems
"""
if core.get_type() is CPUTypes.O3 or target_isa in (ISA.X86, ISA.ARM):
return True
return False
@abstractmethod
def connectQueues(self, network):
"""Connect all of the queues for this controller."""
raise NotImplementedError

View File

@@ -0,0 +1,51 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import abstractmethod
from m5.objects import L2Cache_Controller
class AbstractL2Cache(L2Cache_Controller):
_version = 0
@classmethod
def versionCount(cls):
cls._version += 1 # Use count for this particular type
return cls._version - 1
def __init__(self, network, cache_line_size):
super(AbstractL2Cache, self).__init__()
self.version = self.versionCount()
self._cache_line_size = cache_line_size
self.connectQueues(network)
@abstractmethod
def connectQueues(self, network):
"""Connect all of the queues for this controller."""
raise NotImplementedError

View File

@@ -0,0 +1,54 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .....utils.override import overrides
from ..abstract_directory import AbstractDirectory
from m5.objects import (
MessageBuffer,
RubyDirectoryMemory,
)
class Directory(AbstractDirectory):
def __init__(self, network, cache_line_size, mem_range, port):
super(Directory, self).__init__(network, cache_line_size)
self.addr_ranges = [mem_range]
self.directory = RubyDirectoryMemory()
# Connect this directory to the memory side.
self.memory_out_port = port
@overrides(AbstractDirectory)
def connectQueues(self, network):
self.requestToDir = MessageBuffer()
self.requestToDir.in_port = network.out_port
self.responseToDir = MessageBuffer()
self.responseToDir.in_port = network.out_port
self.responseFromDir = MessageBuffer()
self.responseFromDir.out_port = network.in_port
self.requestToMemory = MessageBuffer()
self.responseFromMemory = MessageBuffer()

View File

@@ -0,0 +1,43 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .....utils.override import overrides
from ..abstract_dma_controller import AbstractDMAController
from m5.objects import MessageBuffer
class DMAController(AbstractDMAController):
def __init__(self, network, cache_line_size):
super(DMAController, self).__init__(network, cache_line_size)
@overrides(AbstractDMAController)
def connectQueues(self, network):
self.mandatoryQueue = MessageBuffer()
self.responseFromDir = MessageBuffer(ordered=True)
self.responseFromDir.in_port = network.out_port
self.requestToDir = MessageBuffer()
self.requestToDir.out_port = network.in_port

View File

@@ -0,0 +1,96 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .....processors.abstract_core import AbstractCore
from .....isas import ISA
from ..abstract_l1_cache import AbstractL1Cache
from .....utils.override import *
from m5.objects import (
MessageBuffer,
RubyPrefetcher,
RubyCache,
ClockDomain,
)
import math
class L1Cache(AbstractL1Cache):
def __init__(
self,
l1i_size,
l1i_assoc,
l1d_size,
l1d_assoc,
network,
core: AbstractCore,
num_l2Caches,
cache_line_size,
target_isa: ISA,
clk_domain: ClockDomain,
):
"""Creating L1 cache controller. Consist of both instruction
and data cache.
"""
super(L1Cache, self).__init__(network, cache_line_size)
# This is the cache memory object that stores the cache data and tags
self.L1Icache = RubyCache(
size=l1i_size,
assoc=l1i_assoc,
start_index_bit=self.getBlockSizeBits(),
is_icache=True,
)
self.L1Dcache = RubyCache(
size=l1d_size,
assoc=l1d_assoc,
start_index_bit=self.getBlockSizeBits(),
is_icache=False,
)
self.l2_select_num_bits = int(math.log(num_l2Caches, 2))
self.clk_domain = clk_domain
self.prefetcher = RubyPrefetcher()
self.send_evictions = self.sendEvicts(core=core, target_isa=target_isa)
self.transitions_per_cycle = 4
self.enable_prefetch = False
@overrides(AbstractL1Cache)
def connectQueues(self, network):
self.mandatoryQueue = MessageBuffer()
self.requestFromL1Cache = MessageBuffer()
self.requestFromL1Cache.out_port = network.in_port
self.responseFromL1Cache = MessageBuffer()
self.responseFromL1Cache.out_port = network.in_port
self.unblockFromL1Cache = MessageBuffer()
self.unblockFromL1Cache.out_port = network.in_port
self.optionalQueue = MessageBuffer()
self.requestToL1Cache = MessageBuffer()
self.requestToL1Cache.in_port = network.out_port
self.responseToL1Cache = MessageBuffer()
self.responseToL1Cache.in_port = network.out_port

View File

@@ -0,0 +1,68 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..abstract_l2_cache import AbstractL2Cache
from .....utils.override import *
from m5.objects import MessageBuffer, RubyCache
import math
class L2Cache(AbstractL2Cache):
def __init__(
self, l2_size, l2_assoc, network, num_l2Caches, cache_line_size
):
super(L2Cache, self).__init__(network, cache_line_size)
# This is the cache memory object that stores the cache data and tags
self.L2cache = RubyCache(
size=l2_size,
assoc=l2_assoc,
start_index_bit=self.getIndexBit(num_l2Caches),
)
self.transitions_per_cycle = "4"
def getIndexBit(self, num_l2caches):
l2_bits = int(math.log(num_l2caches, 2))
bits = int(math.log(self._cache_line_size, 2)) + l2_bits
return bits
@overrides(AbstractL2Cache)
def connectQueues(self, network):
self.DirRequestFromL2Cache = MessageBuffer()
self.DirRequestFromL2Cache.out_port = network.in_port
self.L1RequestFromL2Cache = MessageBuffer()
self.L1RequestFromL2Cache.out_port = network.in_port
self.responseFromL2Cache = MessageBuffer()
self.responseFromL2Cache.out_port = network.in_port
self.unblockToL2Cache = MessageBuffer()
self.unblockToL2Cache.in_port = network.out_port
self.L1RequestToL2Cache = MessageBuffer()
self.L1RequestToL2Cache.in_port = network.out_port
self.responseToL2Cache = MessageBuffer()
self.responseToL2Cache.in_port = network.out_port

View File

@@ -0,0 +1,64 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..abstract_directory import AbstractDirectory
from .....utils.override import overrides
from m5.objects import (
MessageBuffer,
RubyDirectoryMemory,
)
class Directory(AbstractDirectory):
"""
The directory controller for the MI_Example cache hierarchy.
"""
def __init__(self, network, cache_line_size, mem_range, port):
super(Directory, self).__init__(network, cache_line_size)
self.addr_ranges = [mem_range]
self.directory = RubyDirectoryMemory()
# Connect this directory to the memory side.
self.memory_out_port = port
@overrides(AbstractDirectory)
def connectQueues(self, network):
self.requestToDir = MessageBuffer(ordered=True)
self.requestToDir.in_port = network.out_port
self.dmaRequestToDir = MessageBuffer(ordered=True)
self.dmaRequestToDir.in_port = network.out_port
self.responseFromDir = MessageBuffer()
self.responseFromDir.out_port = network.in_port
self.dmaResponseFromDir = MessageBuffer(ordered=True)
self.dmaResponseFromDir.out_port = network.in_port
self.forwardFromDir = MessageBuffer()
self.forwardFromDir.out_port = network.in_port
self.requestToMemory = MessageBuffer()
self.responseFromMemory = MessageBuffer()

View File

@@ -0,0 +1,48 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..abstract_dma_controller import AbstractDMAController
from .....utils.override import overrides
from m5.objects import MessageBuffer
class DMAController(AbstractDMAController):
"""
A DMA Controller for use in the MI_Example cache hierarchy setup.
"""
class DMAController(AbstractDMAController):
def __init__(self, network, cache_line_size):
super(DMAController, self).__init__(network, cache_line_size)
@overrides(AbstractDMAController)
def connectQueues(self, network):
self.mandatoryQueue = MessageBuffer()
self.requestToDir = MessageBuffer()
self.requestToDir.out_port = network.in_port
self.responseFromDir = MessageBuffer(ordered=True)
self.responseFromDir.in_port = network.out_port

View File

@@ -0,0 +1,69 @@
# Copyright (c) 2021 The Regents of the University of California
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .....utils.override import overrides
from .....processors.abstract_core import AbstractCore
from .....isas import ISA
from ..abstract_l1_cache import AbstractL1Cache
from m5.objects import (
MessageBuffer,
RubyCache,
ClockDomain,
)
class L1Cache(AbstractL1Cache):
def __init__(
self,
size: str,
assoc: int,
network,
core: AbstractCore,
cache_line_size,
target_isa: ISA,
clk_domain: ClockDomain,
):
super(L1Cache, self).__init__(network, cache_line_size)
self.cacheMemory = RubyCache(
size=size, assoc=assoc, start_index_bit=self.getBlockSizeBits()
)
self.clk_domain = clk_domain
self.send_evictions = self.sendEvicts(core=core, target_isa=target_isa)
@overrides(AbstractL1Cache)
def connectQueues(self, network):
self.mandatoryQueue = MessageBuffer()
self.requestFromCache = MessageBuffer(ordered=True)
self.requestFromCache.out_port = network.in_port
self.responseFromCache = MessageBuffer(ordered=True)
self.responseFromCache.out_port = network.in_port
self.forwardToCache = MessageBuffer(ordered=True)
self.forwardToCache.in_port = network.out_port
self.responseToCache = MessageBuffer(ordered=True)
self.responseToCache.in_port = network.out_port

View File

@@ -0,0 +1,200 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .abstract_ruby_cache_hierarchy import AbstractRubyCacheHierarchy
from ..abstract_two_level_cache_hierarchy import AbstractTwoLevelCacheHierarchy
from ...coherence_protocol import CoherenceProtocol
from ...isas import ISA
from ...boards.abstract_board import AbstractBoard
from ...runtime import get_runtime_isa
from ...utils.requires import requires
from .topologies.simple_pt2pt import SimplePt2Pt
from .caches.mesi_two_level.l1_cache import L1Cache
from .caches.mesi_two_level.l2_cache import L2Cache
from .caches.mesi_two_level.directory import Directory
from .caches.mesi_two_level.dma_controller import DMAController
from m5.objects import (
RubySystem,
RubySequencer,
DMASequencer,
RubyPortProxy,
)
class MESITwoLevelCacheHierarchy(
AbstractRubyCacheHierarchy, AbstractTwoLevelCacheHierarchy
):
"""A two level private L1 shared L2 MESI hierarchy.
In addition to the normal two level parameters, you can also change the
number of L2 banks in this protocol.
The on-chip network is a point-to-point all-to-all simple network.
"""
def __init__(
self,
l1i_size: str,
l1i_assoc: str,
l1d_size: str,
l1d_assoc: str,
l2_size: str,
l2_assoc: str,
num_l2_banks: int,
):
AbstractRubyCacheHierarchy.__init__(self=self)
AbstractTwoLevelCacheHierarchy.__init__(
self,
l1i_size=l1i_size,
l1i_assoc=l1i_assoc,
l1d_size=l1d_size,
l1d_assoc=l1d_assoc,
l2_size=l2_size,
l2_assoc=l2_assoc,
)
self._num_l2_banks = num_l2_banks
def incorporate_cache(self, board: AbstractBoard) -> None:
requires(coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL)
cache_line_size = board.get_cache_line_size()
self.ruby_system = RubySystem()
# MESI_Two_Level needs 5 virtual networks
self.ruby_system.number_of_virtual_networks = 5
self.ruby_system.network = SimplePt2Pt(self.ruby_system)
self.ruby_system.network.number_of_virtual_networks = 5
self._l1_controllers = []
for i, core in enumerate(board.get_processor().get_cores()):
cache = L1Cache(
self._l1i_size,
self._l1i_assoc,
self._l1d_size,
self._l1d_assoc,
self.ruby_system.network,
core,
self._num_l2_banks,
cache_line_size,
get_runtime_isa(),
board.get_clock_domain(),
)
if board.has_io_bus():
cache.sequencer = RubySequencer(
version=i,
dcache=cache.L1Dcache,
clk_domain=cache.clk_domain,
pio_request_port=board.get_io_bus().cpu_side_ports,
mem_request_port=board.get_io_bus().cpu_side_ports,
pio_response_port=board.get_io_bus().mem_side_ports,
)
else:
cache.sequencer = RubySequencer(
version=i,
dcache=cache.L1Dcache,
clk_domain=cache.clk_domain,
)
cache.ruby_system = self.ruby_system
core.connect_icache(cache.sequencer.in_ports)
core.connect_dcache(cache.sequencer.in_ports)
core.connect_walker_ports(
cache.sequencer.in_ports, cache.sequencer.in_ports
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
int_req_port = cache.sequencer.interrupt_out_port
int_resp_port = cache.sequencer.in_ports
core.connect_interrupt(int_req_port, int_resp_port)
self._l1_controllers.append(cache)
self._l2_controllers = [
L2Cache(
self._l2_size,
self._l2_assoc,
self.ruby_system.network,
self._num_l2_banks,
cache_line_size,
)
for _ in range(self._num_l2_banks)
]
# TODO: Make this prettier: The problem is not being able to proxy
# the ruby system correctly
for cache in self._l2_controllers:
cache.ruby_system = self.ruby_system
self._directory_controllers = [
Directory(self.ruby_system.network, cache_line_size, range, port)
for range, port in board.get_memory().get_mem_ports()
]
# TODO: Make this prettier: The problem is not being able to proxy
# the ruby system correctly
for dir in self._directory_controllers:
dir.ruby_system = self.ruby_system
dma_ports = board.get_dma_ports()
self._dma_controllers = []
for i, port in enumerate(dma_ports):
ctrl = DMAController(self.ruby_system.network, cache_line_size)
ctrl.dma_sequencer = DMASequencer(version=i, in_ports=port)
self._dma_controllers.append(ctrl)
ctrl.ruby_system = self.ruby_system
self.ruby_system.num_of_sequencers = len(self._l1_controllers) + len(
self._dma_controllers
)
self.ruby_system.l1_controllers = self._l1_controllers
self.ruby_system.l2_controllers = self._l2_controllers
self.ruby_system.directory_controllers = self._directory_controllers
if len(self._dma_controllers) != 0:
self.ruby_system.dma_controllers = self._dma_controllers
# Create the network and connect the controllers.
self.ruby_system.network.connectControllers(
self._l1_controllers
+ self._l2_controllers
+ self._directory_controllers
+ self._dma_controllers
)
self.ruby_system.network.setup_buffers()
# Set up a proxy port for the system_port. Used for load binaries and
# other functional-only things.
self.ruby_system.sys_port_proxy = RubyPortProxy()
board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports)

View File

@@ -0,0 +1,184 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .caches.mi_example.l1_cache import L1Cache
from .caches.mi_example.dma_controller import DMAController
from .caches.mi_example.directory import Directory
from .topologies.simple_pt2pt import SimplePt2Pt
from .abstract_ruby_cache_hierarchy import AbstractRubyCacheHierarchy
from ..abstract_cache_hierarchy import AbstractCacheHierarchy
from ...boards.abstract_board import AbstractBoard
from ...coherence_protocol import CoherenceProtocol
from ...isas import ISA
from ...utils.override import overrides
from ...runtime import get_runtime_isa
from ...utils.requires import requires
from m5.objects import (
RubySystem,
RubySequencer,
DMASequencer,
RubyPortProxy,
)
class MIExampleCacheHierarchy(AbstractRubyCacheHierarchy):
"""
The MI_Example cache hierarchy creates a Ruby cache for each code in a
simple point-to-point topology.
"""
def __init__(
self,
size: str,
assoc: str,
):
"""
:param size: The size of each cache in the heirarchy.
:param assoc: The associativity of each cache.
"""
super().__init__()
self._size = size
self._assoc = assoc
@overrides(AbstractCacheHierarchy)
def incorporate_cache(self, board: AbstractBoard) -> None:
requires(coherence_protocol_required=CoherenceProtocol.MI_EXAMPLE)
self.ruby_system = RubySystem()
# Ruby's global network.
self.ruby_system.network = SimplePt2Pt(self.ruby_system)
# MI Example users 5 virtual networks.
self.ruby_system.number_of_virtual_networks = 5
self.ruby_system.network.number_of_virtual_networks = 5
# There is a single global list of all of the controllers to make it
# easier to connect everything to the global network. This can be
# customized depending on the topology/network requirements.
# Create one controller for each L1 cache (and the cache mem obj.)
# Create a single directory controller (Really the memory cntrl).
self._controllers = []
for i, core in enumerate(board.get_processor().get_cores()):
cache = L1Cache(
size=self._size,
assoc=self._assoc,
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
clk_domain=board.get_clock_domain(),
)
if board.has_io_bus():
cache.sequencer = RubySequencer(
version=i,
dcache=cache.cacheMemory,
clk_domain=cache.clk_domain,
pio_request_port=board.get_io_bus().cpu_side_ports,
mem_request_port=board.get_io_bus().cpu_side_ports,
pio_response_port=board.get_io_bus().mem_side_ports,
)
else:
cache.sequencer = RubySequencer(
version=i,
dcache=cache.L1Dcache,
clk_domain=cache.clk_domain,
)
cache.ruby_system = self.ruby_system
core.connect_icache(cache.sequencer.in_ports)
core.connect_dcache(cache.sequencer.in_ports)
core.connect_walker_ports(
cache.sequencer.in_ports, cache.sequencer.in_ports
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
int_req_port = cache.sequencer.interrupt_out_port
int_resp_port = cache.sequencer.in_ports
core.connect_interrupt(int_req_port, int_resp_port)
else:
core.connect_interrupt()
cache.ruby_system = self.ruby_system
self._controllers.append(cache)
# Create the directory controllers
self._directory_controllers = []
for range, port in board.get_memory().get_mem_ports():
dir = Directory(
self.ruby_system.network,
board.get_cache_line_size(),
range,
port,
)
dir.ruby_system = self.ruby_system
self._directory_controllers.append(dir)
# Create the DMA Controllers, if required.
self._dma_controllers = []
if board.has_dma_ports():
dma_ports = board.get_dma_ports()
for i, port in enumerate(dma_ports):
ctrl = DMAController(
self.ruby_system.network, board.get_cache_line_size()
)
ctrl.dma_sequencer = DMASequencer(version=i, in_ports=port)
ctrl.ruby_system = self.ruby_system
ctrl.dma_sequencer.ruby_system = self.ruby_system
self._dma_controllers.append(ctrl)
self.ruby_system.num_of_sequencers = len(self._controllers) + len(
self._dma_controllers
)
# Connect the controllers.
self.ruby_system.controllers = self._controllers
self.ruby_system.directory_controllers = self._directory_controllers
if len(self._dma_controllers) != 0:
self.ruby_system.dma_controllers = self._dma_controllers
self.ruby_system.network.connectControllers(
self._controllers
+ self._directory_controllers
+ self._dma_controllers
)
self.ruby_system.network.setup_buffers()
# Set up a proxy port for the system_port. Used for load binaries and
# other functional-only things.
self.ruby_system.sys_port_proxy = RubyPortProxy()
board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports)

View File

@@ -0,0 +1,67 @@
# Copyright (c) 2021 The Regents of the University of California.
# All Rights Reserved
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.objects import SimpleNetwork, Switch, SimpleExtLink, SimpleIntLink
class SimplePt2Pt(SimpleNetwork):
"""A simple point-to-point network. This doesn't not use garnet."""
def __init__(self, ruby_system):
super(SimplePt2Pt, self).__init__()
self.netifs = []
# TODO: These should be in a base class
# https://gem5.atlassian.net/browse/GEM5-1039
self.ruby_system = ruby_system
def connectControllers(self, controllers):
"""Connect all of the controllers to routers and connec the routers
together in a point-to-point network.
"""
# Create one router/switch per controller in the system
self.routers = [Switch(router_id=i) for i in range(len(controllers))]
# Make a link from each controller to the router. The link goes
# externally to the network.
self.ext_links = [
SimpleExtLink(link_id=i, ext_node=c, int_node=self.routers[i])
for i, c in enumerate(controllers)
]
# Make an "internal" link (internal to the network) between every pair
# of routers.
link_count = 0
int_links = []
for ri in self.routers:
for rj in self.routers:
if ri == rj:
continue # Don't connect a router to itself!
link_count += 1
int_links.append(
SimpleIntLink(link_id=link_count, src_node=ri, dst_node=rj)
)
self.int_links = int_links

View File

@@ -0,0 +1,65 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
Specifies the coherence protocol enum
"""
from enum import Enum
class CoherenceProtocol(Enum):
MESI_THREE_LEVEL = 1
MESI_THREE_LEVEL_HTM = 2
ARM_MOESI_HAMMER = 3
GARNET_STANDALONE = 4
MESI_TWO_LEVEL = 5
MOESI_CMP_DIRECTORY = 6
MOESI_CMP_TOKEN = 7
MOESI_AMD_BASE = 8
MI_EXAMPLE = 9
GPU_VIPER = 10
CHI = 11
def is_ruby(protocol: CoherenceProtocol) -> bool:
"""Specifies if a given protocol is Ruby or not
:returns: True if the given protocol is Ruby, otherwise false
"""
ruby = (
CoherenceProtocol.MESI_THREE_LEVEL,
CoherenceProtocol.MESI_THREE_LEVEL_HTM,
CoherenceProtocol.ARM_MOESI_HAMMER,
CoherenceProtocol.GARNET_STANDALONE,
CoherenceProtocol.MESI_TWO_LEVEL,
CoherenceProtocol.MOESI_CMP_DIRECTORY,
CoherenceProtocol.MOESI_CMP_TOKEN,
CoherenceProtocol.MOESI_AMD_BASE,
CoherenceProtocol.GPU_VIPER,
)
return protocol in ruby

View File

@@ -0,0 +1,41 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
Specifies the ISA enum
"""
from enum import Enum
class ISA(Enum):
X86 = 1
RISCV = 2
ARM = 3
MIPS = 4
POWER = 5
SPARC = 6
NULL = 7

View File

@@ -0,0 +1,73 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from typing import Tuple, Sequence, List
from ..boards.abstract_board import AbstractBoard
from m5.objects import AddrRange, Port, SubSystem, MemCtrl
class AbstractMemorySystem(SubSystem):
__metaclass__ = ABCMeta
def __init__(self) -> None:
super(AbstractMemorySystem, self).__init__()
@abstractmethod
def incorporate_memory(self, board: AbstractBoard) -> None:
"""This function completes all of the necessary steps to add this
memory system to the board."""
raise NotImplementedError
@abstractmethod
def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
"""Get the ports to connect this memory system to the cache"""
raise NotImplementedError
@abstractmethod
def get_memory_controllers(self) -> List[MemCtrl]:
"""Get all of the memory controllers in this memory system"""
raise NotImplementedError
@abstractmethod
def get_size(self) -> int:
"""Returns the total size of the memory system"""
raise NotImplementedError
@abstractmethod
def set_memory_range(self, ranges: List[AddrRange]) -> None:
"""Set the total range for this memory system
May pass multiple non-overlapping ranges. The total size of the ranges
should match the size of the memory.
If this memory system is incompatible with the ranges, an exception
will be raised.
"""
raise NotImplementedError

View File

@@ -0,0 +1,166 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for DDR3 memories
These memory "interfaces" contain the timing, energy, etc. parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class DDR3_1600_8x8(DRAMInterface):
"""
A single DDR3-1600 x64 channel (one command and address bus), with
timings based on a DDR3-1600 4 Gbit datasheet (Micron MT41J512M8) in
an 8x8 configuration.
"""
# size of device in bytes
device_size = "512MiB"
# 8x8 configuration, 8 devices each with an 8-bit interface
device_bus_width = 8
# DDR3 is a BL8 device
burst_length = 8
# Each device has a page (row buffer) size of 1 Kbyte (1K columns x8)
device_rowbuffer_size = "1KiB"
# 8x8 configuration, so 8 devices
devices_per_rank = 8
# Use two ranks
ranks_per_channel = 2
# DDR3 has 8 banks in all configurations
banks_per_rank = 8
# 800 MHz
tCK = "1.25ns"
# 8 beats across an x64 interface translates to 4 clocks @ 800 MHz
tBURST = "5ns"
# DDR3-1600 11-11-11
tRCD = "13.75ns"
tCL = "13.75ns"
tRP = "13.75ns"
tRAS = "35ns"
tRRD = "6ns"
tXAW = "30ns"
activation_limit = 4
tRFC = "260ns"
tWR = "15ns"
# Greater of 4 CK or 7.5 ns
tWTR = "7.5ns"
# Greater of 4 CK or 7.5 ns
tRTP = "7.5ns"
# Default same rank rd-to-wr bus turnaround to 2 CK, @800 MHz = 2.5 ns
tRTW = "2.5ns"
# Default different rank bus delay to 2 CK, @800 MHz = 2.5 ns
tCS = "2.5ns"
# <=85C, half for >85C
tREFI = "7.8us"
# active powerdown and precharge powerdown exit time
tXP = "6ns"
# self refresh exit time
tXS = "270ns"
# Current values from datasheet Die Rev E,J
IDD0 = "55mA"
IDD2N = "32mA"
IDD3N = "38mA"
IDD4W = "125mA"
IDD4R = "157mA"
IDD5 = "235mA"
IDD3P1 = "38mA"
IDD2P1 = "32mA"
IDD6 = "20mA"
VDD = "1.5V"
class DDR3_2133_8x8(DDR3_1600_8x8):
"""
A single DDR3-2133 x64 channel refining a selected subset of the
options for the DDR-1600 configuration, based on the same DDR3-1600
4 Gbit datasheet (Micron MT41J512M8). Most parameters are kept
consistent across the two configurations.
"""
# 1066 MHz
tCK = "0.938ns"
# 8 beats across an x64 interface translates to 4 clocks @ 1066 MHz
tBURST = "3.752ns"
# DDR3-2133 14-14-14
tRCD = "13.09ns"
tCL = "13.09ns"
tRP = "13.09ns"
tRAS = "33ns"
tRRD = "5ns"
tXAW = "25ns"
# Current values from datasheet
IDD0 = "70mA"
IDD2N = "37mA"
IDD3N = "44mA"
IDD4W = "157mA"
IDD4R = "191mA"
IDD5 = "250mA"
IDD3P1 = "44mA"
IDD2P1 = "43mA"
IDD6 = "20mA"
VDD = "1.5V"

View File

@@ -0,0 +1,245 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for DDR4 memories
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class DDR4_2400_16x4(DRAMInterface):
"""
A single DDR4-2400 x64 channel (one command and address bus), with
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A2G4)
in an 16x4 configuration.
Total channel capacity is 32GiB
16 devices/rank * 2 ranks/channel * 1GiB/device = 32GiB/channel
"""
# size of device
device_size = "1GiB"
# 16x4 configuration, 16 devices each with a 4-bit interface
device_bus_width = 4
# DDR4 is a BL8 device
burst_length = 8
# Each device has a page (row buffer) size of 512 byte (1K columns x4)
device_rowbuffer_size = "512B"
# 16x4 configuration, so 16 devices
devices_per_rank = 16
# Match our DDR3 configurations which is dual rank
ranks_per_channel = 2
# DDR4 has 2 (x16) or 4 (x4 and x8) bank groups
# Set to 4 for x4 case
bank_groups_per_rank = 4
# DDR4 has 16 banks(x4,x8) and 8 banks(x16) (4 bank groups in all
# configurations). Currently we do not capture the additional
# constraints incurred by the bank groups
banks_per_rank = 16
# override the default buffer sizes and go for something larger to
# accommodate the larger bank count
write_buffer_size = 128
read_buffer_size = 64
# 1200 MHz
tCK = "0.833ns"
# 8 beats across an x64 interface translates to 4 clocks @ 1200 MHz
# tBURST is equivalent to the CAS-to-CAS delay (tCCD)
# With bank group architectures, tBURST represents the CAS-to-CAS
# delay for bursts to different bank groups (tCCD_S)
tBURST = "3.332ns"
# @2400 data rate, tCCD_L is 6 CK
# CAS-to-CAS delay for bursts to the same bank group
# tBURST is equivalent to tCCD_S; no explicit parameter required
# for CAS-to-CAS delay for bursts to different bank groups
tCCD_L = "5ns"
# DDR4-2400 17-17-17
tRCD = "14.16ns"
tCL = "14.16ns"
tRP = "14.16ns"
tRAS = "32ns"
# RRD_S (different bank group) for 512B page is MAX(4 CK, 3.3ns)
tRRD = "3.332ns"
# RRD_L (same bank group) for 512B page is MAX(4 CK, 4.9ns)
tRRD_L = "4.9ns"
# tFAW for 512B page is MAX(16 CK, 13ns)
tXAW = "13.328ns"
activation_limit = 4
# tRFC is 350ns
tRFC = "350ns"
tWR = "15ns"
# Here using the average of WTR_S and WTR_L
tWTR = "5ns"
# Greater of 4 CK or 7.5 ns
tRTP = "7.5ns"
# Default same rank rd-to-wr bus turnaround to 2 CK, @1200 MHz = 1.666 ns
tRTW = "1.666ns"
# Default different rank bus delay to 2 CK, @1200 MHz = 1.666 ns
tCS = "1.666ns"
# <=85C, half for >85C
tREFI = "7.8us"
# active powerdown and precharge powerdown exit time
tXP = "6ns"
# self refresh exit time
# exit delay to ACT, PRE, PREALL, REF, SREF Enter, and PD Enter is:
# tRFC + 10ns = 340ns
tXS = "340ns"
# Current values from datasheet
IDD0 = "43mA"
IDD02 = "3mA"
IDD2N = "34mA"
IDD3N = "38mA"
IDD3N2 = "3mA"
IDD4W = "103mA"
IDD4R = "110mA"
IDD5 = "250mA"
IDD3P1 = "32mA"
IDD2P1 = "25mA"
IDD6 = "30mA"
VDD = "1.2V"
VDD2 = "2.5V"
class DDR4_2400_8x8(DDR4_2400_16x4):
"""
A single DDR4-2400 x64 channel (one command and address bus), with
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A1G8)
in an 8x8 configuration.
Total channel capacity is 16GiB
8 devices/rank * 2 ranks/channel * 1GiB/device = 16GiB/channel
"""
# 8x8 configuration, 8 devices each with an 8-bit interface
device_bus_width = 8
# Each device has a page (row buffer) size of 1 Kbyte (1K columns x8)
device_rowbuffer_size = "1KiB"
# 8x8 configuration, so 8 devices
devices_per_rank = 8
# RRD_L (same bank group) for 1K page is MAX(4 CK, 4.9ns)
tRRD_L = "4.9ns"
tXAW = "21ns"
# Current values from datasheet
IDD0 = "48mA"
IDD3N = "43mA"
IDD4W = "123mA"
IDD4R = "135mA"
IDD3P1 = "37mA"
class DDR4_2400_4x16(DDR4_2400_16x4):
"""
A single DDR4-2400 x64 channel (one command and address bus), with
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A512M16)
in an 4x16 configuration.
Total channel capacity is 4GiB
4 devices/rank * 1 ranks/channel * 1GiB/device = 4GiB/channel
"""
# 4x16 configuration, 4 devices each with an 16-bit interface
device_bus_width = 16
# Each device has a page (row buffer) size of 2 Kbyte (1K columns x16)
device_rowbuffer_size = "2KiB"
# 4x16 configuration, so 4 devices
devices_per_rank = 4
# Single rank for x16
ranks_per_channel = 1
# DDR4 has 2 (x16) or 4 (x4 and x8) bank groups
# Set to 2 for x16 case
bank_groups_per_rank = 2
# DDR4 has 16 banks(x4,x8) and 8 banks(x16) (4 bank groups in all
# configurations). Currently we do not capture the additional
# constraints incurred by the bank groups
banks_per_rank = 8
# RRD_S (different bank group) for 2K page is MAX(4 CK, 5.3ns)
tRRD = "5.3ns"
# RRD_L (same bank group) for 2K page is MAX(4 CK, 6.4ns)
tRRD_L = "6.4ns"
tXAW = "30ns"
# Current values from datasheet
IDD0 = "80mA"
IDD02 = "4mA"
IDD2N = "34mA"
IDD3N = "47mA"
IDD4W = "228mA"
IDD4R = "243mA"
IDD5 = "280mA"
IDD3P1 = "41mA"

View File

@@ -0,0 +1,134 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for GDDR memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class GDDR5_4000_2x32(DRAMInterface):
"""
A single GDDR5 x64 interface, with default timings based on a GDDR5-4000
1 Gbit part (SK Hynix H5GQ1H24AFR) in a 2x32 configuration.
"""
# size of device
device_size = "128MiB"
# 2x32 configuration, 1 device with a 32-bit interface
device_bus_width = 32
# GDDR5 is a BL8 device
burst_length = 8
# Each device has a page (row buffer) size of 2Kbits (256Bytes)
device_rowbuffer_size = "256B"
# 2x32 configuration, so 2 devices
devices_per_rank = 2
# assume single rank
ranks_per_channel = 1
# GDDR5 has 4 bank groups
bank_groups_per_rank = 4
# GDDR5 has 16 banks with 4 bank groups
banks_per_rank = 16
# 1000 MHz
tCK = "1ns"
# 8 beats across an x64 interface translates to 2 clocks @ 1000 MHz
# Data bus runs @2000 Mhz => DDR ( data runs at 4000 MHz )
# 8 beats at 4000 MHz = 2 beats at 1000 MHz
# tBURST is equivalent to the CAS-to-CAS delay (tCCD)
# With bank group architectures, tBURST represents the CAS-to-CAS
# delay for bursts to different bank groups (tCCD_S)
tBURST = "2ns"
# @1000MHz data rate, tCCD_L is 3 CK
# CAS-to-CAS delay for bursts to the same bank group
# tBURST is equivalent to tCCD_S; no explicit parameter required
# for CAS-to-CAS delay for bursts to different bank groups
tCCD_L = "3ns"
tRCD = "12ns"
# tCL is not directly found in datasheet and assumed equal tRCD
tCL = "12ns"
tRP = "12ns"
tRAS = "28ns"
# RRD_S (different bank group)
# RRD_S is 5.5 ns in datasheet.
# rounded to the next multiple of tCK
tRRD = "6ns"
# RRD_L (same bank group)
# RRD_L is 5.5 ns in datasheet.
# rounded to the next multiple of tCK
tRRD_L = "6ns"
tXAW = "23ns"
# tXAW < 4 x tRRD.
# Therefore, activation limit is set to 0
activation_limit = 0
tRFC = "65ns"
tWR = "12ns"
# Here using the average of WTR_S and WTR_L
tWTR = "5ns"
# Read-to-Precharge 2 CK
tRTP = "2ns"
# Assume 2 cycles
tRTW = "2ns"

View File

@@ -0,0 +1,196 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for LPDDR5 memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class HBM_1000_4H_1x128(DRAMInterface):
"""
A single HBM x128 interface (one command and address bus), with
default timings based on data publically released
("HBM: Memory Solution for High Performance Processors", MemCon, 2014),
IDD measurement values, and by extrapolating data from other classes.
Architecture values based on published HBM spec
A 4H stack is defined, 2Gb per die for a total of 1GiB of memory.
**IMPORTANT**
HBM gen1 supports up to 8 128-bit physical channels
Configuration defines a single channel, with the capacity
set to (full_ stack_capacity / 8) based on 2Gb dies
To use all 8 channels, set 'channels' parameter to 8 in
system configuration
"""
# 128-bit interface legacy mode
device_bus_width = 128
# HBM supports BL4 and BL2 (legacy mode only)
burst_length = 4
# size of channel in bytes, 4H stack of 2Gb dies is 1GiB per stack;
# with 8 channels, 128MiB per channel
device_size = "128MiB"
device_rowbuffer_size = "2KiB"
# 1x128 configuration
devices_per_rank = 1
# HBM does not have a CS pin; set rank to 1
ranks_per_channel = 1
# HBM has 8 or 16 banks depending on capacity
# 2Gb dies have 8 banks
banks_per_rank = 8
# depending on frequency, bank groups may be required
# will always have 4 bank groups when enabled
# current specifications do not define the minimum frequency for
# bank group architecture
# setting bank_groups_per_rank to 0 to disable until range is defined
bank_groups_per_rank = 0
# 500 MHz for 1Gbps DDR data rate
tCK = "2ns"
# use values from IDD measurement in JEDEC spec
# use tRP value for tRCD and tCL similar to other classes
tRP = "15ns"
tRCD = "15ns"
tCL = "15ns"
tRAS = "33ns"
# BL2 and BL4 supported, default to BL4
# DDR @ 500 MHz means 4 * 2ns / 2 = 4ns
tBURST = "4ns"
# value for 2Gb device from JEDEC spec
tRFC = "160ns"
# value for 2Gb device from JEDEC spec
tREFI = "3.9us"
# extrapolate the following from LPDDR configs, using ns values
# to minimize burst length, prefetch differences
tWR = "18ns"
tRTP = "7.5ns"
tWTR = "10ns"
# start with 2 cycles turnaround, similar to other memory classes
# could be more with variations across the stack
tRTW = "4ns"
# single rank device, set to 0
tCS = "0ns"
# from MemCon example, tRRD is 4ns with 2ns tCK
tRRD = "4ns"
# from MemCon example, tFAW is 30ns with 2ns tCK
tXAW = "30ns"
activation_limit = 4
# 4tCK
tXP = "8ns"
# start with tRFC + tXP -> 160ns + 8ns = 168ns
tXS = "168ns"
class HBM_1000_4H_1x64(HBM_1000_4H_1x128):
"""
A single HBM x64 interface (one command and address bus), with
default timings based on HBM gen1 and data publically released
A 4H stack is defined, 8Gb per die for a total of 4GiB of memory.
Note: This defines a pseudo-channel with a unique controller
instantiated per pseudo-channel
Stay at same IO rate (1Gbps) to maintain timing relationship with
HBM gen1 class (HBM_1000_4H_x128) where possible
**IMPORTANT**
For HBM gen2 with pseudo-channel mode, configure 2X channels.
Configuration defines a single pseudo channel, with the capacity
set to (full_ stack_capacity / 16) based on 8Gb dies
To use all 16 pseudo channels, set 'channels' parameter to 16 in
system configuration
"""
# 64-bit pseudo-channel interface
device_bus_width = 64
# HBM pseudo-channel only supports BL4
burst_length = 4
# size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack;
# with 16 channels, 256MiB per channel
device_size = "256MiB"
# page size is halved with pseudo-channel; maintaining the same same number
# of rows per pseudo-channel with 2X banks across 2 channels
device_rowbuffer_size = "1KiB"
# HBM has 8 or 16 banks depending on capacity
# Starting with 4Gb dies, 16 banks are defined
banks_per_rank = 16
# reset tRFC for larger, 8Gb device
# use HBM1 4Gb value as a starting point
tRFC = "260ns"
# start with tRFC + tXP -> 160ns + 8ns = 168ns
tXS = "268ns"
# Default different rank bus delay to 2 CK, @1000 MHz = 2 ns
tCS = "2ns"
tREFI = "3.9us"
# active powerdown and precharge powerdown exit time
tXP = "10ns"
# self refresh exit time
tXS = "65ns"

View File

@@ -0,0 +1,161 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for HMC memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
Note that HMC is configured differently than some other DRAM interfaces.
"""
class HMC_2500_1x32(DDR3_1600_8x8):
"""
A single HMC-2500 x32 model based on:
[1] DRAMSpec: a high-level DRAM bank modelling tool
developed at the University of Kaiserslautern. This high level tool
uses RC (resistance-capacitance) and CV (capacitance-voltage) models to
estimate the DRAM bank latency and power numbers.
[2] High performance AXI-4.0 based interconnect for extensible smart memory
cubes (E. Azarkhish et. al)
Assumed for the HMC model is a 30 nm technology node.
The modelled HMC consists of 4 Gbit layers which sum up to 2GiB of memory
(4 layers).
Each layer has 16 vaults and each vault consists of 2 banks per layer.
In order to be able to use the same controller used for 2D DRAM generations
for HMC, the following analogy is done:
Channel (DDR) => Vault (HMC)
device_size (DDR) => size of a single layer in a vault
ranks per channel (DDR) => number of layers
banks per rank (DDR) => banks per layer
devices per rank (DDR) => devices per layer ( 1 for HMC).
The parameters for which no input is available are inherited from the DDR3
configuration.
This configuration includes the latencies from the DRAM to the logic layer
of the HMC
"""
# size of device
# two banks per device with each bank 4MiB [2]
device_size = "8MiB"
# 1x32 configuration, 1 device with 32 TSVs [2]
device_bus_width = 32
# HMC is a BL8 device [2]
burst_length = 8
# Each device has a page (row buffer) size of 256 bytes [2]
device_rowbuffer_size = "256B"
# 1x32 configuration, so 1 device [2]
devices_per_rank = 1
# 4 layers so 4 ranks [2]
ranks_per_channel = 4
# HMC has 2 banks per layer [2]
# Each layer represents a rank. With 4 layers and 8 banks in total, each
# layer has 2 banks; thus 2 banks per rank.
banks_per_rank = 2
# 1250 MHz [2]
tCK = "0.8ns"
# 8 beats across an x32 interface translates to 4 clocks @ 1250 MHz
tBURST = "3.2ns"
# Values using DRAMSpec HMC model [1]
tRCD = "10.2ns"
tCL = "9.9ns"
tRP = "7.7ns"
tRAS = "21.6ns"
# tRRD depends on the power supply network for each vendor.
# We assume a tRRD of a double bank approach to be equal to 4 clock
# cycles (Assumption)
tRRD = "3.2ns"
# activation limit is set to 0 since there are only 2 banks per vault
# layer.
activation_limit = 0
# Values using DRAMSpec HMC model [1]
tRFC = "59ns"
tWR = "8ns"
tRTP = "4.9ns"
# Default different rank bus delay assumed to 1 CK for TSVs, @1250 MHz =
# 0.8 ns (Assumption)
tCS = "0.8ns"
# Value using DRAMSpec HMC model [1]
tREFI = "3.9us"
# The default page policy in the vault controllers is simple closed page
# [2] nevertheless 'close' policy opens and closes the row multiple times
# for bursts largers than 32Bytes. For this reason we use 'close_adaptive'
page_policy = "close_adaptive"
# RoCoRaBaCh resembles the default address mapping in HMC
addr_mapping = "RoCoRaBaCh"
# These parameters do not directly correlate with buffer_size in real
# hardware. Nevertheless, their value has been tuned to achieve a
# bandwidth similar to the cycle-accurate model in [2]
write_buffer_size = 32
read_buffer_size = 32
def controller(self):
"""
Instantiate the memory controller and bind it to
the current interface.
"""
controller = MemCtrl(
min_writes_per_switch=8,
static_backend_latency="4ns",
static_frontend_latency="4ns",
)
controller.dram = self
return controller

View File

@@ -0,0 +1,154 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for LPDDR2 memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class LPDDR2_S4_1066_1x32(DRAMInterface):
"""
A single LPDDR2-S4 x32 interface (one command/address bus), with
default timings based on a LPDDR2-1066 4 Gbit part (Micron MT42L128M32D1)
in a 1x32 configuration.
"""
# No DLL in LPDDR2
dll = False
# size of device
device_size = "512MiB"
# 1x32 configuration, 1 device with a 32-bit interface
device_bus_width = 32
# LPDDR2_S4 is a BL4 and BL8 device
burst_length = 8
# Each device has a page (row buffer) size of 1KB
# (this depends on the memory density)
device_rowbuffer_size = "1KiB"
# 1x32 configuration, so 1 device
devices_per_rank = 1
# Use a single rank
ranks_per_channel = 1
# LPDDR2-S4 has 8 banks in all configurations
banks_per_rank = 8
# 533 MHz
tCK = "1.876ns"
# Fixed at 15 ns
tRCD = "15ns"
# 8 CK read latency, 4 CK write latency @ 533 MHz, 1.876 ns cycle time
tCL = "15ns"
# Pre-charge one bank 15 ns (all banks 18 ns)
tRP = "15ns"
tRAS = "42ns"
tWR = "15ns"
tRTP = "7.5ns"
# 8 beats across an x32 DDR interface translates to 4 clocks @ 533 MHz.
# Note this is a BL8 DDR device.
# Requests larger than 32 bytes are broken down into multiple requests
# in the controller
tBURST = "7.5ns"
# LPDDR2-S4, 4 Gbit
tRFC = "130ns"
tREFI = "3.9us"
# active powerdown and precharge powerdown exit time
tXP = "7.5ns"
# self refresh exit time
tXS = "140ns"
# Irrespective of speed grade, tWTR is 7.5 ns
tWTR = "7.5ns"
# Default same rank rd-to-wr bus turnaround to 2 CK, @533 MHz = 3.75 ns
tRTW = "3.75ns"
# Default different rank bus delay to 2 CK, @533 MHz = 3.75 ns
tCS = "3.75ns"
# Activate to activate irrespective of density and speed grade
tRRD = "10.0ns"
# Irrespective of density, tFAW is 50 ns
tXAW = "50ns"
activation_limit = 4
# Current values from datasheet
IDD0 = "15mA"
IDD02 = "70mA"
IDD2N = "2mA"
IDD2N2 = "30mA"
IDD3N = "2.5mA"
IDD3N2 = "30mA"
IDD4W = "10mA"
IDD4W2 = "190mA"
IDD4R = "3mA"
IDD4R2 = "220mA"
IDD5 = "40mA"
IDD52 = "150mA"
IDD3P1 = "1.2mA"
IDD3P12 = "8mA"
IDD2P1 = "0.6mA"
IDD2P12 = "0.8mA"
IDD6 = "1mA"
IDD62 = "3.2mA"
VDD = "1.8V"
VDD2 = "1.2V"

View File

@@ -0,0 +1,154 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for LPDDR3 memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class LPDDR3_1600_1x32(DRAMInterface):
"""
A single LPDDR3 x32 interface (one command/address bus), with default
timings based on a LPDDR3-1600 4 Gbit part (Micron EDF8132A1MC) in a 1x32
configuration.
"""
# No DLL for LPDDR3
dll = False
# size of device
device_size = "512MiB"
# 1x32 configuration, 1 device with a 32-bit interface
device_bus_width = 32
# LPDDR3 is a BL8 device
burst_length = 8
# Each device has a page (row buffer) size of 4KB
device_rowbuffer_size = "4KiB"
# 1x32 configuration, so 1 device
devices_per_rank = 1
# Technically the datasheet is a dual-rank package, but for
# comparison with the LPDDR2 config we stick to a single rank
ranks_per_channel = 1
# LPDDR3 has 8 banks in all configurations
banks_per_rank = 8
# 800 MHz
tCK = "1.25ns"
tRCD = "18ns"
# 12 CK read latency, 6 CK write latency @ 800 MHz, 1.25 ns cycle time
tCL = "15ns"
tRAS = "42ns"
tWR = "15ns"
# Greater of 4 CK or 7.5 ns, 4 CK @ 800 MHz = 5 ns
tRTP = "7.5ns"
# Pre-charge one bank 18 ns (all banks 21 ns)
tRP = "18ns"
# 8 beats across a x32 DDR interface translates to 4 clocks @ 800 MHz.
# Note this is a BL8 DDR device.
# Requests larger than 32 bytes are broken down into multiple requests
# in the controller
tBURST = "5ns"
# LPDDR3, 4 Gb
tRFC = "130ns"
tREFI = "3.9us"
# active powerdown and precharge powerdown exit time
tXP = "7.5ns"
# self refresh exit time
tXS = "140ns"
# Irrespective of speed grade, tWTR is 7.5 ns
tWTR = "7.5ns"
# Default same rank rd-to-wr bus turnaround to 2 CK, @800 MHz = 2.5 ns
tRTW = "2.5ns"
# Default different rank bus delay to 2 CK, @800 MHz = 2.5 ns
tCS = "2.5ns"
# Activate to activate irrespective of density and speed grade
tRRD = "10.0ns"
# Irrespective of size, tFAW is 50 ns
tXAW = "50ns"
activation_limit = 4
# Current values from datasheet
IDD0 = "8mA"
IDD02 = "60mA"
IDD2N = "0.8mA"
IDD2N2 = "26mA"
IDD3N = "2mA"
IDD3N2 = "34mA"
IDD4W = "2mA"
IDD4W2 = "190mA"
IDD4R = "2mA"
IDD4R2 = "230mA"
IDD5 = "28mA"
IDD52 = "150mA"
IDD3P1 = "1.4mA"
IDD3P12 = "11mA"
IDD2P1 = "0.8mA"
IDD2P12 = "1.8mA"
IDD6 = "0.5mA"
IDD62 = "1.8mA"
VDD = "1.8V"
VDD2 = "1.2V"

View File

@@ -0,0 +1,358 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for LPDDR5 memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class LPDDR5_5500_1x16_BG_BL32(DRAMInterface):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on
initial JEDEC specification
Starting with 5.5Gbps data rates and 8Gbit die
Configuring for 16-bank mode with bank-group architecture
burst of 32, which means bursts can be interleaved
"""
# Increase buffer size to account for more bank resources
read_buffer_size = 64
# Set page policy to better suit DMC Huxley
page_policy = "close_adaptive"
# 16-bit channel interface
device_bus_width = 16
# LPDDR5 is a BL16 or BL32 device
# With BG mode, BL16 and BL32 are supported
# Use BL32 for higher command bandwidth
burst_length = 32
# size of device in bytes
device_size = "1GiB"
# 2KiB page with BG mode
device_rowbuffer_size = "2KiB"
# Use a 1x16 configuration
devices_per_rank = 1
# Use a single rank
ranks_per_channel = 1
# LPDDR5 supports configurable bank options
# 8B : BL32, all frequencies
# 16B : BL32 or BL16, <=3.2Gbps
# 16B with Bank Group Arch (4B/BG): BL32 or BL16, >3.2Gbps
# Initial configuration will have 16 banks with Bank Group Arch
# to maximim resources and enable higher data rates
banks_per_rank = 16
bank_groups_per_rank = 4
# 5.5Gb/s DDR with 4:1 WCK:CK ratio for 687.5 MHz CK
tCK = "1.455ns"
# Greater of 2 CK or 18ns
tRCD = "18ns"
# Base RL is 16 CK @ 687.5 MHz = 23.28ns
tCL = "23.280ns"
# Greater of 2 CK or 18ns
tRP = "18ns"
# Greater of 3 CK or 42ns
tRAS = "42ns"
# Greater of 3 CK or 34ns
tWR = "34ns"
# active powerdown and precharge powerdown exit time
# Greater of 3 CK or 7ns
tXP = "7ns"
# self refresh exit time (tRFCab + 7.5ns)
tXS = "217.5ns"
# Greater of 2 CK or 7.5 ns minus 2 CK
tRTP = "4.59ns"
# With BG architecture, burst of 32 transferred in two 16-beat
# sub-bursts, with a 16-beat gap in between.
# Each 16-beat sub-burst is 8 WCK @2.75 GHz or 2 CK @ 687.5 MHz
# tBURST is the delay to transfer the Bstof32 = 6 CK @ 687.5 MHz
tBURST = "8.73ns"
# can interleave a Bstof32 from another bank group at tBURST_MIN
# 16-beats is 8 WCK @2.75 GHz or 2 CK @ 687.5 MHz
tBURST_MIN = "2.91ns"
# tBURST_MAX is the maximum burst delay for same bank group timing
# this is 8 CK @ 687.5 MHz
tBURST_MAX = "11.64ns"
# 8 CK @ 687.5 MHz
tCCD_L = "11.64ns"
# LPDDR5, 8 Gbit/channel for 280ns tRFCab
tRFC = "210ns"
tREFI = "3.9us"
# Greater of 4 CK or 6.25 ns
tWTR = "6.25ns"
# Greater of 4 CK or 12 ns
tWTR_L = "12ns"
# Required RD-to-WR timing is RL+ BL/n + tWCKDQ0/tCK - WL
# tWCKDQ0/tCK will be 1 CK for most cases
# For gem5 RL = WL and BL/n is already accounted for with tBURST
# Result is and additional 1 CK is required
tRTW = "1.455ns"
# Default different rank bus delay to 2 CK, @687.5 MHz = 2.91 ns
tCS = "2.91ns"
# 2 CK
tPPD = "2.91ns"
# Greater of 2 CK or 5 ns
tRRD = "5ns"
tRRD_L = "5ns"
# With Bank Group Arch mode tFAW is 20 ns
tXAW = "20ns"
activation_limit = 4
# at 5Gbps, 4:1 WCK to CK ratio required
# 2 data beats per WCK (DDR) -> 8 per CK
beats_per_clock = 8
# 2 cycles required to send activate command
# 2 command phases can be sent back-to-back or
# with a gap up to tAAD = 8 CK
two_cycle_activate = True
tAAD = "11.640ns"
data_clock_sync = True
class LPDDR5_5500_1x16_BG_BL16(LPDDR5_5500_1x16_BG_BL32):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on
initial JEDEC specification
Starting with 5.5Gbps data rates and 8Gbit die
Configuring for 16-bank mode with bank-group architecture, burst of 16
"""
# LPDDR5 is a BL16 or BL32 device
# With BG mode, BL16 and BL32 are supported
# Use BL16 for smaller access granularity
burst_length = 16
# For Bstof16 with BG arch, 2 CK @ 687.5 MHz with 4:1 clock ratio
tBURST = "2.91ns"
tBURST_MIN = "2.91ns"
# For Bstof16 with BG arch, 4 CK @ 687.5 MHz with 4:1 clock ratio
tBURST_MAX = "5.82ns"
# 4 CK @ 687.5 MHz
tCCD_L = "5.82ns"
class LPDDR5_5500_1x16_8B_BL32(LPDDR5_5500_1x16_BG_BL32):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on
initial JEDEC specification
Starting with 5.5Gbps data rates and 8Gbit die
Configuring for 8-bank mode, burst of 32
"""
# 4KiB page with 8B mode
device_rowbuffer_size = "4KiB"
# LPDDR5 supports configurable bank options
# 8B : BL32, all frequencies
# 16B : BL32 or BL16, <=3.2Gbps
# 16B with Bank Group Arch (4B/BG): BL32 or BL16, >3.2Gbps
# Select 8B
banks_per_rank = 8
bank_groups_per_rank = 0
# For Bstof32 with 8B mode, 4 CK @ 687.5 MHz with 4:1 clock ratio
tBURST = "5.82ns"
tBURST_MIN = "5.82ns"
tBURST_MAX = "5.82ns"
# Greater of 4 CK or 12 ns
tWTR = "12ns"
# Greater of 2 CK or 10 ns
tRRD = "10ns"
# With 8B mode tFAW is 40 ns
tXAW = "40ns"
activation_limit = 4
# Reset BG arch timing for 8B mode
tCCD_L = "0ns"
tRRD_L = "0ns"
tWTR_L = "0ns"
class LPDDR5_6400_1x16_BG_BL32(LPDDR5_5500_1x16_BG_BL32):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on
initial JEDEC specification
6.4Gbps data rates and 8Gbit die
Configuring for 16-bank mode with bank-group architecture
burst of 32, which means bursts can be interleaved
"""
# 5.5Gb/s DDR with 4:1 WCK:CK ratio for 687.5 MHz CK
tCK = "1.25ns"
# Base RL is 17 CK @ 800 MHz = 21.25ns
tCL = "21.25ns"
# With BG architecture, burst of 32 transferred in two 16-beat
# sub-bursts, with a 16-beat gap in between.
# Each 16-beat sub-burst is 8 WCK @3.2 GHz or 2 CK @ 800 MHz
# tBURST is the delay to transfer the Bstof32 = 6 CK @ 800 MHz
tBURST = "7.5ns"
# can interleave a Bstof32 from another bank group at tBURST_MIN
# 16-beats is 8 WCK @2.3 GHz or 2 CK @ 800 MHz
tBURST_MIN = "2.5ns"
# tBURST_MAX is the maximum burst delay for same bank group timing
# this is 8 CK @ 800 MHz
tBURST_MAX = "10ns"
# 8 CK @ 800 MHz
tCCD_L = "10ns"
# Required RD-to-WR timing is RL+ BL/n + tWCKDQ0/tCK - WL
# tWCKDQ0/tCK will be 1 CK for most cases
# For gem5 RL = WL and BL/n is already accounted for with tBURST
# Result is and additional 1 CK is required
tRTW = "1.25ns"
# Default different rank bus delay to 2 CK, @687.5 MHz = 2.5 ns
tCS = "2.5ns"
# 2 CK
tPPD = "2.5ns"
# 2 command phases can be sent back-to-back or
# with a gap up to tAAD = 8 CK
tAAD = "10ns"
class LPDDR5_6400_1x16_BG_BL16(LPDDR5_6400_1x16_BG_BL32):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on initial
JEDEC specifcation
6.4Gbps data rates and 8Gbit die
Configuring for 16-bank mode with bank-group architecture, burst of 16
"""
# LPDDR5 is a BL16 or BL32 device
# With BG mode, BL16 and BL32 are supported
# Use BL16 for smaller access granularity
burst_length = 16
# For Bstof16 with BG arch, 2 CK @ 800 MHz with 4:1 clock ratio
tBURST = "2.5ns"
tBURST_MIN = "2.5ns"
# For Bstof16 with BG arch, 4 CK @ 800 MHz with 4:1 clock ratio
tBURST_MAX = "5ns"
# 4 CK @ 800 MHz
tCCD_L = "5ns"
class LPDDR5_6400_1x16_8B_BL32(LPDDR5_6400_1x16_BG_BL32):
"""
A single LPDDR5 x16 interface (one command/address bus)
for a single x16 channel with default timings based on
initial JEDEC specification
6.4Gbps data rates and 8Gbit die
Configuring for 8-bank mode, burst of 32
"""
# 4KiB page with 8B mode
device_rowbuffer_size = "4KiB"
# LPDDR5 supports configurable bank options
# 8B : BL32, all frequencies
# 16B : BL32 or BL16, <=3.2Gbps
# 16B with Bank Group Arch (4B/BG): BL32 or BL16, >3.2Gbps
# Select 8B
banks_per_rank = 8
bank_groups_per_rank = 0
# For Bstof32 with 8B mode, 4 CK @ 800 MHz with 4:1 clock ratio
tBURST = "5ns"
tBURST_MIN = "5ns"
tBURST_MAX = "5ns"
# Greater of 4 CK or 12 ns
tWTR = "12ns"
# Greater of 2 CK or 10 ns
tRRD = "10ns"
# With 8B mode tFAW is 40 ns
tXAW = "40ns"
activation_limit = 4
# Reset BG arch timing for 8B mode
tCCD_L = "0ns"
tRRD_L = "0ns"
tWTR_L = "0ns"

View File

@@ -0,0 +1,122 @@
# Copyright (c) 2012-2021 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Copyright (c) 2013 Amin Farmahini-Farahani
# Copyright (c) 2015 University of Kaiserslautern
# Copyright (c) 2015 The University of Bologna
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Interfaces for WideIO memory devices
These memory "interfaces" contain the timing,energy,etc parameters for each
memory type and are usually based on datasheets for the memory devices.
You can use these interfaces in the MemCtrl object as the `dram` timing
interface.
"""
from m5.objects import DRAMInterface
class WideIO_200_1x128(DRAMInterface):
"""
A single WideIO x128 interface (one command and address bus), with
default timings based on an estimated WIO-200 8 Gbit part.
"""
# No DLL for WideIO
dll = False
# size of device
device_size = "1024MiB"
# 1x128 configuration, 1 device with a 128-bit interface
device_bus_width = 128
# This is a BL4 device
burst_length = 4
# Each device has a page (row buffer) size of 4KB
# (this depends on the memory density)
device_rowbuffer_size = "4KiB"
# 1x128 configuration, so 1 device
devices_per_rank = 1
# Use one rank for a one-high die stack
ranks_per_channel = 1
# WideIO has 4 banks in all configurations
banks_per_rank = 4
# 200 MHz
tCK = "5ns"
# WIO-200
tRCD = "18ns"
tCL = "18ns"
tRP = "18ns"
tRAS = "42ns"
tWR = "15ns"
# Read to precharge is same as the burst
tRTP = "20ns"
# 4 beats across an x128 SDR interface translates to 4 clocks @ 200 MHz.
# Note this is a BL4 SDR device.
tBURST = "20ns"
# WIO 8 Gb
tRFC = "210ns"
# WIO 8 Gb, <=85C, half for >85C
tREFI = "3.9us"
# Greater of 2 CK or 15 ns, 2 CK @ 200 MHz = 10 ns
tWTR = "15ns"
# Default same rank rd-to-wr bus turnaround to 2 CK, @200 MHz = 10 ns
tRTW = "10ns"
# Default different rank bus delay to 2 CK, @200 MHz = 10 ns
tCS = "10ns"
# Activate to activate irrespective of density and speed grade
tRRD = "10.0ns"
# Two instead of four activation window
tXAW = "50ns"
activation_limit = 2
# The WideIO specification does not provide current information

View File

@@ -0,0 +1,166 @@
import m5
import os
import configparser
from m5.objects import DRAMsim3, AddrRange, Port, MemCtrl
from m5.util.convert import toMemorySize
from ..utils.override import overrides
from ..boards.abstract_board import AbstractBoard
from .abstract_memory_system import AbstractMemorySystem
from typing import Optional, Tuple, Sequence, List
def config_ds3(mem_type: str, num_chnls: int) -> Tuple[str, str]:
"""
This function creates a config file that will be used to create a memory
controller of type DRAMSim3. It stores the config file in /tmp/ directory.
:param mem_type: The name for the type of the memory to be configured.
:param num_chnls: The number of channels to configure for the memory
:returns: A tuple containing the output file and the output directory.
"""
config = configparser.ConfigParser()
# TODO: We need a better solution to this. This hard-coding is not
# an acceptable solution.
dramsim_3_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.pardir,
os.pardir,
os.pardir,
"ext",
"DRAMsim3",
)
dramsim_3_mem_configs = os.path.join(dramsim_3_dir, "configs")
input_file = os.path.join(dramsim_3_mem_configs, mem_type + ".ini")
# Run checks to ensure the `ext/DRAMsim3` directory is present, contains
# the configs directory, and the configuration file we require.
if not os.path.isdir(dramsim_3_dir):
raise Exception(
"The `ext/DRAMsim3` directory cannot be found.\n"
"Please navigate to `ext` and run:\n"
"git clone git@github.com:umd-memsys/DRAMsim3.git"
)
elif os.path.isdir(dramsim_3_mem_configs):
raise Exception(
"The `ext/DRAMsim3/configs` directory cannot be found."
)
elif os.path.isfile(input_file):
raise Exception(
"The configuration file '" + input_file + "' cannot " " be found."
)
output_file = "/tmp/" + mem_type + "_chnls" + str(num_chnls) + ".ini"
new_config = open(output_file, "w")
config.read(input_file)
config.set("system", "channels", str(num_chnls))
config.write(new_config)
new_config.close()
return output_file, m5.options.outdir
class DRAMSim3MemCtrl(DRAMsim3):
"""
A DRAMSim3 Memory Controller.
The class serves as a SimObject object wrapper, utiliszing the DRAMSim3
configuratons.
"""
def __init__(self, mem_name: str, num_chnls: int) -> None:
"""
:param mem_name: The name of the type of memory to be configured.
:param num_chnls: The number of channels.
"""
super(DRAMSim3MemCtrl, self).__init__()
ini_path, outdir = config_ds3(mem_name, num_chnls)
self.configFile = ini_path
self.filePath = outdir
class SingleChannel(AbstractMemorySystem):
"""
A Single Channel Memory system.
"""
def __init__(self, mem_type: str, size: Optional[str]):
"""
:param mem_name: The name of the type of memory to be configured.
:param num_chnls: The number of channels.
"""
super(SingleChannel, self).__init__()
self.mem_ctrl = DRAMSim3MemCtrl(mem_type, 1)
self._size = toMemorySize(size)
if not size:
raise NotImplementedError(
"DRAMSim3 memory controller requires a size parameter."
)
@overrides(AbstractMemorySystem)
def incorporate_memory(self, board: AbstractBoard) -> None:
pass
@overrides(AbstractMemorySystem)
def get_mem_ports(self) -> Tuple[Sequence[AddrRange], Port]:
return [(self.mem_ctrl.range, self.mem_ctrl.port)]
@overrides(AbstractMemorySystem)
def get_memory_controllers(self) -> List[MemCtrl]:
return [self.mem_ctrl]
@overrides(AbstractMemorySystem)
def get_size(self) -> int:
return self._size
@overrides(AbstractMemorySystem)
def set_memory_range(self, ranges: List[AddrRange]) -> None:
if len(ranges != 1) or ranges[0].size != self._size:
raise Exception(
"Single channel DRAMSim memory controller requires a single "
"range which matches the memory's size."
)
self.mem_ctrl.range = ranges[0]
def SingleChannelDDR3_1600(
size: Optional[str] = "2048MB",
) -> SingleChannel:
"""
A single channel DDR3_1600.
:param size: The size of the memory system. Default value of 2048MB.
"""
return SingleChannel("DDR3_8Gb_x8_1600", size)
def SingleChannelDDR4_2400(size: Optional[str] = "1024MB") -> SingleChannel:
"""
A single channel DDR3_2400.
:param size: The size of the memory system. Default value of 1024MB.
"""
return SingleChannel("DDR4_4Gb_x8_2400", size)
def SingleChannelLPDDR3_1600(size: Optional[str] = "256MB") -> SingleChannel:
"""
A single channel LPDDR3_1600.
:param size: The size of the memory system. Default value of 256MB.
"""
return SingleChannel("LPDDR3_8Gb_x32_1600", size)
def SingleChannelHBM(size: Optional[str] = "64MB") -> SingleChannel:
"""
A single channel HBM.
:param size: The size of the memory system. Default value of 64MB.
"""
return SingleChannel("HBM1_4Gb_x128", size)

View File

@@ -0,0 +1,136 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Single channel "generic" DDR memory controllers
"""
from ..boards.abstract_board import AbstractBoard
from .abstract_memory_system import AbstractMemorySystem
from ..utils.override import overrides
from m5.objects import AddrRange, DRAMInterface, MemCtrl, Port
from m5.util.convert import toMemorySize
from typing import List, Sequence, Tuple, Type, Optional
class SingleChannelMemory(AbstractMemorySystem):
"""A simple implementation of a single channel memory system
This class can take a DRAM Interface as a parameter to model many different
DDR memory systems.
"""
def __init__(
self,
dram_interface_class: Type[DRAMInterface],
size: Optional[str] = None,
):
"""
:param dram_interface_class: The DRAM interface type to create with
this memory controller
:param size: Optionally specify the size of the DRAM controller's
address space. By default, it starts at 0 and ends at the size of
the DRAM device specified
"""
super().__init__()
self._dram = dram_interface_class()
if size:
self._size = toMemorySize(size)
else:
self._size = self._get_dram_size(self._dram)
self.mem_ctrl = MemCtrl(dram=self._dram)
def _get_dram_size(self, dram: DRAMInterface) -> int:
return (
dram.device_size.value
* dram.devices_per_rank.value
* dram.ranks_per_channel.value
)
@overrides(AbstractMemorySystem)
def incorporate_memory(self, board: AbstractBoard) -> None:
pass
@overrides(AbstractMemorySystem)
def get_mem_ports(self) -> Tuple[Sequence[AddrRange], Port]:
return [(self._dram.range, self.mem_ctrl.port)]
@overrides(AbstractMemorySystem)
def get_memory_controllers(self) -> List[MemCtrl]:
return [self.mem_ctrl]
@overrides(AbstractMemorySystem)
def get_size(self) -> int:
return self._size
@overrides(AbstractMemorySystem)
def set_memory_range(self, ranges: List[AddrRange]) -> None:
if len(ranges) != 1 or ranges[0].size() != self._size:
print(ranges[0].size())
raise Exception(
"Single channel memory controller requires a single range "
"which matches the memory's size."
)
self.mem_ctrl.dram.range = ranges[0]
from .dram_interfaces.ddr3 import DDR3_1600_8x8, DDR3_2133_8x8
from .dram_interfaces.ddr4 import DDR4_2400_8x8
from .dram_interfaces.lpddr3 import LPDDR3_1600_1x32
from .dram_interfaces.hbm import HBM_1000_4H_1x128
# Enumerate all of the different DDR memory systems we support
def SingleChannelDDR3_1600(size: Optional[str] = None) -> AbstractMemorySystem:
"""
A single channel memory system using a single DDR3_1600_8x8 based DIMM
"""
return SingleChannelMemory(DDR3_1600_8x8, size)
def SingleChannelDDR3_2133(size: Optional[str] = None) -> AbstractMemorySystem:
"""
A single channel memory system using a single DDR3_2133_8x8 based DIMM
"""
return SingleChannelMemory(DDR3_2133_8x8, size)
def SingleChannelDDR4_2400(size: Optional[str] = None) -> AbstractMemorySystem:
"""
A single channel memory system using a single DDR4_2400_8x8 based DIMM
"""
return SingleChannelMemory(DDR4_2400_8x8, size)
def SingleChannelLPDDR3_1600(
size: Optional[str] = None,
) -> AbstractMemorySystem:
return SingleChannelMemory(LPDDR3_1600_1x32, size)
def SingleChannelHBM(size: Optional[str] = None) -> AbstractMemorySystem:
return SingleChannelMemory(HBM_1000_4H_1x128, size)

View File

@@ -0,0 +1,104 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from typing import Optional
from .cpu_types import CPUTypes
from ..utils.requires import requires
from m5.objects import BaseMMU, Port, SubSystem
class AbstractCore(SubSystem):
__metaclass__ = ABCMeta
def __init__(self, cpu_type: CPUTypes):
super(AbstractCore, self).__init__()
if cpu_type == CPUTypes.KVM:
requires(kvm_required=True)
self._cpu_type = cpu_type
def get_type(self) -> CPUTypes:
return self._cpu_type
@abstractmethod
def connect_icache(self, port: Port) -> None:
"""
This function should connect the response port from the instruction
cache to the right request port on the core.
:param port: The response port from the icache to connect to.
"""
raise NotImplementedError
@abstractmethod
def connect_dcache(self, port: Port) -> None:
"""
This function should connect the response port from the data cache to
the right request port on the core.
:param port: The response port from the icache to connect to.
"""
raise NotImplementedError
@abstractmethod
def connect_walker_ports(self, port1: Port, port2: Port) -> None:
"""
Connect the response port from itb and dtb to their respective request
ports in the core.
:param port1: The response port from itb walker to connect to.
:param port2: The response port from dtb walker to connect to.
"""
raise NotImplementedError
@abstractmethod
def set_workload(self, process: "Process") -> None:
raise NotImplementedError
@abstractmethod
def set_switched_out(self, value: bool) -> None:
raise NotImplementedError
@abstractmethod
def connect_interrupt(
self, interrupt_requestor: Optional[Port] = None,
interrupt_responce: Optional[Port] = None
) -> None:
""" Connect the core interrupts to the interrupt controller
This function is usually called from the cache hierarchy since the
optional ports can be implemented as cache ports.
"""
raise NotImplementedError
@abstractmethod
def get_mmu(self) -> BaseMMU:
""" Return the MMU for this core.
This is used in the board to setup system-specific MMU settings.
"""
raise NotImplementedError

View File

@@ -0,0 +1,95 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.objects import Port, PyTrafficGen
from ..utils.override import overrides
from .cpu_types import CPUTypes
from .abstract_core import AbstractCore
from typing import Optional
class AbstractGeneratorCore(AbstractCore):
"""The abstract generator core
Generator cores are cores that can replace the processing cores to allow
for testing computer systems in gem5. The abstract class
AbstractGeneratorCore defines the external interface that every generator
core must implement. Certain generator cores might need to extend this
interface to fit their requirements.
"""
def __init__(self):
"""
Create an AbstractCore with the CPUType of Timing. Also, setup a
dummy generator object to connect to icache
"""
# TODO: Remove the CPU Type parameter. This not needed.
# Jira issue here: https://gem5.atlassian.net/browse/GEM5-1031
super(AbstractGeneratorCore, self).__init__(CPUTypes.TIMING)
self.dummy_generator = PyTrafficGen()
@overrides(AbstractCore)
def connect_icache(self, port: Port) -> None:
"""
Generator cores only have one request port which we will connect to
the data cache not the icache. Just connect the icache to the dummy
generator here.
"""
self.dummy_generator.port = port
@overrides(AbstractCore)
def connect_walker_ports(self, port1: Port, port2: Port) -> None:
"""
Since generator cores are not used in full system mode, no need to
connect them to walker ports. Just pass here.
"""
pass
@overrides(AbstractCore)
def set_workload(self, process: "Process") -> None:
"""
Generator cores do not need any workload assigned to them, as they
generate their own synthetic workload (synthetic traffic). Just pass
here.
:param process: The process to execute during simulation.
"""
pass
@overrides(AbstractCore)
def connect_interrupt(
self,
interrupt_requestor: Optional[Port] = None,
interrupt_responce: Optional[Port] = None,
) -> None:
"""
Since generator cores are not used in full system mode, no need to
connect them to walker ports. Just pass here.
"""
pass

View File

@@ -0,0 +1,54 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from .abstract_core import AbstractCore
from m5.objects import SubSystem
from ..boards.abstract_board import AbstractBoard
from typing import List
class AbstractProcessor(SubSystem):
__metaclass__ = ABCMeta
def __init__(self, cores: List[AbstractCore]) -> None:
super(AbstractProcessor, self).__init__()
assert len(cores) > 0
self.cores = cores
def get_num_cores(self) -> int:
return len(self.cores)
def get_cores(self) -> List[AbstractCore]:
return self.cores
@abstractmethod
def incorporate_processor(self, board: AbstractBoard) -> None:
raise NotImplementedError

View File

@@ -0,0 +1,137 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..utils.override import overrides
from ..boards.mem_mode import MemMode
from .complex_generator_core import ComplexGeneratorCore
from .abstract_processor import AbstractProcessor
from ..boards.abstract_board import AbstractBoard
class ComplexGenerator(AbstractProcessor):
def __init__(self, num_cores: int = 1) -> None:
super(ComplexGenerator, self).__init__(
cores=[ComplexGeneratorCore() for i in range(num_cores)]
)
"""The complex generator
This class defines an external interface to create a list of complex
generator cores that could replace the processing cores in a board.
:param num_cores: The number of complex generator cores to create.
"""
@overrides(AbstractProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
board.set_mem_mode(MemMode.TIMING)
def add_linear(
self,
duration: str = "1ms",
rate: str = "100GB/s",
block_size: int = 64,
min_addr: int = 0,
max_addr: int = 32768,
rd_perc: int = 100,
data_limit: int = 0,
) -> None:
"""
This function will add a linear traffic to all the cores in the
generator with the params specified.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
for core in self.cores:
core.add_linear(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
def add_random(
self,
duration: str = "1ms",
rate: str = "100GB/s",
block_size: int = 64,
min_addr: int = 0,
max_addr: int = 32768,
rd_perc: int = 100,
data_limit: int = 0,
) -> None:
"""
This function will add a random traffic to all the cores in the
generator with the params specified.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
for core in self.cores:
core.add_random(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
def start_traffic(self) -> None:
"""
This function will start the traffic at the top of the traffic list. It
will also pop the first element so that the generator will start a
new traffic everytime this is called.
"""
for core in self.cores:
core.start_traffic()

View File

@@ -0,0 +1,332 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.ticks import fromSeconds
from m5.util.convert import toLatency, toMemoryBandwidth
from m5.objects import PyTrafficGen, Port
from .abstract_core import AbstractCore
from .abstract_generator_core import AbstractGeneratorCore
from ..utils.override import overrides
from enum import Enum
class TrafficModes(Enum):
"""The traffic mode class
This class is an enum to store traffic mode in a more meaningful way
"""
linear = 0
random = 1
class ComplexTrafficParams:
def __init__(
self,
mode: TrafficModes,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
):
"""The complex traffic params class
This class is a container for parameters to create either a linear or
random traffic. The complex generator core stores a list of complex
traffic params for resolution after m5.instantiate is called.
"""
self._mode = mode
self._duration = duration
self._rate = rate
self._block_size = block_size
self._min_addr = min_addr
self._max_addr = max_addr
self._rd_perc = rd_perc
self._data_limit = data_limit
class ComplexGeneratorCore(AbstractGeneratorCore):
def __init__(self):
"""The complex generator core interface.
This class defines the interface for a generator core that will create
a series of different types of traffic. This core uses PyTrafficGen to
create and inject the synthetic traffic. This generator could be used
to create more complex traffics that consist of linear and random
traffic in different phases.
"""
super(ComplexGeneratorCore, self).__init__()
self.generator = PyTrafficGen()
self._traffic_params = []
self._traffic = []
self._traffic_set = False
@overrides(AbstractCore)
def connect_dcache(self, port: Port) -> None:
self.generator.port = port
def add_linear(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function will add the params for a linear traffic to the list of
traffic params in this generator core. These params will be later
resolved by the start_traffic call. This core uses a PyTrafficGen to
create the traffic based on the specified params below.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
param = ComplexTrafficParams(
TrafficModes.linear,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic_params = self._traffic_params + [param]
self._traffic_set = False
def add_random(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function will add the params for a random traffic to the list of
traffic params in this generator core. These params will be later
resolved by the start_traffic call. This core uses a PyTrafficGen to
create the traffic based on the specified params below.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
param = ComplexTrafficParams(
TrafficModes.random,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic_params = self._traffic_params + [param]
self._traffic_set = False
def start_traffic(self) -> None:
"""
This function first checks if there are any pending traffics that
require creation, if so it will create the pending traffics based on
traffic_params list and adds them to the traffic list, then it starts
generating the traffic at the top of the traffic list. It also pops the
first element in the list so that every time this function is called a
new traffic is generated, each instance of a call to this function
should happen before each instance of the call to m5.simulate(). All
the instances of calls to this function should happen after
m5.instantiate()
"""
if not self._traffic_set:
self._set_traffic()
if self._traffic:
self.generator.start(self._traffic.pop(0))
else:
print("No phases left to generate!")
def _set_traffic(self) -> None:
"""
This function will pop params from traffic params list and create their
respective traffic and adds the traffic to the core's traffic list.
"""
while self._traffic_params:
param = self._traffic_params.pop(0)
mode = param._mode
duration = param._duration
rate = param._rate
block_size = param._block_size
min_addr = param._min_addr
max_addr = param._max_addr
rd_perc = param._rd_perc
data_limit = param._data_limit
if mode == TrafficModes.linear:
traffic = self._create_linear_traffic(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic = self._traffic + [traffic]
if mode == TrafficModes.random:
traffic = self._create_random_traffic(
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
)
self._traffic = self._traffic + [traffic]
self._traffic_set = True
def _create_linear_traffic(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function yields (creates) a linear traffic based on the input
params. Then it will yield (create) an exit traffic (exit traffic is
used to exit the simulation).
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
duration = fromSeconds(toLatency(duration))
rate = toMemoryBandwidth(rate)
period = fromSeconds(block_size / rate)
min_period = period
max_period = period
yield self.generator.createLinear(
duration,
min_addr,
max_addr,
block_size,
min_period,
max_period,
rd_perc,
data_limit,
)
yield self.generator.createExit(0)
def _create_random_traffic(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
"""
This function yields (creates) a random traffic based on the input
params. Then it will yield (create) an exit traffic (exit traffic is
used to exit the simulation).
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
duration = fromSeconds(toLatency(duration))
rate = toMemoryBandwidth(rate)
period = fromSeconds(block_size / rate)
min_period = period
max_period = period
yield self.generator.createRandom(
duration,
min_addr,
max_addr,
block_size,
min_period,
max_period,
rd_perc,
data_limit,
)
yield self.generator.createExit(0)

View File

@@ -0,0 +1,34 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from enum import Enum
class CPUTypes(Enum):
ATOMIC = 1
KVM = 2
O3 = 3
TIMING = 4

View File

@@ -0,0 +1,119 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..utils.override import overrides
from ..boards.mem_mode import MemMode
from .linear_generator_core import LinearGeneratorCore
from .abstract_processor import AbstractProcessor
from ..boards.abstract_board import AbstractBoard
from typing import List
class LinearGenerator(AbstractProcessor):
def __init__(
self,
num_cores: int = 1,
duration: str = "1ms",
rate: str = "100GB/s",
block_size: int = 64,
min_addr: int = 0,
max_addr: int = 32768,
rd_perc: int = 100,
data_limit: int = 0,
) -> None:
super(LinearGenerator, self).__init__(
cores=self._create_cores(
num_cores=num_cores,
duration=duration,
rate=rate,
block_size=block_size,
min_addr=min_addr,
max_addr=max_addr,
rd_perc=rd_perc,
data_limit=data_limit,
)
)
"""The linear generator
This class defines an external interface to create a list of linear
generator cores that could replace the processing cores in a board.
:param num_cores: The number of linear generator cores to create.
:param duration: The number of ticks for the generator to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
def _create_cores(
self,
num_cores,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
) -> List[LinearGeneratorCore]:
"""
The helper function to create the cores for the generator, it will use
the same inputs as the constructor function.
"""
return [
LinearGeneratorCore(
duration=duration,
rate=rate,
block_size=block_size,
min_addr=min_addr,
max_addr=max_addr,
rd_perc=rd_perc,
data_limit=data_limit,
)
for i in range(num_cores)
]
@overrides(AbstractProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
board.set_mem_mode(MemMode.TIMING)
def start_traffic(self) -> None:
"""
This function will start the assigned traffic to this generator.
"""
for core in self.cores:
core.start_traffic()

View File

@@ -0,0 +1,121 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.ticks import fromSeconds
from m5.util.convert import toLatency, toMemoryBandwidth
from m5.objects import PyTrafficGen, Port, BaseTrafficGen
from .abstract_core import AbstractCore
from .abstract_generator_core import AbstractGeneratorCore
from ..utils.override import overrides
from typing import Iterator
class LinearGeneratorCore(AbstractGeneratorCore):
def __init__(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
super(LinearGeneratorCore, self).__init__()
""" The linear generator core interface.
This class defines the interface for a generator core that will create
a linear (stream) traffic specific to the parameters below. This core
uses PyTrafficGen to create and inject the synthetic traffic.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
self.generator = PyTrafficGen()
self._duration = duration
self._rate = rate
self._block_size = block_size
self._min_addr = min_addr
self._max_addr = max_addr
self._rd_perc = rd_perc
self._data_limit = data_limit
@overrides(AbstractCore)
def connect_dcache(self, port: Port) -> None:
self.generator.port = port
def _set_traffic(self) -> None:
"""
This private function will set the traffic to be generated.
"""
self._traffic = self._create_traffic()
def _create_traffic(self) -> Iterator[BaseTrafficGen]:
"""
A python generator that yields (creates) a linear traffic with the
specified params in the generator core and then yields (creates) an
exit traffic.
:rtype: Iterator[BaseTrafficGen]
"""
duration = fromSeconds(toLatency(self._duration))
rate = toMemoryBandwidth(self._rate)
period = fromSeconds(self._block_size / rate)
min_period = period
max_period = period
yield self.generator.createLinear(
duration,
self._min_addr,
self._max_addr,
self._block_size,
min_period,
max_period,
self._rd_perc,
self._data_limit,
)
yield self.generator.createExit(0)
def start_traffic(self) -> None:
"""
A call to this function will start generating the traffic, this call
should happen before m5.simulate() and after m5.instantiate()
"""
self._set_traffic()
self.generator.start(self._traffic)

View File

@@ -0,0 +1,119 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..utils.override import overrides
from ..boards.mem_mode import MemMode
from .random_generator_core import RandomGeneratorCore
from .abstract_processor import AbstractProcessor
from ..boards.abstract_board import AbstractBoard
from typing import List
class RandomGenerator(AbstractProcessor):
def __init__(
self,
num_cores: int = 1,
duration: str = "1ms",
rate: str = "100GB/s",
block_size: int = 64,
min_addr: int = 0,
max_addr: int = 32768,
rd_perc: int = 100,
data_limit: int = 0,
) -> None:
super(RandomGenerator, self).__init__(
cores=self._create_cores(
num_cores=num_cores,
duration=duration,
rate=rate,
block_size=block_size,
min_addr=min_addr,
max_addr=max_addr,
rd_perc=rd_perc,
data_limit=data_limit,
)
)
"""The random generator
This class defines an external interface to create a list of random
generator cores that could replace the processing cores in a board.
:param num_cores: The number of linear generator cores to create.
:param duration: The number of ticks for the generator to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
def _create_cores(
self,
num_cores,
duration,
rate,
block_size,
min_addr,
max_addr,
rd_perc,
data_limit,
) -> List[RandomGeneratorCore]:
"""
The helper function to create the cores for the generator, it will use
the same inputs as the constructor function.
"""
return [
RandomGeneratorCore(
duration=duration,
rate=rate,
block_size=block_size,
min_addr=min_addr,
max_addr=max_addr,
rd_perc=rd_perc,
data_limit=data_limit,
)
for i in range(num_cores)
]
@overrides(AbstractProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
board.set_mem_mode(MemMode.TIMING)
def start_traffic(self) -> None:
"""
This function will start the assigned traffic to this generator.
"""
for core in self.cores:
core.start_traffic()

View File

@@ -0,0 +1,121 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.ticks import fromSeconds
from m5.util.convert import toLatency, toMemoryBandwidth
from m5.objects import PyTrafficGen, Port, BaseTrafficGen
from .abstract_core import AbstractCore
from .abstract_generator_core import AbstractGeneratorCore
from ..utils.override import overrides
from typing import Iterator
class RandomGeneratorCore(AbstractGeneratorCore):
def __init__(
self,
duration: str,
rate: str,
block_size: int,
min_addr: int,
max_addr: int,
rd_perc: int,
data_limit: int,
) -> None:
super(RandomGeneratorCore, self).__init__()
""" The random generator core interface.
This class defines the interface for a generator core that will create
a random traffic specific to the parameters below. This core uses
PyTrafficGen to create and inject the synthetic traffic.
:param duration: The number of ticks for the generator core to generate
traffic.
:param rate: The rate at which the synthetic data is read/written.
:param block_size: The number of bytes to be read/written with each
request.
:param min_addr: The lower bound of the address range the generator
will read/write from/to.
:param max_addr: The upper bound of the address range the generator
will read/write from/to.
:param rd_perc: The percentage of read requests among all the generated
requests. The write percentage would be equal to 100 - rd_perc.
:param data_limit: The amount of data in bytes to read/write by the
generator before stopping generation.
"""
self.generator = PyTrafficGen()
self._duration = duration
self._rate = rate
self._block_size = block_size
self._min_addr = min_addr
self._max_addr = max_addr
self._rd_perc = rd_perc
self._data_limit = data_limit
@overrides(AbstractCore)
def connect_dcache(self, port: Port) -> None:
self.generator.port = port
def _set_traffic(self) -> None:
"""
This private function will set the traffic to be generated.
"""
self._traffic = self._create_traffic()
def _create_traffic(self) -> Iterator[BaseTrafficGen]:
"""
A python generator that yields (creates) a random traffic with the
specified params in the generator core and then yields (creates) an
exit traffic.
:rtype: Iterator[BaseTrafficGen]
"""
duration = fromSeconds(toLatency(self._duration))
rate = toMemoryBandwidth(self._rate)
period = fromSeconds(self._block_size / rate)
min_period = period
max_period = period
yield self.generator.createRandom(
duration,
self._min_addr,
self._max_addr,
self._block_size,
min_period,
max_period,
self._rd_perc,
self._data_limit,
)
yield self.generator.createExit(0)
def start_traffic(self) -> None:
"""
A call to this function will start generating the traffic, this call
should happen before m5.simulate() and after m5.instantiate().
"""
self._set_traffic()
self.generator.start(self._traffic)

View File

@@ -0,0 +1,106 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from typing import Optional
from ..runtime import get_runtime_isa
from ..processors.abstract_core import AbstractCore
from .cpu_types import CPUTypes
from ..isas import ISA
from ..utils.override import overrides
from m5.objects import (
BaseMMU,
Port,
AtomicSimpleCPU,
DerivO3CPU,
TimingSimpleCPU,
BaseCPU,
Process,
)
class SimpleCore(AbstractCore):
def __init__(self, cpu_type: CPUTypes, core_id: int):
super(SimpleCore, self).__init__(cpu_type=cpu_type)
if cpu_type == CPUTypes.ATOMIC:
self.core = AtomicSimpleCPU(cpu_id=core_id)
elif cpu_type == CPUTypes.O3:
self.core = DerivO3CPU(cpu_id=core_id)
elif cpu_type == CPUTypes.TIMING:
self.core = TimingSimpleCPU(cpu_id=core_id)
elif cpu_type == CPUTypes.KVM:
from m5.objects import X86KvmCPU
self.core = X86KvmCPU(cpu_id=core_id)
else:
raise NotImplementedError
self.core.createThreads()
def get_simobject(self) -> BaseCPU:
return self.core
@overrides(AbstractCore)
def connect_icache(self, port: Port) -> None:
self.core.icache_port = port
@overrides(AbstractCore)
def connect_dcache(self, port: Port) -> None:
self.core.dcache_port = port
@overrides(AbstractCore)
def connect_walker_ports(self, port1: Port, port2: Port) -> None:
self.core.mmu.connectWalkerPorts(port1, port2)
@overrides(AbstractCore)
def set_workload(self, process: Process) -> None:
self.core.workload = process
@overrides(AbstractCore)
def set_switched_out(self, value: bool) -> None:
self.core.switched_out = value
@overrides(AbstractCore)
def connect_interrupt(
self, interrupt_requestor: Optional[Port] = None,
interrupt_responce: Optional[Port] = None
) -> None:
# TODO: This model assumes that we will only create an interrupt
# controller as we require it. Not sure how true this is in all cases.
self.core.createInterruptController()
if get_runtime_isa() == ISA.X86:
if interrupt_requestor != None:
self.core.interrupts[0].pio = interrupt_requestor
self.core.interrupts[0].int_responder = interrupt_requestor
if interrupt_responce != None:
self.core.interrupts[0].int_requestor = interrupt_responce
@overrides(AbstractCore)
def get_mmu(self) -> BaseMMU:
return self.core.mmu

View File

@@ -0,0 +1,93 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..utils.override import overrides
from ..boards.mem_mode import MemMode
from ..processors.simple_core import SimpleCore
from m5.util import warn
from .abstract_processor import AbstractProcessor
from .cpu_types import CPUTypes
from ..boards.abstract_board import AbstractBoard
from typing import List
class SimpleProcessor(AbstractProcessor):
"""
A SimpeProcessor contains a number of cores of a a single CPUType.
"""
def __init__(self, cpu_type: CPUTypes, num_cores: int) -> None:
super(SimpleProcessor, self).__init__(
cores=self._create_cores(
cpu_type=cpu_type,
num_cores=num_cores,
)
)
self._cpu_type = cpu_type
if self._cpu_type == CPUTypes.KVM:
from m5.objects import KvmVM
self.kvm_vm = KvmVM()
def _create_cores(self, cpu_type: CPUTypes, num_cores: int):
return [
SimpleCore(cpu_type=cpu_type, core_id=i) for i in range(num_cores)
]
@overrides(AbstractProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
if self._cpu_type == CPUTypes.KVM:
board.kvm_vm = self.kvm_vm
# Set the memory mode.
if self._cpu_type == CPUTypes.TIMING or self._cpu_type == CPUTypes.O3:
board.set_mem_mode(MemMode.TIMING)
elif self._cpu_type == CPUTypes.KVM:
board.set_mem_mode(MemMode.ATOMIC_NONCACHING)
elif self._cpu_type == CPUTypes.ATOMIC:
if board.get_cache_hierarchy().is_ruby():
warn(
"Using an atomic core with Ruby will result in "
"'atomic_noncaching' memory mode. This will skip caching "
"completely."
)
else:
board.set_mem_mode(MemMode.ATOMIC)
else:
raise NotImplementedError
if self._cpu_type == CPUTypes.KVM:
# To get the KVM CPUs to run on different host CPUs
# Specify a different event queue for each CPU
for i, core in enumerate(self.cores):
for obj in core.get_simobject().descendants():
obj.eventq_index = 0
core.get_simobject().eventq_index = i + 1

View File

@@ -0,0 +1,98 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..boards.mem_mode import MemMode
from ..boards.abstract_board import AbstractBoard
from ..processors.simple_core import SimpleCore
from ..processors.cpu_types import CPUTypes
from .switchable_processor import SwitchableProcessor
from ..utils.override import *
from m5.objects import KvmVM
class SimpleSwitchableProcessor(SwitchableProcessor):
"""
A Simplified implementation of SwitchableProcessor where there is one
processor at the start of the simuation, and another that can be switched
to via the "switch" function later in the simulation. This is good for
fast/detailed CPU setups.
"""
def __init__(
self,
starting_core_type: CPUTypes,
switch_core_type: CPUTypes,
num_cores: int,
) -> None:
if num_cores <= 0:
raise AssertionError("Number of cores must be a positive integer!")
self._start_key = "start"
self._switch_key = "switch"
self._current_is_start = True
if starting_core_type in (CPUTypes.TIMING, CPUTypes.O3):
self._mem_mode = MemMode.TIMING
elif starting_core_type == CPUTypes.KVM:
self._mem_mode = MemMode.ATOMIC_NONCACHING
elif starting_core_type == CPUTypes.ATOMIC:
self._mem_mode = MemMode.ATOMIC
else:
raise NotImplementedError
switchable_cores = {
self._start_key: [
SimpleCore(cpu_type=starting_core_type, core_id=i)
for i in range(num_cores)
],
self._switch_key: [
SimpleCore(cpu_type=switch_core_type, core_id=i)
for i in range(num_cores)
],
}
super(SimpleSwitchableProcessor, self).__init__(
switchable_cores=switchable_cores,
starting_cores=self._start_key,
)
@overrides(SwitchableProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
super().incorporate_processor(board=board)
board.set_mem_mode(self._mem_mode)
def switch(self):
"""Switches to the "switched out" cores."""
if self._current_is_start:
self.switch_to_processor(self._switch_key)
else:
self.switch_to_processor(self._start_key)
self._current_is_start = not self._current_is_start

View File

@@ -0,0 +1,158 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .simple_core import SimpleCore
from .abstract_core import AbstractCore
from .cpu_types import CPUTypes
import m5
from typing import Dict, Any, List
from .abstract_processor import AbstractProcessor
from ..boards.abstract_board import AbstractBoard
from ..utils.override import *
class SwitchableProcessor(AbstractProcessor):
"""
This class can be used to setup a switchable processor/processors on a
system.
Though this class can be used directly, it is best inherited from. See
"SimpleSwitchableCPU" for an example of this.
"""
def __init__(
self,
switchable_cores: Dict[Any, List[SimpleCore]],
starting_cores: Any,
) -> None:
if starting_cores not in switchable_cores.keys():
raise AssertionError(
f"Key {starting_cores} cannot be found in the "
"switchable_processors dictionary."
)
self._current_cores = switchable_cores[starting_cores]
self._switchable_cores = switchable_cores
all_cores = []
for core_list in self._switchable_cores.values():
for core in core_list:
core.set_switched_out(core not in self._current_cores)
all_cores.append(core)
self._prepare_kvm = CPUTypes.KVM in [
core.get_type() for core in all_cores
]
if self._prepare_kvm:
if all_cores[0].get_type() != CPUTypes.KVM:
raise Exception(
"When using KVM, the switchable processor must start "
"with the KVM cores."
)
from m5.objects import KvmVM
self.kvm_vm = KvmVM()
super(SwitchableProcessor, self).__init__(cores=all_cores)
@overrides(AbstractProcessor)
def incorporate_processor(self, board: AbstractBoard) -> None:
# This is a bit of a hack. The `m5.switchCpus` function, used in the
# "switch_to_processor" function, requires the System simobject as an
# argument. We therefore need to store the board when incorporating the
# procsesor
self._board = board
if self._prepare_kvm:
board.kvm_vm = self.kvm_vm
# To get the KVM CPUs to run on different host CPUs
# Specify a different event queue for each CPU
kvm_cores = [
core for core in self.cores if core.get_type() == CPUTypes.KVM
]
for i, core in enumerate(kvm_cores):
for obj in core.get_simobject().descendants():
obj.eventq_index = 0
core.get_simobject().eventq_index = i + 1
@overrides(AbstractProcessor)
def get_num_cores(self) -> int:
# Note: This is a special case where the total number of cores in the
# design is not the number of cores, due to some being switched out.
return len(self._current_cores)
@overrides(AbstractProcessor)
def get_cores(self) -> List[AbstractCore]:
return self._current_cores
def switch_to_processor(self, switchable_core_key: Any):
# Run various checks.
if not hasattr(self, "_board"):
raise AssertionError("The processor has not been incorporated.")
if switchable_core_key not in self._switchable_cores.keys():
raise AssertionError(
f"Key {switchable_core_key} is not a key in the"
" switchable_processor dictionary."
)
# Select the correct processor to switch to.
to_switch = self._switchable_cores[switchable_core_key]
# Run more checks.
if to_switch == self._current_cores:
raise AssertionError(
"Cannot swap current cores with the current cores"
)
if len(to_switch) != len(self._current_cores):
raise AssertionError(
"The number of cores to swap in is not the same as the number "
"already swapped in. This is not allowed."
)
current_core_simobj = [
core.get_simobject() for core in self._current_cores
]
to_switch_simobj = [core.get_simobject() for core in to_switch]
# Switch the CPUs
m5.switchCpus(
self._board,
list(zip(current_core_simobj, to_switch_simobj)),
)
# Ensure the current processor is updated.
self._current_cores = to_switch

View File

@@ -0,0 +1,255 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json
import urllib.request
import hashlib
import os
import shutil
import gzip
import hashlib
import base64
from typing import List, Dict, Optional
from ..utils.filelock import FileLock
"""
This Python module contains functions used to download, list, and obtain
information about resources from resources.gem5.org.
"""
def _get_resources_json_uri() -> str:
# TODO: This is hardcoded to develop. This will need updated for each
# release to the stable branch.
uri = (
"https://gem5.googlesource.com/public/gem5-resources/"
+ "+/refs/heads/develop/resources.json?format=TEXT"
)
return uri
def _get_resources_json() -> Dict:
"""
Gets the Resources JSON.
:returns: The Resources JSON (as a Python Dictionary).
"""
# Note: Google Source does not properly support obtaining files as raw
# text. Therefore when we open the URL we receive the JSON in base64
# format. Conversion is needed before it can be loaded.
with urllib.request.urlopen(_get_resources_json_uri()) as url:
return json.loads(base64.b64decode(url.read()).decode("utf-8"))
def _get_resources(resources_group: Dict) -> Dict[str, Dict]:
"""
A recursive function to get all the resources.
:returns: A dictionary of resource names to the resource JSON objects.
"""
to_return = {}
for resource in resources_group:
if resource["type"] == "artifact":
# If the type is "artifact" then we add it directly to the map
# after a check that the name is unique.
if resource["name"] in to_return.keys():
raise Exception(
"Error: Duplicate artifact with name '{}'.".format(
resource["name"]
)
)
to_return[resource["name"]] = resource
elif resource["type"] == "group":
# If it's a group we get recursive. We then check to see if there
# are any duplication of keys.
new_map = _get_resources(resource["contents"])
intersection = set(new_map.keys()).intersection(to_return.keys())
if len(intersection) > 0:
# Note: if this error is received it's likely an error with
# the resources.json file. The resources names need to be
# unique keyes.
raise Exception(
"Error: Duplicate artifacts with names: {}.".format(
str(intersection)
)
)
to_return.update(new_map)
else:
raise Exception(
"Error: Unknown type '{}'.".format(resource["type"])
)
return to_return
def _get_md5(file: str) -> str:
"""
Gets the md5 of a file.
:param file: The file needing an md5 value.
:returns: The md5 of the input file.
"""
# Note: This code is slightly more complex than you might expect as
# `hashlib.md5(<file>)` returns malloc errors for large files (such as
# disk images).
md5_object = hashlib.md5()
block_size = 128 * md5_object.block_size
a_file = open(file, "rb")
chunk = a_file.read(block_size)
while chunk:
md5_object.update(chunk)
chunk = a_file.read(block_size)
return md5_object.hexdigest()
def _download(url: str, download_to: str) -> None:
"""
Downloads a file.
:param url: The URL of the file to download.
:param download_to: The location the downloaded file is to be stored.
"""
# TODO: This whole setup will only work for single files we can get via
# wget. We also need to support git clones going forward.
urllib.request.urlretrieve(url, download_to)
def list_resources() -> List[str]:
"""
Lists all available resources by name.
:returns: A list of resources by name.
"""
return _get_resources(_get_resources_json()["resources"]).keys()
def get_resources_json_obj(resource_name: str) -> Dict:
"""
Get a JSON object of a specified resource.
:param resource_name: The name of the resource.
:returns: The JSON object (in the form of a dictionary).
:raises Exception: An exception is raised if the specified resources does
not exist.
"""
artifact_map = _get_resources(_get_resources_json()["resources"])
if resource_name not in artifact_map:
raise Exception(
"Error: Resource with name '{}' does not exist".format(
resource_name
)
)
return artifact_map[resource_name]
def get_resource(
resource_name: str,
to_path: str,
unzip: Optional[bool] = True,
override: Optional[bool] = False,
) -> None:
"""
Obtains a gem5 resource and stored it to a specified location. If the
specified resource is already at the location, no action is taken.
:param resource_name: The resource to be obtained.
:param to_path: The location in the file system the resource is to be
stored. The filename should be included.
:param unzip: If true, gzipped resources will be unzipped prior to saving
to `to_path`. True by default.
:param override: If a resource is present with an incorrect hash (e.g.,
an outdated version of the resource is present), `get_resource` will delete
this local resource and re-download it if this parameter is True. False by
default.
:raises Exception: An exception is thrown if a file is already present at
`to_path` but it does not have the correct md5 sum. An exception will also
be thrown is a directory is present at `to_path`
"""
# We apply a lock for a specific resource. This is to avoid circumstances
# where multiple instances of gem5 are running and trying to obtain the
# same resources at once. The timeout here is somewhat arbitarily put at 15
# minutes.Most resources should be downloaded and decompressed in this
# timeframe, even on the most constrained of systems.
with FileLock("{}.lock".format(to_path), timeout=900):
resource_json = get_resources_json_obj(resource_name)
if os.path.exists(to_path):
if not os.path.isfile(to_path):
raise Exception(
"There is a directory at '{}'.".format(to_path)
)
if _get_md5(to_path) == resource_json["md5sum"]:
# In this case, the file has already been download, no need to
# do so again.
return
elif override:
os.remove(to_path)
else:
raise Exception(
"There already a file present at '{}' but "
"its md5 value is invalid.".format(to_path)
)
download_dest = to_path
run_unzip = unzip and resource_json["is_zipped"].lower() == "true"
if run_unzip:
download_dest += ".gz"
# TODO: Might be nice to have some kind of download status bar here.
# TODO: There might be a case where this should be silenced.
print("'{}' not found locally. Downloading...".format(resource_name))
_download(url=resource_json["url"], download_to=download_dest)
print("Finished downloading '{}'.".format(resource_name))
if run_unzip:
print("Decompressing '{}'...".format(resource_name))
with gzip.open(download_dest, "rb") as f:
with open(to_path, "wb") as o:
shutil.copyfileobj(f, o)
os.remove(download_dest)
print("Finished decompressing '{}.".format(resource_name))

View File

@@ -0,0 +1,109 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta
import os
from .downloader import get_resource
from typing import Optional
"""
A Resource object encapsulates a gem5 resource. Resources are items needed to
run a simulation, such as a disk image, kernel, or binary. The gem5 project
provides pre-built resources, with sources, at <resources.gem5.org>.
The purpose of this encapsulation is two fold:
1. It allows automatic retrieval of gem5 resources. E.g., specifying a resource
which is not local will initiate a download.
2. It provides a location where code may be added to record the resources used
within a simulation. At present this is a TODO work-item.
"""
class AbstractResource:
__metaclass__ = ABCMeta
def __init__(self, local_path: str):
self._local_path = local_path
def get_local_path(self) -> str:
return self._local_path
class CustomResource(AbstractResource):
"""
A custom gem5 resource. This can be used to encapsulate a resource provided
by a gem5 user as opposed to one available within the gem5 resources
repository.
"""
def __init__(self, local_path: str):
"""
:param local_path: The path of the resource on the host system.
"""
super().__init__(local_path=local_path)
class Resource(AbstractResource):
"""
An official gem5 resources as hosted within our gem5 resources repository
(<resources.gem5.org>).
A user need only specify the name of the resource during construction. The
resource will be downloaded if needed. A list of available resources can
be obtained via `downloader.list_resources()`.
"""
def __init__(
self,
resource_name: str,
resource_directory: Optional[str] = None,
override: Optional[bool] = False,
):
"""
:param resource_name: The name of the gem5 resource.
:param resource_directory: The location of the directory in which the
resource is to be stored.
:param override: If the resource is present, but does not have the
correct md5 value, the resoruce will be deleted and re-downloaded if
this value is True. Otherwise an exception will be thrown. False by
default.
"""
if resource_directory != None:
if not os.path.exists(resource_directory):
os.makedirs(resource_directory)
to_path = os.path.join(resource_directory, resource_name)
else:
to_path = resource_name
super(Resource, self).__init__(local_path=to_path)
get_resource(
resource_name=resource_name, to_path=to_path, override=override
)

View File

@@ -0,0 +1,87 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
This file contains functions to extract gem5 runtime information.
"""
from m5.defines import buildEnv
from .isas import ISA
from .coherence_protocol import CoherenceProtocol
def get_runtime_isa() -> ISA:
"""Gets the target ISA.
This can be inferred at runtime.
:returns: The target ISA.
"""
isa_map = {
"sparc": ISA.SPARC,
"mips": ISA.MIPS,
"null": ISA.NULL,
"arm": ISA.ARM,
"x86": ISA.X86,
"power": ISA.POWER,
"riscv": ISA.RISCV,
}
isa_str = str(buildEnv["TARGET_ISA"]).lower()
if isa_str not in isa_map.keys():
raise NotImplementedError(
"ISA '" + buildEnv["TARGET_ISA"] + "' not recognized."
)
return isa_map[isa_str]
def get_runtime_coherence_protocol() -> CoherenceProtocol:
"""Gets the cache coherence protocol.
This can be inferred at runtime.
:returns: The cache coherence protocol.
"""
protocol_map = {
"mi_example": CoherenceProtocol.MI_EXAMPLE,
"moesi_hammer": CoherenceProtocol.ARM_MOESI_HAMMER,
"garnet_standalone": CoherenceProtocol.GARNET_STANDALONE,
"moesi_cmp_token": CoherenceProtocol.MOESI_CMP_TOKEN,
"mesi_two_level": CoherenceProtocol.MESI_TWO_LEVEL,
"moesi_amd_base": CoherenceProtocol.MOESI_AMD_BASE,
"mesi_three_level_htm": CoherenceProtocol.MESI_THREE_LEVEL_HTM,
"mesi_three_level": CoherenceProtocol.MESI_THREE_LEVEL,
"gpu_viper": CoherenceProtocol.GPU_VIPER,
"chi": CoherenceProtocol.CHI,
}
protocol_str = str(buildEnv["PROTOCOL"]).lower()
if protocol_str not in protocol_map.keys():
raise NotImplementedError(
"Protocol '" + buildEnv["PROTOCOL"] + "' not recognized."
)
return protocol_map[protocol_str]

View File

@@ -0,0 +1,111 @@
# Copyright (c) 2009, Evan Fosmark
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the <organization> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
import time
import errno
class FileLockException(Exception):
pass
class FileLock(object):
"""A file locking mechanism that has context-manager support so
you can use it in a with statement. This should be relatively cross
compatible as it doesn't rely on msvcrt or fcntl for the locking.
"""
def __init__(self, file_name, timeout=10, delay=0.05):
"""Prepare the file locker. Specify the file to lock and optionally
the maximum timeout and the delay between each attempt to lock.
"""
if timeout is not None and delay is None:
raise ValueError(
"If timeout is not None, then delay must not be None."
)
self.is_locked = False
self.lockfile = os.path.join(os.getcwd(), "%s.lock" % file_name)
self.file_name = file_name
self.timeout = timeout
self.delay = delay
def acquire(self):
"""Acquire the lock, if possible. If the lock is in use, it check again
every `wait` seconds. It does this until it either gets the lock or
exceeds `timeout` number of seconds, in which case it throws
an exception.
"""
start_time = time.time()
while True:
try:
self.fd = os.open(
self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR
)
self.is_locked = True # moved to ensure tag only when locked
break
except OSError as e:
if e.errno != errno.EEXIST:
raise
if self.timeout is None:
raise FileLockException(
"Could not acquire lock on {}".format(self.file_name)
)
if (time.time() - start_time) >= self.timeout:
raise FileLockException("Timeout occured.")
time.sleep(self.delay)
# self.is_locked = True
def release(self):
"""Get rid of the lock by deleting the lockfile.
When working in a `with` statement, this gets automatically
called at the end.
"""
if self.is_locked:
os.close(self.fd)
os.unlink(self.lockfile)
self.is_locked = False
def __enter__(self):
"""Activated when used in the with statement.
Should automatically acquire a lock to be used in the with block.
"""
if not self.is_locked:
self.acquire()
return self
def __exit__(self, type, value, traceback):
"""Activated at the end of the with statement.
It automatically releases the lock if it isn't locked.
"""
if self.is_locked:
self.release()
def __del__(self):
"""Make sure that the FileLock instance doesn't leave a lockfile
lying around.
"""
self.release()

View File

@@ -0,0 +1,55 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
def overrides(interface_class):
"""
Function override annotation.
Corollary to @abc.abstractmethod where the override is not of an
abstractmethod.
Modified from answer https://stackoverflow.com/a/8313042/471376
"""
def confirm_override(method):
if method.__name__ not in dir(interface_class):
raise NotImplementedError(
f"function {method.__name__} is an @override, but that"
f" function is not implemented in base class {interface_class}"
)
def func():
pass
attr = getattr(interface_class, method.__name__)
if type(attr) is not type(func):
raise NotImplementedError(
f"function {method.__name__} is an @overide, but that is"
f" implemented as type {type(attr)} in base class"
f" {interface_class}, expected implemented type {type(func)}."
)
return method
return confirm_override

View File

@@ -0,0 +1,103 @@
# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ..runtime import get_runtime_coherence_protocol, get_runtime_isa
from ..isas import ISA
from ..coherence_protocol import CoherenceProtocol
from typing import Optional
import os
import inspect
def _get_exception_str(msg: str):
# The inspect module allows us to get information about live objects,
# modules, classes, etc. Here was use it to generate an exception string
# that incorporates information on what file or class this requirement was
# stated. `inspect.stack()[1]` is the `requires` caller method. One above
# this on the stack, `inspect.stack()[2]` should be where `requires` is
# called.
if inspect.stack()[2].function == '<module>':
# If the caller is a Python module, we use the filename. This is for
# the case where the `requires` function is called outside of a class.
name = inspect.stack()[2].filename
else:
# Otherwise we assume the `requires` is being called by a class, in
# which case we label the exception message with the class name.
name = inspect.stack()[2].frame.f_locals['self'].__class__.__name__
return "[{}] {}".format(name, msg)
def requires(
isa_required: Optional[ISA] = None,
coherence_protocol_required: Optional[CoherenceProtocol] = None,
kvm_required: Optional[bool] = False,
) -> None:
"""
Ensures the ISA/Coherence protocol/KVM requirements are met. An exception
will be raise if they are not.
:param isa_required: The ISA gem5 must be compiled to.
:param coherence_protocol_required: The coherence protocol gem5 must be
compiled to.
:param kvm_required: The host system must have the Kernel-based Virtual
Machine available.
:raises Exception: Raises an exception if the required ISA or coherence
protocol do not match that of the current gem5 binary.
"""
runtime_isa = get_runtime_isa()
runtime_coherence_protocol = get_runtime_coherence_protocol()
kvm_available = os.access("/dev/kvm", mode=os.R_OK | os.W_OK)
if isa_required != None and isa_required != runtime_isa:
raise Exception(
_get_exception_str(
msg="The current ISA is '{}'. Required: '{}'".format(
runtime_isa.name, isa_required.name
)
)
)
if (
coherence_protocol_required != None
and coherence_protocol_required != runtime_coherence_protocol
):
raise Exception(
_get_exception_str(
msg="The current coherence protocol is "
"'{}'. Required: '{}'".format(
runtime_coherence_protocol.name,
coherence_protocol_required.name,
)
)
)
if kvm_required and not kvm_available:
raise Exception(
_get_exception_str(
msg="KVM is required but is unavaiable on this system"
)
)