diff --git a/spinn_machine/ignores/ignore_core.py b/spinn_machine/ignores/ignore_core.py index 70fae128..ae1f0fe5 100644 --- a/spinn_machine/ignores/ignore_core.py +++ b/spinn_machine/ignores/ignore_core.py @@ -11,17 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import re -from typing import Any, Iterable, List, Optional, Set, Union +from typing import Any, List, Optional, Set, Union from typing_extensions import TypeAlias +from spinn_machine.data import MachineDataView + _Intable: TypeAlias = Union[int, str] TYPICAL_PHYSICAL_VIRTUAL_MAP = { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 0, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18} -CORE_RANGE = re.compile(r"(\d+)-(\d+)") - class IgnoreCore(object): """ @@ -69,21 +68,6 @@ def virtual_p(self) -> int: else: return TYPICAL_PHYSICAL_VIRTUAL_MAP[0-self.p] - @staticmethod - def parse_cores(core_string: str) -> Iterable[int]: - """ - Parses the "core" part of a string, which might be a single core, - or otherwise is a range of cores - - :param str: A string to parse - :return: A list of cores, which might be just one - :rtype: list(int) - """ - result = CORE_RANGE.fullmatch(core_string) - if result is not None: - return range(int(result.group(1)), int(result.group(2)) + 1) - return (int(core_string),) - @staticmethod def parse_single_string(downed_core: str) -> List['IgnoreCore']: """ @@ -113,14 +97,15 @@ def parse_single_string(downed_core: str) -> List['IgnoreCore']: :return: A list of IgnoreCore objects :rtype: list(IgnoreCore) """ + version = MachineDataView.get_machine_version() parts = downed_core.split(",") if len(parts) == 3: return [IgnoreCore(parts[0], parts[1], core) - for core in IgnoreCore.parse_cores(parts[2])] + for core in version.parse_cores_string(parts[2])] elif len(parts) == 4: return [IgnoreCore(parts[0], parts[1], core, parts[3]) - for core in IgnoreCore.parse_cores(parts[2])] + for core in version.parse_cores_string(parts[2])] else: raise ValueError(f"Unexpected downed_core: {downed_core}") diff --git a/spinn_machine/version/abstract_version.py b/spinn_machine/version/abstract_version.py index a8558c8a..6ff2cd79 100644 --- a/spinn_machine/version/abstract_version.py +++ b/spinn_machine/version/abstract_version.py @@ -13,7 +13,10 @@ # limitations under the License. from __future__ import annotations import logging -from typing import Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING +import re +from typing import (Dict, Iterable, List, Optional, Sequence, Tuple, + TYPE_CHECKING) + from spinn_utilities.abstract_base import AbstractBase, abstractmethod from spinn_utilities.log import FormatAdapter from spinn_utilities.config_holder import get_config_int_or_none @@ -25,6 +28,9 @@ logger = FormatAdapter(logging.getLogger(__name__)) +CORE_RANGE = re.compile(r"(\d+)-(\d+)") +CORE_SINGLE = re.compile(r"(-*)(\d+)") + class AbstractVersion(object, metaclass=AbstractBase): """ @@ -417,6 +423,7 @@ def supports_multiple_boards(self) -> bool: """ raise NotImplementedError + @abstractmethod def spinnaker_links(self) -> List[Tuple[int, int, int]]: """ The list of Local X, Y and link Id to add spinnaker links to @@ -428,6 +435,7 @@ def spinnaker_links(self) -> List[Tuple[int, int, int]]: """ raise NotImplementedError + @abstractmethod def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: """ The list of Local X, Y, link, fpga_link_id and fpga_id @@ -439,6 +447,7 @@ def fpga_links(self) -> List[Tuple[int, int, int, int, int]]: """ raise NotImplementedError + @abstractmethod def quads_maps(self) -> Optional[Dict[int, Tuple[int, int, int]]]: """ If applicable returns a map of virtual id to quad qx, qy, qp @@ -448,3 +457,73 @@ def quads_maps(self) -> Optional[Dict[int, Tuple[int, int, int]]]: :rtype: None or dict(int, (int, int, int) """ raise NotImplementedError + + @abstractmethod + def qx_qy_qp_to_id(self, qx: int, qy: int, qp: int) -> int: + """ + Converts quad coordinates to the core id + + :param int qx: quad x coordinate of the core + :param int qy: quad y coordinate of the core + :param int qp: quad p coordinate of the core + :rtype: int + :raises NotImplementedError: + If called on a version that does not support quads + """ + raise NotImplementedError + + @abstractmethod + def id_to_qx_qy_qp(self, core_id: int) -> Tuple[int, int, int]: + """ + Converts core id to quad coordinates + + :param int core_id: id of the core + :return: (qx, qy, qp) + :rtype: (int, int, int) + :raises NotImplementedError: + If called on a version that does not support quads + """ + raise NotImplementedError + + def parse_cores_string(self, core_string: str) -> Iterable[int]: + """ + Parses a string representation of a core or cores + + The main usage of this method is to support the cfg down_cores. + + This may be a single positive int + which will be taken as the virtual core id + + This may be a single negative int + which will be taken as the physical core id + + This may be two int values separated by a minus + which will be taken as a range of one of the above + + Other formats are version specific. + See version_parse_cores_string + + :param str: A string to parse + :return: A list of cores, which might be just one + :rtype: list(int) + """ + result = CORE_SINGLE.fullmatch(core_string) + if result is not None: + return (int(core_string),) + + result = CORE_RANGE.fullmatch(core_string) + if result is not None: + return range(int(result.group(1)), int(result.group(2)) + 1) + + return self.version_parse_cores_string(core_string) + + @abstractmethod + def version_parse_cores_string(self, core_string: str) -> Iterable[int]: + """ + A version specific parsing of the core string + + :param str core_string: + :return: A list of cores, which might be just one + :rtype: list(int) + """ + raise NotImplementedError diff --git a/spinn_machine/version/version_spin1.py b/spinn_machine/version/version_spin1.py index aa814781..ab0077a8 100644 --- a/spinn_machine/version/version_spin1.py +++ b/spinn_machine/version/version_spin1.py @@ -12,9 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import List +from typing import List, Iterable, Tuple from spinn_utilities.abstract_base import AbstractBase +from spinn_utilities.exceptions import ConfigException from spinn_utilities.overrides import overrides + +from spinn_machine.exceptions import SpinnMachineException from .abstract_version import AbstractVersion @@ -54,5 +57,19 @@ def clock_speeds_hz(self) -> List[int]: def dtcm_bytes(self) -> int: return 2 ** 16 + @overrides(AbstractVersion.quads_maps) def quads_maps(self) -> None: return None + + @overrides(AbstractVersion.qx_qy_qp_to_id) + def qx_qy_qp_to_id(self, qx: int, qy: int, qp: int) -> int: + raise SpinnMachineException("Not supported in Version 1") + + @overrides(AbstractVersion.id_to_qx_qy_qp) + def id_to_qx_qy_qp(self, core_id: int) -> Tuple[int, int, int]: + raise SpinnMachineException("Not supported in Version 1") + + @overrides(AbstractVersion.version_parse_cores_string) + def version_parse_cores_string(self, core_string: str) -> Iterable[int]: + raise ConfigException( + f"{core_string} does not represent cores for Version 1 boards") diff --git a/spinn_machine/version/version_spin2.py b/spinn_machine/version/version_spin2.py index 9eaa07ec..709ca76d 100644 --- a/spinn_machine/version/version_spin2.py +++ b/spinn_machine/version/version_spin2.py @@ -12,14 +12,56 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Final, List, Tuple +import re +from typing import Dict, Final, List, Iterable, Tuple from spinn_utilities.abstract_base import AbstractBase +from spinn_utilities.exceptions import ConfigException from spinn_utilities.overrides import overrides from .abstract_version import AbstractVersion CHIPS_PER_BOARD: Final = {(0, 0): 152} +CORE_QX_QY_QP = re.compile(r"(\d)\.(\d)\.(\d)") +QUAD_MAP = ( + {0: (0, 0, 0), 1: (7, 6, 0), 2: (7, 6, 1), 3: (7, 6, 2), 4: (7, 6, 3), + 5: (7, 5, 0), 6: (7, 5, 1), 7: (7, 5, 2), 8: (7, 5, 3), + 9: (6, 6, 0), 10: (6, 6, 1), 11: (6, 6, 2), 12: (6, 6, 3), + 13: (6, 5, 0), 14: (6, 5, 1), 15: (6, 5, 2), 16: (6, 5, 3), + 17: (6, 4, 0), 18: (6, 4, 1), 19: (6, 4, 2), 20: (6, 4, 3), + 21: (5, 4, 0), 22: (5, 4, 1), 23: (5, 4, 2), 24: (5, 4, 3), + 25: (5, 6, 0), 26: (5, 6, 1), 27: (5, 6, 2), 28: (5, 6, 3), + 29: (3, 6, 0), 30: (3, 6, 1), 31: (3, 6, 2), 32: (3, 6, 3), + 33: (4, 6, 0), 34: (4, 6, 1), 35: (4, 6, 2), 36: (4, 6, 3), + 37: (5, 5, 0), 38: (5, 5, 1), 39: (5, 5, 2), 40: (5, 5, 3), + 41: (3, 5, 0), 42: (3, 5, 1), 43: (3, 5, 2), 44: (3, 5, 3), + 45: (4, 5, 0), 46: (4, 5, 1), 47: (4, 5, 2), 48: (4, 5, 3), + 49: (1, 6, 0), 50: (1, 6, 1), 51: (1, 6, 2), 52: (1, 6, 3), + 53: (2, 6, 0), 54: (2, 6, 1), 55: (2, 6, 2), 56: (2, 6, 3), + 57: (1, 5, 0), 58: (1, 5, 1), 59: (1, 5, 2), 60: (1, 5, 3), + 61: (2, 5, 0), 62: (2, 5, 1), 63: (2, 5, 2), 64: (2, 5, 3), + 65: (1, 4, 0), 66: (1, 4, 1), 67: (1, 4, 2), 68: (1, 4, 3), + 69: (2, 4, 0), 70: (2, 4, 1), 71: (2, 4, 2), 72: (2, 4, 3), + 73: (3, 4, 0), 74: (3, 4, 1), 75: (3, 4, 2), 76: (3, 4, 3), + 77: (1, 1, 0), 78: (1, 1, 1), 79: (1, 1, 2), 80: (1, 1, 3), + 81: (2, 1, 0), 82: (2, 1, 1), 83: (2, 1, 2), 84: (2, 1, 3), + 85: (1, 2, 0), 86: (1, 2, 1), 87: (1, 2, 2), 88: (1, 2, 3), + 89: (2, 2, 0), 90: (2, 2, 1), 91: (2, 2, 2), 92: (2, 2, 3), + 93: (1, 3, 0), 94: (1, 3, 1), 95: (1, 3, 2), 96: (1, 3, 3), + 97: (2, 3, 0), 98: (2, 3, 1), 99: (2, 3, 2), 100: (2, 3, 3), + 101: (3, 3, 0), 102: (3, 3, 1), 103: (3, 3, 2), 104: (3, 3, 3), + 105: (5, 1, 0), 106: (5, 1, 1), 107: (5, 1, 2), 108: (5, 1, 3), + 109: (3, 1, 0), 110: (3, 1, 1), 111: (3, 1, 2), 112: (3, 1, 3), + 113: (4, 1, 0), 114: (4, 1, 1), 115: (4, 1, 2), 116: (4, 1, 3), + 117: (5, 2, 0), 118: (5, 2, 1), 119: (5, 2, 2), 120: (5, 2, 3), + 121: (3, 2, 0), 122: (3, 2, 1), 123: (3, 2, 2), 124: (3, 2, 3), + 125: (4, 2, 0), 126: (4, 2, 1), 127: (4, 2, 2), 128: (4, 2, 3), + 129: (7, 1, 0), 130: (7, 1, 1), 131: (7, 1, 2), 132: (7, 1, 3), + 133: (6, 1, 0), 134: (6, 1, 1), 135: (6, 1, 2), 136: (6, 1, 3), + 137: (7, 2, 0), 138: (7, 2, 1), 139: (7, 2, 2), 140: (7, 2, 3), + 141: (6, 2, 0), 142: (6, 2, 1), 143: (6, 2, 2), 144: (6, 2, 3), + 145: (6, 3, 0), 146: (6, 3, 1), 147: (6, 3, 2), 148: (6, 3, 3), + 149: (5, 3, 0), 150: (5, 3, 1), 151: (5, 3, 2), 152: (5, 3, 3)}) class VersionSpin2(AbstractVersion, metaclass=AbstractBase): @@ -28,11 +70,13 @@ class VersionSpin2(AbstractVersion, metaclass=AbstractBase): Code for the 1 Chip test Spin2 board versions """ - __slots__ = () + __slots__ = ["_reverse_quad_map"] def __init__(self) -> None: super().__init__(max_cores_per_chip=153, max_sdram_per_chip=1073741824) + self._reverse_quad_map: Dict[Tuple[int, int, int], int] = ( + dict((v, k) for k, v in QUAD_MAP.items())) @property @overrides(AbstractVersion.n_scamp_cores) @@ -59,44 +103,26 @@ def clock_speeds_hz(self) -> List[int]: def dtcm_bytes(self) -> int: raise NotImplementedError + @overrides(AbstractVersion.quads_maps) def quads_maps(self) -> Dict[int, Tuple[int, int, int]]: - return ( - {0: (0, 0, 0), - 1: (7, 6, 0), 2: (7, 6, 1), 3: (7, 6, 2), 4: (7, 6, 3), - 5: (7, 5, 0), 6: (7, 5, 1), 7: (7, 5, 2), 8: (7, 5, 3), - 9: (6, 6, 0), 10: (6, 6, 1), 11: (6, 6, 2), 12: (6, 6, 3), - 13: (6, 5, 0), 14: (6, 5, 1), 15: (6, 5, 2), 16: (6, 5, 3), - 17: (6, 4, 0), 18: (6, 4, 1), 19: (6, 4, 2), 20: (6, 4, 3), - 21: (5, 4, 0), 22: (5, 4, 1), 23: (5, 4, 2), 24: (5, 4, 3), - 25: (5, 6, 0), 26: (5, 6, 1), 27: (5, 6, 2), 28: (5, 6, 3), - 29: (3, 6, 0), 30: (3, 6, 1), 31: (3, 6, 2), 32: (3, 6, 3), - 33: (4, 6, 0), 34: (4, 6, 1), 35: (4, 6, 2), 36: (4, 6, 3), - 37: (5, 5, 0), 38: (5, 5, 1), 39: (5, 5, 2), 40: (5, 5, 3), - 41: (3, 5, 0), 42: (3, 5, 1), 43: (3, 5, 2), 44: (3, 5, 3), - 45: (4, 5, 0), 46: (4, 5, 1), 47: (4, 5, 2), 48: (4, 5, 3), - 49: (1, 6, 0), 50: (1, 6, 1), 51: (1, 6, 2), 52: (1, 6, 3), - 53: (2, 6, 0), 54: (2, 6, 1), 55: (2, 6, 2), 56: (2, 6, 3), - 57: (1, 5, 0), 58: (1, 5, 1), 59: (1, 5, 2), 60: (1, 5, 3), - 61: (2, 5, 0), 62: (2, 5, 1), 63: (2, 5, 2), 64: (2, 5, 3), - 65: (1, 4, 0), 66: (1, 4, 1), 67: (1, 4, 2), 68: (1, 4, 3), - 69: (2, 4, 0), 70: (2, 4, 1), 71: (2, 4, 2), 72: (2, 4, 3), - 73: (3, 4, 0), 74: (3, 4, 1), 75: (3, 4, 2), 76: (3, 4, 3), - 77: (1, 1, 0), 78: (1, 1, 1), 79: (1, 1, 2), 80: (1, 1, 3), - 81: (2, 1, 0), 82: (2, 1, 1), 83: (2, 1, 2), 84: (2, 1, 3), - 85: (1, 2, 0), 86: (1, 2, 1), 87: (1, 2, 2), 88: (1, 2, 3), - 89: (2, 2, 0), 90: (2, 2, 1), 91: (2, 2, 2), 92: (2, 2, 3), - 93: (1, 3, 0), 94: (1, 3, 1), 95: (1, 3, 2), 96: (1, 3, 3), - 97: (2, 3, 0), 98: (2, 3, 1), 99: (2, 3, 2), 100: (2, 3, 3), - 101: (3, 3, 0), 102: (3, 3, 1), 103: (3, 3, 2), 104: (3, 3, 3), - 105: (5, 1, 0), 106: (5, 1, 1), 107: (5, 1, 2), 108: (5, 1, 3), - 109: (3, 1, 0), 110: (3, 1, 1), 111: (3, 1, 2), 112: (3, 1, 3), - 113: (4, 1, 0), 114: (4, 1, 1), 115: (4, 1, 2), 116: (4, 1, 3), - 117: (5, 2, 0), 118: (5, 2, 1), 119: (5, 2, 2), 120: (5, 2, 3), - 121: (3, 2, 0), 122: (3, 2, 1), 123: (3, 2, 2), 124: (3, 2, 3), - 125: (4, 2, 0), 126: (4, 2, 1), 127: (4, 2, 2), 128: (4, 2, 3), - 129: (7, 1, 0), 130: (7, 1, 1), 131: (7, 1, 2), 132: (7, 1, 3), - 133: (6, 1, 0), 134: (6, 1, 1), 135: (6, 1, 2), 136: (6, 1, 3), - 137: (7, 2, 0), 138: (7, 2, 1), 139: (7, 2, 2), 140: (7, 2, 3), - 141: (6, 2, 0), 142: (6, 2, 1), 143: (6, 2, 2), 144: (6, 2, 3), - 145: (6, 3, 0), 146: (6, 3, 1), 147: (6, 3, 2), 148: (6, 3, 3), - 149: (5, 3, 0), 150: (5, 3, 1), 151: (5, 3, 2), 152: (5, 3, 3)}) + return QUAD_MAP + + @overrides(AbstractVersion.qx_qy_qp_to_id) + def qx_qy_qp_to_id(self, qx: int, qy: int, qp: int) -> int: + return self._reverse_quad_map[(qx, qy, qp)] + + @overrides(AbstractVersion.id_to_qx_qy_qp) + def id_to_qx_qy_qp(self, core_id: int) -> Tuple[int, int, int]: + return QUAD_MAP[core_id] + + @overrides(AbstractVersion.version_parse_cores_string) + def version_parse_cores_string(self, core_string: str) -> Iterable[int]: + result = CORE_QX_QY_QP.fullmatch(core_string) + if result is not None: + qx = int(result.group(1)) + qy = int(result.group(2)) + qp = int(result.group(3)) + return (self.qx_qy_qp_to_id(qx, qy, qp),) + + raise ConfigException( + f"{core_string} does not represent cores for Version 2 boards") diff --git a/unittests/test_ignore_cores.py b/unittests/test_ignore_cores.py new file mode 100644 index 00000000..c955eaf1 --- /dev/null +++ b/unittests/test_ignore_cores.py @@ -0,0 +1,76 @@ +# Copyright (c) 2024 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from spinn_utilities.config_holder import set_config +from spinn_utilities.exceptions import ConfigException +from spinn_machine.config_setup import unittest_setup +from spinn_machine.exceptions import SpinnMachineException +from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink +from spinn_machine.version import SPIN2_1CHIP +from spinn_machine.version.version_201 import Version201 +from spinn_machine.version.version_5 import Version5 +from spinn_machine.version.version_strings import VersionStrings + + +class TestDownCores(unittest.TestCase): + + def setUp(self): + unittest_setup() + + def test_bad_ignores(self): + set_config("Machine", "versions", VersionStrings.BIG.text) + + try: + IgnoreChip.parse_string("4,4,3,4:6,6,ignored_ip") + except Exception as ex: + self.assertTrue("downed_chip" in str(ex)) + + try: + IgnoreCore.parse_string("3,3,3,4: 5,5,-5:7,7,7,ignored_ip") + except Exception as ex: + self.assertTrue("downed_core" in str(ex)) + + empty = IgnoreCore.parse_string(None) + self.assertEqual(len(empty), 0) + + try: + IgnoreLink.parse_string("1,3:5,3,3,ignored_ip") + except Exception as ex: + self.assertTrue("downed_link" in str(ex)) + + def test_down_cores_bad_string(self): + set_config("Machine", "versions", VersionStrings.BIG.text) + with self.assertRaises(ConfigException): + IgnoreCore.parse_string("4,4,bacon") + + def test_qx_qy_qp_to_id_spin2(self): + version = Version201() + self.assertEqual(75, version.qx_qy_qp_to_id(3, 4, 2)) + self.assertEqual((3, 4, 2), version.id_to_qx_qy_qp(75)) + + def test_qx_qy_qp_to_spin1(self): + version = Version5() + with self.assertRaises(SpinnMachineException): + self.assertEqual(75, version.qx_qy_qp_to_id(3, 4, 2)) + with self.assertRaises(SpinnMachineException): + self.assertEqual((3, 4, 2), version.id_to_qx_qy_qp(75)) + + def test_version_401(self): + set_config("Machine", "version", SPIN2_1CHIP) + ignores = IgnoreCore.parse_string("0,0,3.4.2") + self.assertEqual(1, len(ignores)) + for ignore in ignores: + self.assertEqual(75, ignore.p) + self.assertEqual(75, ignore.virtual_p) diff --git a/unittests/test_using_virtual_machine.py b/unittests/test_using_virtual_machine.py index 971a7fe0..15021254 100644 --- a/unittests/test_using_virtual_machine.py +++ b/unittests/test_using_virtual_machine.py @@ -20,7 +20,6 @@ virtual_machine_by_boards, virtual_machine_by_min_size) from spinn_machine.data import MachineDataView from spinn_machine.exceptions import (SpinnMachineException) -from spinn_machine.ignores import IgnoreChip, IgnoreCore, IgnoreLink from spinn_machine.machine_factory import machine_repair from spinn_machine.version.version_strings import VersionStrings from spinn_machine.version.version_5 import CHIPS_PER_BOARD @@ -343,25 +342,6 @@ def test_ignores(self): for i in range(12, 18): self.assertTrue(chip.is_processor_with_id(i)) - def test_bad_ignores(self): - try: - IgnoreChip.parse_string("4,4,3,4:6,6,ignored_ip") - except Exception as ex: - self.assertTrue("downed_chip" in str(ex)) - - try: - IgnoreCore.parse_string("3,3,3,4: 5,5,-5:7,7,7,ignored_ip") - except Exception as ex: - self.assertTrue("downed_core" in str(ex)) - - empty = IgnoreCore.parse_string(None) - self.assertEqual(len(empty), 0) - - try: - IgnoreLink.parse_string("1,3:5,3,3,ignored_ip") - except Exception as ex: - self.assertTrue("downed_link" in str(ex)) - if __name__ == '__main__': unittest.main() diff --git a/unittests/test_virtual_machine201.py b/unittests/test_virtual_machine201.py index 547a3005..2c9dc41a 100644 --- a/unittests/test_virtual_machine201.py +++ b/unittests/test_virtual_machine201.py @@ -14,8 +14,10 @@ import unittest from spinn_utilities.config_holder import set_config -from spinn_machine.config_setup import unittest_setup + from spinn_machine import Chip, Link, Router, virtual_machine +from spinn_machine.config_setup import unittest_setup +from spinn_machine.data import MachineDataView from spinn_machine.exceptions import ( SpinnMachineException, SpinnMachineAlreadyExistsException) from spinn_machine.version import SPIN2_1CHIP @@ -254,6 +256,16 @@ def test_by_cores_too_many(self): with self.assertRaises(SpinnMachineException): virtual_machine_by_boards(2) + def test_down(self): + set_config("Machine", "version", SPIN2_1CHIP) + set_config("Machine", "down_cores", "0,0,2.2.1") + version = MachineDataView.get_machine_version() + self.assertEqual(90, version.qx_qy_qp_to_id(2, 2, 1)) + + machine = virtual_machine_by_cores(1) + chip = machine[(0, 0)] + self.assertFalse(chip.is_processor_with_id(90)) + if __name__ == '__main__': unittest.main()