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:
@@ -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')
|
||||
|
||||
37
src/python/components_library/README.md
Normal file
37
src/python/components_library/README.md
Normal 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/)
|
||||
0
src/python/components_library/__init__.py
Normal file
0
src/python/components_library/__init__.py
Normal file
0
src/python/components_library/boards/__init__.py
Normal file
0
src/python/components_library/boards/__init__.py
Normal file
213
src/python/components_library/boards/abstract_board.py
Normal file
213
src/python/components_library/boards/abstract_board.py
Normal 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
|
||||
53
src/python/components_library/boards/mem_mode.py
Normal file
53
src/python/components_library/boards/mem_mode.py
Normal 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
|
||||
378
src/python/components_library/boards/riscv_board.py
Normal file
378
src/python/components_library/boards/riscv_board.py
Normal 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"))
|
||||
164
src/python/components_library/boards/simple_board.py
Normal file
164
src/python/components_library/boards/simple_board.py
Normal 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)
|
||||
130
src/python/components_library/boards/test_board.py
Normal file
130
src/python/components_library/boards/test_board.py
Normal 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)
|
||||
376
src/python/components_library/boards/x86_board.py
Normal file
376
src/python/components_library/boards/x86_board.py
Normal 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
|
||||
]
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
65
src/python/components_library/coherence_protocol.py
Normal file
65
src/python/components_library/coherence_protocol.py
Normal 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
|
||||
41
src/python/components_library/isas.py
Normal file
41
src/python/components_library/isas.py
Normal 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
|
||||
0
src/python/components_library/memory/__init__.py
Normal file
0
src/python/components_library/memory/__init__.py
Normal 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
|
||||
166
src/python/components_library/memory/dram_interfaces/ddr3.py
Normal file
166
src/python/components_library/memory/dram_interfaces/ddr3.py
Normal 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"
|
||||
245
src/python/components_library/memory/dram_interfaces/ddr4.py
Normal file
245
src/python/components_library/memory/dram_interfaces/ddr4.py
Normal 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"
|
||||
134
src/python/components_library/memory/dram_interfaces/gddr.py
Normal file
134
src/python/components_library/memory/dram_interfaces/gddr.py
Normal 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"
|
||||
196
src/python/components_library/memory/dram_interfaces/hbm.py
Normal file
196
src/python/components_library/memory/dram_interfaces/hbm.py
Normal 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"
|
||||
161
src/python/components_library/memory/dram_interfaces/hmc.py
Normal file
161
src/python/components_library/memory/dram_interfaces/hmc.py
Normal 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
|
||||
154
src/python/components_library/memory/dram_interfaces/lpddr2.py
Normal file
154
src/python/components_library/memory/dram_interfaces/lpddr2.py
Normal 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"
|
||||
154
src/python/components_library/memory/dram_interfaces/lpddr3.py
Normal file
154
src/python/components_library/memory/dram_interfaces/lpddr3.py
Normal 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"
|
||||
358
src/python/components_library/memory/dram_interfaces/lpddr5.py
Normal file
358
src/python/components_library/memory/dram_interfaces/lpddr5.py
Normal 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"
|
||||
122
src/python/components_library/memory/dram_interfaces/wideio.py
Normal file
122
src/python/components_library/memory/dram_interfaces/wideio.py
Normal 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
|
||||
166
src/python/components_library/memory/dramsim_3.py
Normal file
166
src/python/components_library/memory/dramsim_3.py
Normal 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)
|
||||
136
src/python/components_library/memory/single_channel.py
Normal file
136
src/python/components_library/memory/single_channel.py
Normal 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)
|
||||
104
src/python/components_library/processors/abstract_core.py
Normal file
104
src/python/components_library/processors/abstract_core.py
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
137
src/python/components_library/processors/complex_generator.py
Normal file
137
src/python/components_library/processors/complex_generator.py
Normal 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()
|
||||
@@ -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)
|
||||
34
src/python/components_library/processors/cpu_types.py
Normal file
34
src/python/components_library/processors/cpu_types.py
Normal 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
|
||||
119
src/python/components_library/processors/linear_generator.py
Normal file
119
src/python/components_library/processors/linear_generator.py
Normal 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()
|
||||
@@ -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)
|
||||
119
src/python/components_library/processors/random_generator.py
Normal file
119
src/python/components_library/processors/random_generator.py
Normal 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()
|
||||
@@ -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)
|
||||
106
src/python/components_library/processors/simple_core.py
Normal file
106
src/python/components_library/processors/simple_core.py
Normal 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
|
||||
93
src/python/components_library/processors/simple_processor.py
Normal file
93
src/python/components_library/processors/simple_processor.py
Normal 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
|
||||
@@ -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
|
||||
158
src/python/components_library/processors/switchable_processor.py
Normal file
158
src/python/components_library/processors/switchable_processor.py
Normal 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
|
||||
0
src/python/components_library/resources/__init__.py
Normal file
0
src/python/components_library/resources/__init__.py
Normal file
255
src/python/components_library/resources/downloader.py
Normal file
255
src/python/components_library/resources/downloader.py
Normal 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))
|
||||
109
src/python/components_library/resources/resource.py
Normal file
109
src/python/components_library/resources/resource.py
Normal 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
|
||||
)
|
||||
87
src/python/components_library/runtime.py
Normal file
87
src/python/components_library/runtime.py
Normal 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]
|
||||
0
src/python/components_library/utils/__init__.py
Normal file
0
src/python/components_library/utils/__init__.py
Normal file
111
src/python/components_library/utils/filelock.py
Normal file
111
src/python/components_library/utils/filelock.py
Normal 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()
|
||||
55
src/python/components_library/utils/override.py
Normal file
55
src/python/components_library/utils/override.py
Normal 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
|
||||
103
src/python/components_library/utils/requires.py
Normal file
103
src/python/components_library/utils/requires.py
Normal 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"
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user