stdlib: Incorporating multi-isa work to the stdlib

The main restriction with this design is it results in one ISA target
per board. The ISA is declared per core. To make the design simpler it's
assumed a Processor (a collection of cores) are all of the same ISA. As
each board has one processor, this also means a board is typically tied
to one ISA per simulation.

In order to remain backwards compatible and maintain the standard
library APIs, this patch adds a `--main-isa` parameter which will
determine what `gem5.runtime.get_runtime_isa` returns in cases where
mutliple ISAs are compiled in. When setting the ISA in a simulation (via
the Processor or Cores), the user may, as before, choose not to and, in
this case, the `gem5.runtime.get_runtime_isa` function is used.

The `gem5.runtime.get_runtime_isa` function is an intermediate step
which should be removed in future versions of gem5 (users should specify
precisely what ISA they want via configuration scripts). For this reason
it throws a warning when used and should not be heavily relied upon. It
is deprecated.

Change-Id: Ia76541bfa9a5a4b6b86401309281849b49dc724b
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/55423
Reviewed-by: Gabe Black <gabe.black@gmail.com>
Maintainer: Gabe Black <gabe.black@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Bobby R. Bruce
2022-01-11 11:53:32 -08:00
committed by Bobby Bruce
parent 3b6ea3dfa9
commit 79a93f3429
40 changed files with 404 additions and 106 deletions

View File

@@ -35,7 +35,6 @@ from ...cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from ..kernel_disk_workload import KernelDiskWorkload
from ....resources.resource import AbstractResource
from ....isas import ISA
from ....utils.requires import requires
import m5
from m5.objects import (
@@ -91,10 +90,14 @@ class LupvBoard(AbstractBoard, KernelDiskWorkload):
cache_hierarchy: AbstractCacheHierarchy,
) -> None:
requires(isa_required=ISA.RISCV)
if cache_hierarchy.is_ruby():
raise EnvironmentError("RiscvBoard is not compatible with Ruby")
if processor.get_isa() != ISA.RISCV:
raise Exception("The LupvBoard requires a processor using the "
"RISCV ISA. Current processor "
f"ISA: '{processor.get_isa().name}'.")
super().__init__(clk_freq, processor, memory, cache_hierarchy)
@overrides(AbstractBoard)

View File

@@ -37,7 +37,6 @@ from ..cachehierarchies.abstract_cache_hierarchy import AbstractCacheHierarchy
from ...resources.resource import AbstractResource
from ...isas import ISA
from ...utils.requires import requires
import m5
@@ -89,7 +88,11 @@ class RiscvBoard(AbstractBoard, KernelDiskWorkload):
cache_hierarchy: AbstractCacheHierarchy,
) -> None:
super().__init__(clk_freq, processor, memory, cache_hierarchy)
requires(isa_required=ISA.RISCV)
if processor.get_isa() != ISA.RISCV:
raise Exception("The RISCVBoard requires a processor using the"
"RISCV ISA. Current processor ISA: "
f"'{processor.get_isa().name}'.")
@overrides(AbstractBoard)
def _setup_board(self) -> None:

View File

@@ -57,7 +57,6 @@ from m5.util.convert import toMemorySize
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
from typing import List, Sequence
@@ -85,7 +84,9 @@ class X86Board(AbstractBoard, KernelDiskWorkload):
cache_hierarchy=cache_hierarchy,
)
requires(isa_required=ISA.X86)
if self.get_processor().get_isa() != ISA.X86:
raise Exception("The X86Board requires a processor using the X86 "
f"ISA. Current processor ISA: '{processor.get_isa().name}'.")
@overrides(AbstractBoard)
def _setup_board(self) -> None:

View File

@@ -35,7 +35,6 @@ from gem5.components.cachehierarchies.abstract_cache_hierarchy import (
)
from gem5.coherence_protocol import CoherenceProtocol
from gem5.isas import ISA
from gem5.runtime import get_runtime_isa
from gem5.utils.requires import requires
from gem5.utils.override import overrides
from gem5.components.boards.abstract_board import AbstractBoard
@@ -155,7 +154,7 @@ class PrivateL1CacheHierarchy(AbstractRubyCacheHierarchy):
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
target_isa=board.get_processor().get_isa(),
clk_domain=board.get_clock_domain(),
)
cluster.icache = PrivateL1MOESICache(
@@ -164,7 +163,7 @@ class PrivateL1CacheHierarchy(AbstractRubyCacheHierarchy):
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
target_isa=board.get_processor().get_isa(),
clk_domain=board.get_clock_domain(),
)
@@ -194,7 +193,7 @@ class PrivateL1CacheHierarchy(AbstractRubyCacheHierarchy):
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_isa() == ISA.X86:
int_req_port = cluster.dcache.sequencer.interrupt_out_port
int_resp_port = cluster.dcache.sequencer.in_ports
core.connect_interrupt(int_req_port, int_resp_port)

View File

@@ -28,7 +28,6 @@ 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
@@ -107,7 +106,7 @@ class NoCache(AbstractClassicCacheHierarchy):
self.membus.cpu_side_ports, self.membus.cpu_side_ports
)
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_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)

View File

@@ -31,7 +31,6 @@ 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
@@ -129,7 +128,7 @@ class PrivateL1CacheHierarchy(AbstractClassicCacheHierarchy):
self.iptw_caches[i].cpu_side, self.dptw_caches[i].cpu_side
)
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_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)

View File

@@ -33,8 +33,6 @@ 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 *
@@ -166,7 +164,7 @@ class PrivateL1PrivateL2CacheHierarchy(
self.iptw_caches[i].cpu_side, self.dptw_caches[i].cpu_side
)
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_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)

View File

@@ -30,7 +30,6 @@ 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
@@ -106,7 +105,7 @@ class MESITwoLevelCacheHierarchy(
core,
self._num_l2_banks,
cache_line_size,
get_runtime_isa(),
board.processor.get_isa(),
board.get_clock_domain(),
)
@@ -129,7 +128,7 @@ class MESITwoLevelCacheHierarchy(
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_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)

View File

@@ -34,7 +34,6 @@ 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
@@ -93,7 +92,7 @@ class MIExampleCacheHierarchy(AbstractRubyCacheHierarchy):
network=self.ruby_system.network,
core=core,
cache_line_size=board.get_cache_line_size(),
target_isa=get_runtime_isa(),
target_isa=board.get_processor().get_isa(),
clk_domain=board.get_clock_domain(),
)
@@ -116,7 +115,7 @@ class MIExampleCacheHierarchy(AbstractRubyCacheHierarchy):
)
# Connect the interrupt ports
if get_runtime_isa() == ISA.X86:
if board.get_processor().get_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)

View File

@@ -26,7 +26,10 @@
from abc import ABCMeta, abstractmethod
from typing import Optional
import importlib
from .cpu_types import CPUTypes
from ...isas import ISA
from ...utils.requires import requires
from m5.objects import BaseMMU, Port, SubSystem
@@ -44,6 +47,10 @@ class AbstractCore(SubSystem):
def get_type(self) -> CPUTypes:
return self._cpu_type
@abstractmethod
def get_isa(self) -> ISA:
raise NotImplementedError
@abstractmethod
def connect_icache(self, port: Port) -> None:
"""
@@ -102,3 +109,66 @@ class AbstractCore(SubSystem):
This is used in the board to setup system-specific MMU settings.
"""
raise NotImplementedError
@classmethod
def cpu_simobject_factory(cls, cpu_type: CPUTypes, isa: ISA, core_id: int):
"""
A factory used to return the SimObject core object given the cpu type,
and ISA target. An exception will be thrown if there is an
incompatibility.
:param cpu_type: The target CPU type.
:param isa: The target ISA.
:param core_id: The id of the core to be returned.
"""
requires(isa_required=isa)
_isa_string_map = {
ISA.X86 : "X86",
ISA.ARM : "Arm",
ISA.RISCV : "Riscv",
ISA.SPARC : "Sparc",
ISA.POWER : "Power",
ISA.MIPS : "Mips",
}
_cpu_types_string_map = {
CPUTypes.ATOMIC : "AtomicSimpleCPU",
CPUTypes.O3 : "O3CPU",
CPUTypes.TIMING : "TimingSimpleCPU",
CPUTypes.KVM : "KvmCPU"
}
if isa not in _isa_string_map:
raise NotImplementedError(f"ISA '{isa.name}' does not have an"
"entry in `AbstractCore.cpu_simobject_factory._isa_string_map`"
)
if cpu_type not in _cpu_types_string_map:
raise NotImplementedError(f"CPUType '{cpu_type.name}' "
"does not have an entry in "
"`AbstractCore.cpu_simobject_factory._cpu_types_string_map`"
)
if cpu_type == CPUTypes.KVM:
# For some reason, the KVM CPU is under "m5.objects" not the
# "m5.objects.{ISA}CPU".
module_str = f"m5.objects"
else:
module_str = f"m5.objects.{_isa_string_map[isa]}CPU"
cpu_class_str = f"{_isa_string_map[isa]}"\
f"{_cpu_types_string_map[cpu_type]}"
try:
to_return_cls = getattr(importlib.import_module(module_str),
cpu_class_str
)
except ImportError:
raise Exception(
f"Cannot find CPU type '{cpu_type.name}' for '{isa.name}' "
"ISA. Please ensure you have compiled the correct version of "
"gem5."
)
return to_return_cls(cpu_id=core_id)

View File

@@ -30,6 +30,8 @@ from ...utils.override import overrides
from .cpu_types import CPUTypes
from .abstract_core import AbstractCore
from ...isas import ISA
from ...utils.requires import requires
from typing import Optional
@@ -52,8 +54,13 @@ class AbstractGeneratorCore(AbstractCore):
# TODO: Remove the CPU Type parameter. This not needed.
# Jira issue here: https://gem5.atlassian.net/browse/GEM5-1031
super().__init__(CPUTypes.TIMING)
requires(isa_required=ISA.NULL)
self.port_end = PortTerminator()
@overrides(AbstractCore)
def get_isa(self) -> ISA:
return ISA.NULL
@overrides(AbstractCore)
def connect_icache(self, port: Port) -> None:
"""

View File

@@ -25,11 +25,14 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from abc import ABCMeta, abstractmethod
from ...utils.requires import requires
from .abstract_core import AbstractCore
from m5.objects import SubSystem
from ..boards.abstract_board import AbstractBoard
from ...isas import ISA
from typing import List
@@ -41,6 +44,13 @@ class AbstractProcessor(SubSystem):
super().__init__()
assert len(cores) > 0
# In the stdlib we assume the system processor conforms to a single
# ISA target.
assert len(set(core.get_isa() for core in cores)) == 1
self._isa = cores[0].get_isa()
requires(isa_required=self._isa)
self.cores = cores
def get_num_cores(self) -> int:
@@ -49,6 +59,9 @@ class AbstractProcessor(SubSystem):
def get_cores(self) -> List[AbstractCore]:
return self.cores
def get_isa(self) -> ISA:
return self._isa
@abstractmethod
def incorporate_processor(self, board: AbstractBoard) -> None:
raise NotImplementedError

View File

@@ -25,45 +25,50 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from typing import Optional
from ...runtime import get_runtime_isa
from python.gem5.utils.requires import requires
from ..processors.abstract_core import AbstractCore
from .cpu_types import CPUTypes
from ...isas import ISA
from ...runtime import get_runtime_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):
def __init__(
self,
cpu_type: CPUTypes,
core_id: int,
isa: Optional[ISA]= None
):
super().__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)
if isa:
requires(isa_required=isa)
self._isa = isa
else:
raise NotImplementedError
self._isa = get_runtime_isa()
self.core = AbstractCore.cpu_simobject_factory(
isa=self._isa,
cpu_type=cpu_type,
core_id=core_id
)
self.core.createThreads()
def get_simobject(self) -> BaseCPU:
return self.core
@overrides(AbstractCore)
def get_isa(self) -> ISA:
return self._isa
@overrides(AbstractCore)
def connect_icache(self, port: Port) -> None:
self.core.icache_port = port
@@ -94,7 +99,7 @@ class SimpleCore(AbstractCore):
# controller as we require it. Not sure how true this is in all cases.
self.core.createInterruptController()
if get_runtime_isa() == ISA.X86:
if self.get_isa() == ISA.X86:
if interrupt_requestor != None:
self.core.interrupts[0].pio = interrupt_requestor
self.core.interrupts[0].int_responder = interrupt_requestor

View File

@@ -33,19 +33,39 @@ from m5.util import warn
from .abstract_processor import AbstractProcessor
from .cpu_types import CPUTypes
from ...isas import ISA
from ..boards.abstract_board import AbstractBoard
from typing import Optional
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:
def __init__(
self,
cpu_type: CPUTypes,
num_cores: int,
isa: Optional[ISA] = None,
) -> None:
"""
param cpu_type: The CPU type for each type in the processor.
:
:param num_cores: The number of CPU cores in the processor.
:param isa: The ISA of the processor. This argument is optional. If not
set the `runtime.get_runtime_isa` is used to determine the ISA at
runtime. **WARNING**: This functionality is deprecated. It is
recommended you explicitly set your ISA via SimpleProcessor
construction.
"""
super().__init__(
cores=self._create_cores(
cpu_type=cpu_type,
num_cores=num_cores,
isa = isa,
)
)
@@ -55,9 +75,15 @@ class SimpleProcessor(AbstractProcessor):
self.kvm_vm = KvmVM()
def _create_cores(self, cpu_type: CPUTypes, num_cores: int):
def _create_cores(
self,
cpu_type: CPUTypes,
num_cores: int,
isa: Optional[ISA]
):
return [
SimpleCore(cpu_type=cpu_type, core_id=i) for i in range(num_cores)
SimpleCore(cpu_type=cpu_type, core_id=i, isa=isa,) \
for i in range(num_cores)
]
@overrides(AbstractProcessor)

View File

@@ -29,9 +29,12 @@ from ..boards.abstract_board import AbstractBoard
from ..processors.simple_core import SimpleCore
from ..processors.cpu_types import CPUTypes
from .switchable_processor import SwitchableProcessor
from ...isas import ISA
from ...utils.override import *
from typing import Optional
class SimpleSwitchableProcessor(SwitchableProcessor):
"""
@@ -46,7 +49,21 @@ class SimpleSwitchableProcessor(SwitchableProcessor):
starting_core_type: CPUTypes,
switch_core_type: CPUTypes,
num_cores: int,
isa: Optional[ISA] = None,
) -> None:
"""
param starting_core_type: The CPU type for each type in the processor
to start with (i.e., when the simulation has just started).
:
:param switch_core_types: The CPU type for each core, to be switched
to..
:param isa: The ISA of the processor. This argument is optional. If not
set the `runtime.get_runtime_isa` is used to determine the ISA at
runtime. **WARNING**: This functionality is deprecated. It is
recommended you explicitly set your ISA via SimpleSwitchableProcessor
construction.
"""
if num_cores <= 0:
raise AssertionError("Number of cores must be a positive integer!")
@@ -66,11 +83,11 @@ class SimpleSwitchableProcessor(SwitchableProcessor):
switchable_cores = {
self._start_key: [
SimpleCore(cpu_type=starting_core_type, core_id=i)
SimpleCore(cpu_type=starting_core_type, core_id=i, isa=isa)
for i in range(num_cores)
],
self._switch_key: [
SimpleCore(cpu_type=switch_core_type, core_id=i)
SimpleCore(cpu_type=switch_core_type, core_id=i, isa=isa)
for i in range(num_cores)
],
}

View File

@@ -28,14 +28,59 @@
Specifies the ISA enum
"""
import os
from enum import Enum
from typing import Set
class ISA(Enum):
X86 = 1
RISCV = 2
ARM = 3
MIPS = 4
POWER = 5
SPARC = 6
NULL = 7
"""
The ISA Enums which may be used in the gem5 stdlib to specify ISAs.
Their value may be used to translate the ISA to strings and compare against
inputs and environment variables.
E.g., to check if the X86 ISA is compiled:
```
if buildEnv[f"USE_{ISA.X86.value}_ISA"]:
...
```
"""
X86 = "x86"
RISCV = "riscv"
ARM = "arm"
MIPS = "mips"
POWER = "power"
SPARC = "sparc"
NULL = "null"
def get_isas_str_set() -> Set[ISA]:
"""
Returns a set of all the ISA as strings.
"""
return {isa.value for isa in ISA}
def get_isa_from_str(input: str) -> ISA:
"""
Will return the correct enum given the input string. This is matched on
the enum's value. E.g., "x86" will return ISA.X86. Throws an exception if
the input string is invalid.
`get_isas_str_set()` can be used to determine the valid strings.
This is for parsing text inputs that specify ISA targets.
:param input: The ISA to return, as a string. Case-insensitive.
"""
for isa in ISA:
if input.lower() == isa.value:
return isa
valid_isas_str_list =str()
for isa_str in get_isa_from_str():
valid_isas_str_list += f"{os.linesep}{isa_str}"
raise Exception(
f"Value '{input}' does not correspond to a known ISA. Known ISAs:"
f"{valid_isas_str_list}"
)

View File

@@ -75,7 +75,11 @@ class X86DemoBoard(X86Board):
"real-world system. Use with caution.")
memory = SingleChannelDDR3_1600(size="2GB")
processor = SimpleProcessor(cpu_type=CPUTypes.TIMING, num_cores=4)
processor = SimpleProcessor(
cpu_type=CPUTypes.TIMING,
isa=ISA.X86,
num_cores=4
)
cache_hierarchy = MESITwoLevelCacheHierarchy(
l1d_size="32kB",
l1d_assoc=8,

View File

@@ -29,34 +29,86 @@ This file contains functions to extract gem5 runtime information.
"""
from m5.defines import buildEnv
from m5.util import warn
import os
from .isas import ISA
from .isas import ISA, get_isa_from_str, get_isas_str_set
from .coherence_protocol import CoherenceProtocol
from typing import Set
from m5 import options
def get_supported_isas() -> Set[ISA]:
supported_isas = set()
# This if-statement is an intermediate step so the stdlib works on the
# "old style" of determining the available ISA (via the "TARGET_ISA"
# environment variable) and the "new style" which enables multiple ISAs
# (via the "USE_X_ISA" environment variables). Once multiple ISAs are fully
# incorporated, this code may be simplified.
if "TARGET_ISA" in buildEnv.keys():
supported_isas.add(get_isa_from_str(buildEnv["TARGET_ISA"]))
else:
for key in get_isas_str_set:
if buildEnv[f"USE_{key.upper()}_ISA"]:
supported_isas.add(get_isa_from_str(key))
return supported_isas
def get_runtime_isa() -> ISA:
"""Gets the target ISA.
This can be inferred at runtime.
"""Returns a single target ISA at runtime.
This is inferred at runtime and is assumed to be the ISA target ISA.
This is determined one of two ways:
1. The gem5 binary is compiled to one ISA target.
2. The user specifies the target ISA via gem5's `--main-isa` parameter.
**WARNING**: This function is deprecated and may be removed in future
versions of gem5. This function should not be relied upon to run gem5
simulations.
: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."
)
warn("The `get_runtime_isa` function is deprecated. Please migrate away "
"from using this function.")
return isa_map[isa_str]
supported = get_supported_isas()
main_isa_param = options.main_isa
supported_list_str = ""
for isa in supported:
supported_list_str += f"{os.linesep}{isa.name}"
if not main_isa_param:
if len(supported) == 1:
# In this case, where the main_isa_param is not specified, but only
# one ISA is compiled, we go with the ISA that has been compiled.
return next(iter(supported))
# If there are multiple supported ISAs, but no main ISA specified, we
# raise an exception.
raise Exception("The gem5 binary is compiled with multiple-ISAs. "
"Please specify which you require using the "
"`--main-isa` parameter when running gem5. "
f"Supported ISAs: {supported_list_str}"
)
assert main_isa_param
main_isa = get_isa_from_str(main_isa_param)
if main_isa not in supported:
# In the case the user has specified an ISA not compiled into
# the binary.
raise Exception(f"The ISA specified via the `--main-isa` "
f"parameter, '{main_isa_param}', has not been "
f"compiled into the binary. ISAs available: "
f"{supported_list_str}."
)
return main_isa
def get_runtime_coherence_protocol() -> CoherenceProtocol:

View File

@@ -24,7 +24,7 @@
# (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 ..runtime import get_runtime_coherence_protocol, get_supported_isas
from ..isas import ISA
from ..coherence_protocol import CoherenceProtocol
from typing import Optional
@@ -59,7 +59,7 @@ def requires(
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 isa_required: The ISA(s) 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
@@ -68,18 +68,37 @@ def requires(
protocol do not match that of the current gem5 binary.
"""
runtime_isa = get_runtime_isa()
supported_isas = get_supported_isas()
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.value != runtime_isa.value:
raise Exception(
_get_exception_str(
msg="The current ISA is '{}'. Required: '{}'".format(
runtime_isa.name, isa_required.name
)
)
)
# Note, previously I had the following code here:
#
# `if isa_required != None and isa_required not in supported_isas:`
#
# However, for reasons I do not currently understand, I frequently
# encountered errors such as the following:
#
# ```
# Exception: The required ISA is 'RISCV'. Supported ISAs:
# SPARC
# RISCV
# ARM
# X86
# POWER
# MIPS
# ```
#
# I do not know why this happens and my various attempts at tracking down
# why the enum did not compare correctly yielded no results. The following
# code works, even though it is verbose and appears functionally equivalent
# to the original code.
if isa_required != None and isa_required.value not in \
(isa.value for isa in supported_isas):
msg=f"The required ISA is '{isa_required.name}'. Supported ISAs: "
for isa in supported_isas:
msg += f"{os.linesep}{isa.name}"
raise Exception(_get_exception_str(msg=msg))
if (
coherence_protocol_required != None

View File

@@ -107,6 +107,12 @@ def parse_options():
help="Reduce verbosity")
option('-v', "--verbose", action="count", default=0,
help="Increase verbosity")
option('--main-isa', action='store', default=None,
help='Select the main target ISA. This dictates what the '
'`gem5.runtime.get_runtime_isa()` function returns when multiple '
'ISAs are compiled into the gem5 binary. Note: This functionality '
'is deprecated. The `gem5.runtime.get_runtime_isa()` function will '
'be removed in future releases of gem5.')
# Statistics options
group("Statistics Options")