Beispiel #1
0
    def test_read_libs(self) -> None:
        """
        Test that HammerTool can read technology IP libraries and filter/process them.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir(
            "dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        HammerToolTestHelpers.write_tech_json(tech_json_filename)
        tech = self.get_tech(
            hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("")

        class Tool(SingleStepTool):
            def step(self) -> bool:
                def test_tool_format(lib, filt) -> List[str]:
                    return ["drink {0}".format(lib)]

                self._read_lib_output = tech.read_libs(
                    [hammer_tech.filters.milkyway_techfile_filter],
                    test_tool_format,
                    must_exist=False)

                self._test_filter_output = tech.read_libs(
                    [HammerToolTestHelpers.make_test_filter()],
                    test_tool_format,
                    must_exist=False)
                return True

        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        database = hammer_config.HammerDatabase()
        test.set_database(database)
        tech.set_database(database)
        test.run()

        # Don't care about ordering here.
        self.assertEqual(set(test._read_lib_output), {
            "drink {0}/soy".format(tech_dir),
            "drink {0}/coconut".format(tech_dir)
        })

        # We do care about ordering here.
        self.assertEqual(test._test_filter_output, [
            "drink {0}/tea".format(tech_dir),
            "drink {0}/grapefruit".format(tech_dir),
            "drink {0}/juice".format(tech_dir),
            "drink {0}/orange".format(tech_dir)
        ])

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #2
0
 def __init__(self, test: unittest.TestCase, tool_type: str) -> None:
     self.test = test  # type unittest.TestCase
     self.logger = HammerVLSILogging.context("")
     self._driver = None  # type: Optional[hammer_vlsi.HammerDriver]
     if tool_type not in ["sram_generator"]:
         raise NotImplementedError("Have not created a test for %s yet" % (tool_type))
     self._tool_type = tool_type
Beispiel #3
0
    def test_macro_sizes(self) -> None:
        """
        Test that getting macro sizes works as expected.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir(
            "dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")

        def add_lib_with_lef(d: Dict[str, Any]) -> Dict[str, Any]:
            with open(os.path.join(tech_dir, 'my_vendor_lib.lef'), 'w') as f:
                f.write("""VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;

MACRO my_awesome_macro
  CLASS BLOCK ;
  ORIGIN -0.435 607.525 ;
  FOREIGN my_awesome_macro 0.435 -607.525 ;
  SIZE 810.522 BY 607.525 ;
  SYMMETRY X Y R90 ;
END my_awesome_macro

END LIBRARY
                """)
            r = deepdict(d)
            r['libraries'].append({
                'name': 'my_vendor_lib',
                'lef file': 'test/my_vendor_lib.lef'
            })
            return r

        HammerToolTestHelpers.write_tech_json(tech_json_filename,
                                              add_lib_with_lef)
        tech_opt = hammer_tech.HammerTechnology.load_from_dir(
            "dummy28", tech_dir)
        if tech_opt is None:
            self.assertTrue(False, "Unable to load technology")
            return
        else:
            tech = tech_opt  # type: hammer_tech.HammerTechnology
        tech.cache_dir = tech_dir

        tech.logger = HammerVLSILogging.context("")

        database = hammer_config.HammerDatabase()
        tech.set_database(database)

        # Test that macro sizes can be read out of the LEF.
        self.assertEqual(tech.get_macro_sizes(), [
            hammer_tech.MacroSize(library='my_vendor_lib',
                                  name='my_awesome_macro',
                                  width=Decimal("810.522"),
                                  height=Decimal("607.525"))
        ])

        # Cleanup
        shutil.rmtree(tech_dir_base)
Beispiel #4
0
 def __init__(self, test: unittest.TestCase, tool_type: str) -> None:
     self.test = test  # type unittest.TestCase
     self.logger = HammerVLSILogging.context("")
     self._driver = None  # type: Optional[hammer_vlsi.HammerDriver]
     if tool_type not in ["drc", "lvs"]:
         raise NotImplementedError("Have not created a test for %s yet" %
                                   (tool_type))
     self._tool_type = tool_type
Beispiel #5
0
    def test_read_libs(self) -> None:
        """
        Test that HammerTool can read technology IP libraries and filter/process them.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir("dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        HammerToolTestHelpers.write_tech_json(tech_json_filename)
        tech = self.get_tech(hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("")

        class Tool(SingleStepTool):
            def step(self) -> bool:
                def test_tool_format(lib, filt) -> List[str]:
                    return ["drink {0}".format(lib)]

                self._read_lib_output = tech.read_libs([hammer_tech.filters.milkyway_techfile_filter], test_tool_format, must_exist=False)

                self._test_filter_output = tech.read_libs([HammerToolTestHelpers.make_test_filter()], test_tool_format, must_exist=False)
                return True
        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        database = hammer_config.HammerDatabase()
        test.set_database(database)
        tech.set_database(database)
        test.run()

        # Don't care about ordering here.
        self.assertEqual(set(test._read_lib_output),
                         {"drink {0}/soy".format(tech_dir), "drink {0}/coconut".format(tech_dir)})

        # We do care about ordering here.
        self.assertEqual(test._test_filter_output, [
            "drink {0}/tea".format(tech_dir),
            "drink {0}/grapefruit".format(tech_dir),
            "drink {0}/juice".format(tech_dir),
            "drink {0}/orange".format(tech_dir)
        ])

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #6
0
 def __init__(self, test: unittest.TestCase, cmd_type: str) -> None:
     self.echo_command_args = ["go", "bears", "!"]
     self.echo_command = ["echo"] + self.echo_command_args
     self.test = test  # type unittest.TestCase
     self.logger = HammerVLSILogging.context("")
     self._driver = None  # type: Optional[hammer_vlsi.HammerDriver]
     if cmd_type not in ["lsf", "local"]:
         raise NotImplementedError("Have not built a test for %s yet" % cmd_type)
     self._cmd_type = cmd_type
     self._submit_command = None  # type: Optional[hammer_vlsi.HammerSubmitCommand]
Beispiel #7
0
 def __init__(self, test: unittest.TestCase, cmd_type: str) -> None:
     self.echo_command_args = ["go", "bears", "!"]
     self.echo_command = ["echo"] + self.echo_command_args
     self.test = test  # type unittest.TestCase
     self.logger = HammerVLSILogging.context("")
     self._driver = None  # type: Optional[hammer_vlsi.HammerDriver]
     if cmd_type not in ["lsf", "local"]:
         raise NotImplementedError("Have not built a test for %s yet" %
                                   cmd_type)
     self._cmd_type = cmd_type
     self._submit_command = None  # type: Optional[hammer_vlsi.HammerSubmitCommand]
Beispiel #8
0
    def test_macro_sizes(self) -> None:
        """
        Test that getting macro sizes works as expected.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir("dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")

        def add_lib_with_lef(d: Dict[str, Any]) -> Dict[str, Any]:
            with open(os.path.join(tech_dir, 'my_vendor_lib.lef'), 'w') as f:
                f.write("""VERSION 5.8 ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;

MACRO my_awesome_macro
  CLASS BLOCK ;
  ORIGIN -0.435 607.525 ;
  FOREIGN my_awesome_macro 0.435 -607.525 ;
  SIZE 810.522 BY 607.525 ;
  SYMMETRY X Y R90 ;
END my_awesome_macro

END LIBRARY
                """)
            r = deepdict(d)
            r['libraries'].append({
                'name': 'my_vendor_lib',
                'lef file': 'test/my_vendor_lib.lef'
            })
            return r

        HammerToolTestHelpers.write_tech_json(tech_json_filename, add_lib_with_lef)
        tech_opt = hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir)
        if tech_opt is None:
            self.assertTrue(False, "Unable to load technology")
            return
        else:
            tech = tech_opt  # type: hammer_tech.HammerTechnology
        tech.cache_dir = tech_dir

        tech.logger = HammerVLSILogging.context("")

        database = hammer_config.HammerDatabase()
        tech.set_database(database)

        # Test that macro sizes can be read out of the LEF.
        self.assertEqual(tech.get_macro_sizes(), [
            hammer_tech.MacroSize(library='my_vendor_lib', name='my_awesome_macro',
                                  width=810.522, height=607.525)
        ])

        # Cleanup
        shutil.rmtree(tech_dir_base)
Beispiel #9
0
    def test_file_logging(self):
        fd, path = tempfile.mkstemp(".log")
        os.close(fd) # Don't leak file descriptors

        filelogger = HammerVLSIFileLogger(path)

        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(filelogger.callback)
        log = HammerVLSILogging.context()
        log.info("Hello world")
        log.info("Eternal voyage to the edge of the universe")
        filelogger.close()

        with open(path, 'r') as f:
            self.assertEqual(f.read().strip(), """
[<global>] Level.INFO: Hello world
[<global>] Level.INFO: Eternal voyage to the edge of the universe
""".strip())

        # Remove temp file
        os.remove(path)
Beispiel #10
0
    def test_file_logging(self):
        fd, path = tempfile.mkstemp(".log")
        os.close(fd) # Don't leak file descriptors

        filelogger = HammerVLSIFileLogger(path)

        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(filelogger.callback)
        log = HammerVLSILogging.context()
        log.info("Hello world")
        log.info("Eternal voyage to the edge of the universe")
        filelogger.close()

        with open(path, 'r') as f:
            self.assertEqual(f.read().strip(), """
[<global>] Level.INFO: Hello world
[<global>] Level.INFO: Eternal voyage to the edge of the universe
""".strip())

        # Remove temp file
        os.remove(path)
Beispiel #11
0
    def test_colours(self):
        """
        Test that we can log with and without colour.
        """
        msg = "This is a test message"  # type: str

        log = HammerVLSILogging.context("test")

        HammerVLSILogging.enable_buffering = True  # we need this for test
        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(HammerVLSILogging.callback_buffering)

        HammerVLSILogging.enable_colour = True
        log.info(msg)
        self.assertEqual(
            HammerVLSILogging.get_colour_escape(Level.INFO) + "[test] " + msg +
            HammerVLSILogging.COLOUR_CLEAR,
            HammerVLSILogging.get_buffer()[0])

        HammerVLSILogging.enable_colour = False
        log.info(msg)
        self.assertEqual("[test] " + msg, HammerVLSILogging.get_buffer()[0])
Beispiel #12
0
    def test_colours(self):
        """
        Test that we can log with and without colour.
        """
        msg = "This is a test message"  # type: str

        log = HammerVLSILogging.context("test")

        HammerVLSILogging.enable_buffering = True  # we need this for test
        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(HammerVLSILogging.callback_buffering)

        HammerVLSILogging.enable_colour = True
        log.info(msg)
        self.assertEqual(HammerVLSILogging.get_colour_escape(Level.INFO) + "[test] " + msg + HammerVLSILogging.COLOUR_CLEAR, HammerVLSILogging.get_buffer()[0])

        HammerVLSILogging.enable_colour = False
        log.info(msg)
        self.assertEqual("[test] " + msg, HammerVLSILogging.get_buffer()[0])
Beispiel #13
0
    def test_subcontext(self):
        HammerVLSILogging.enable_colour = False
        HammerVLSILogging.enable_tag = True

        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(HammerVLSILogging.callback_buffering)

        # Get top context
        log = HammerVLSILogging.context("top")

        # Create sub-contexts.
        logA = log.context("A")
        logB = log.context("B")

        msgA = "Hello world from A"
        msgB = "Hello world from B"

        logA.info(msgA)
        logB.error(msgB)

        self.assertEqual(HammerVLSILogging.get_buffer(),
                         ['[top] [A] ' + msgA, '[top] [B] ' + msgB])
Beispiel #14
0
    def test_subcontext(self):
        HammerVLSILogging.enable_colour = False
        HammerVLSILogging.enable_tag = True

        HammerVLSILogging.clear_callbacks()
        HammerVLSILogging.add_callback(HammerVLSILogging.callback_buffering)

        # Get top context
        log = HammerVLSILogging.context("top")

        # Create sub-contexts.
        logA = log.context("A")
        logB = log.context("B")

        msgA = "Hello world from A"
        msgB = "Hello world from B"

        logA.info(msgA)
        logB.error(msgB)

        self.assertEqual(HammerVLSILogging.get_buffer(),
            ['[top] [A] ' + msgA, '[top] [B] ' + msgB]
        )
Beispiel #15
0
    def test_read_extra_libs(self) -> None:
        """
        Test that HammerTool can read/process extra IP libraries in addition to those of the technology.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir(
            "dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        HammerToolTestHelpers.write_tech_json(tech_json_filename)
        tech = self.get_tech(
            hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("tech")

        class Tool(hammer_vlsi.DummyHammerTool):
            lib_output = []  # type: List[str]
            filter_output = []  # type: List[str]

            @property
            def steps(self) -> List[hammer_vlsi.HammerToolStep]:
                return self.make_steps_from_methods([self.step])

            def step(self) -> bool:
                def test_tool_format(lib, filt) -> List[str]:
                    return ["drink {0}".format(lib)]

                Tool.lib_output = tech.read_libs(
                    [hammer_tech.filters.milkyway_techfile_filter],
                    test_tool_format,
                    must_exist=False)

                Tool.filter_output = tech.read_libs(
                    [HammerToolTestHelpers.make_test_filter()],
                    test_tool_format,
                    must_exist=False)
                return True

        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        # Add some extra libraries to see if they are picked up
        database = hammer_config.HammerDatabase()
        lib1_path = "/foo/bar"
        lib1b_path = "/library/specific/prefix"
        lib2_path = "/baz/quux"
        database.update_project([{
            'vlsi.technology.extra_libraries': [{
                "library": {
                    "milkyway techfile": "test/xylophone"
                }
            }, {
                "library": {
                    "openaccess techfile": "test/orange"
                }
            }, {
                "prefix": {
                    "prefix": "lib1",
                    "path": lib1_path
                },
                "library": {
                    "milkyway techfile": "lib1/muffin"
                }
            }, {
                "prefix": {
                    "prefix": "lib1",
                    "path": lib1b_path
                },
                "library": {
                    "milkyway techfile": "lib1/granola"
                }
            }, {
                "prefix": {
                    "prefix": "lib2",
                    "path": lib2_path
                },
                "library": {
                    "openaccess techfile": "lib2/cake",
                    "milkyway techfile": "lib2/brownie",
                    "provides": [{
                        "lib_type": "stdcell"
                    }]
                }
            }]
        }])
        test.set_database(database)
        tech.set_database(database)
        test.run()

        # Not testing ordering in this assertion.
        self.assertEqual(
            set(Tool.lib_output), {
                "drink {0}/soy".format(tech_dir),
                "drink {0}/coconut".format(tech_dir),
                "drink {0}/xylophone".format(tech_dir),
                "drink {0}/muffin".format(lib1_path),
                "drink {0}/granola".format(lib1b_path),
                "drink {0}/brownie".format(lib2_path)
            })

        # We do care about ordering here.
        # Our filter should put the techfile first and sort the rest.
        print("Tool.filter_output = " + str(Tool.filter_output))
        tech_lef_result = [
            # tech lef
            "drink {0}/tea".format(tech_dir)
        ]
        base_lib_results = [
            "drink {0}/grapefruit".format(tech_dir),
            "drink {0}/juice".format(tech_dir),
            "drink {0}/orange".format(tech_dir)
        ]
        extra_libs_results = ["drink {0}/cake".format(lib2_path)]
        self.assertEqual(
            Tool.filter_output,
            tech_lef_result + sorted(base_lib_results + extra_libs_results))

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #16
0
    def test_timing_lib_ecsm_filter(self) -> None:
        """
        Test that the ECSM-first filter works as expected.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir(
            "dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        tech_json = {
            "name":
            "dummy28",
            "installs": [{
                "path": "test",
                "base var": ""  # means relative to tech dir
            }],
            "libraries": [{
                "ecsm liberty file": "test/eggs.ecsm",
                "ccs liberty file": "test/eggs.ccs",
                "nldm liberty file": "test/eggs.nldm"
            }, {
                "ccs liberty file": "test/custard.ccs",
                "nldm liberty file": "test/custard.nldm"
            }, {
                "nldm liberty file": "test/noodles.nldm"
            }, {
                "ecsm liberty file": "test/eggplant.ecsm"
            }, {
                "ccs liberty file": "test/cookies.ccs"
            }]
        }
        with open(tech_json_filename, "w") as f:
            f.write(json.dumps(tech_json, indent=4))
        tech = self.get_tech(
            hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("")

        class Tool(SingleStepTool):
            lib_outputs = []  # type: List[str]

            def step(self) -> bool:
                Tool.lib_outputs = tech.read_libs(
                    [hammer_tech.filters.timing_lib_with_ecsm_filter],
                    hammer_tech.HammerTechnologyUtils.to_plain_item,
                    must_exist=False)
                return True

        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        test.set_database(hammer_config.HammerDatabase())
        tech.set_database(hammer_config.HammerDatabase())
        test.run()

        # Check that the ecsm-based filter prioritized ecsm -> ccs -> nldm.
        self.assertEqual(
            set(Tool.lib_outputs), {
                "{0}/eggs.ecsm".format(tech_dir),
                "{0}/custard.ccs".format(tech_dir),
                "{0}/noodles.nldm".format(tech_dir),
                "{0}/eggplant.ecsm".format(tech_dir),
                "{0}/cookies.ccs".format(tech_dir)
            })

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #17
0
    def test_timing_lib_ecsm_filter(self) -> None:
        """
        Test that the ECSM-first filter works as expected.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir("dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        tech_json = {
            "name": "dummy28",
            "installs": [
                {
                    "path": "test",
                    "base var": ""  # means relative to tech dir
                }
            ],
            "libraries": [
                {
                    "ecsm liberty file": "test/eggs.ecsm",
                    "ccs liberty file": "test/eggs.ccs",
                    "nldm liberty file": "test/eggs.nldm"
                },
                {
                    "ccs liberty file": "test/custard.ccs",
                    "nldm liberty file": "test/custard.nldm"
                },
                {
                    "nldm liberty file": "test/noodles.nldm"
                },
                {
                    "ecsm liberty file": "test/eggplant.ecsm"
                },
                {
                    "ccs liberty file": "test/cookies.ccs"
                }
            ]
        }
        with open(tech_json_filename, "w") as f:
            f.write(json.dumps(tech_json, indent=4))
        tech = self.get_tech(hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("")

        class Tool(SingleStepTool):
            lib_outputs = []  # type: List[str]

            def step(self) -> bool:
                Tool.lib_outputs = tech.read_libs([hammer_tech.filters.timing_lib_with_ecsm_filter],
                                                  hammer_tech.HammerTechnologyUtils.to_plain_item,
                                                  must_exist=False)
                return True

        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        test.set_database(hammer_config.HammerDatabase())
        tech.set_database(hammer_config.HammerDatabase())
        test.run()

        # Check that the ecsm-based filter prioritized ecsm -> ccs -> nldm.
        self.assertEqual(set(Tool.lib_outputs), {
            "{0}/eggs.ecsm".format(tech_dir),
            "{0}/custard.ccs".format(tech_dir),
            "{0}/noodles.nldm".format(tech_dir),
            "{0}/eggplant.ecsm".format(tech_dir),
            "{0}/cookies.ccs".format(tech_dir)
        })

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #18
0
    def test_read_extra_libs(self) -> None:
        """
        Test that HammerTool can read/process extra IP libraries in addition to those of the technology.
        """
        import hammer_config

        tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir("dummy28")
        tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
        HammerToolTestHelpers.write_tech_json(tech_json_filename)
        tech = self.get_tech(hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
        tech.cache_dir = tech_dir
        tech.logger = HammerVLSILogging.context("tech")

        class Tool(hammer_vlsi.DummyHammerTool):
            lib_output = []  # type: List[str]
            filter_output = []  # type: List[str]

            @property
            def steps(self) -> List[hammer_vlsi.HammerToolStep]:
                return self.make_steps_from_methods([
                    self.step
                ])

            def step(self) -> bool:
                def test_tool_format(lib, filt) -> List[str]:
                    return ["drink {0}".format(lib)]

                Tool.lib_output = tech.read_libs([hammer_tech.filters.milkyway_techfile_filter], test_tool_format, must_exist=False)

                Tool.filter_output = tech.read_libs([HammerToolTestHelpers.make_test_filter()], test_tool_format,
                                                    must_exist=False)
                return True

        test = Tool()
        test.logger = HammerVLSILogging.context("")
        test.run_dir = tempfile.mkdtemp()
        test.technology = tech
        # Add some extra libraries to see if they are picked up
        database = hammer_config.HammerDatabase()
        lib1_path = "/foo/bar"
        lib1b_path = "/library/specific/prefix"
        lib2_path = "/baz/quux"
        database.update_project([{
            'vlsi.technology.extra_libraries': [
                {
                    "library": {"milkyway techfile": "test/xylophone"}
                },
                {
                    "library": {"openaccess techfile": "test/orange"}
                },
                {
                    "prefix": {
                        "prefix": "lib1",
                        "path": lib1_path
                    },
                    "library": {"milkyway techfile": "lib1/muffin"}
                },
                {
                    "prefix": {
                        "prefix": "lib1",
                        "path": lib1b_path
                    },
                    "library": {"milkyway techfile": "lib1/granola"}
                },
                {
                    "prefix": {
                        "prefix": "lib2",
                        "path": lib2_path
                    },
                    "library": {
                        "openaccess techfile": "lib2/cake",
                        "milkyway techfile": "lib2/brownie",
                        "provides": [
                            {"lib_type": "stdcell"}
                        ]
                    }
                }
            ]
        }])
        test.set_database(database)
        tech.set_database(database)
        test.run()

        # Not testing ordering in this assertion.
        self.assertEqual(set(Tool.lib_output),
                         {
                             "drink {0}/soy".format(tech_dir),
                             "drink {0}/coconut".format(tech_dir),
                             "drink {0}/xylophone".format(tech_dir),
                             "drink {0}/muffin".format(lib1_path),
                             "drink {0}/granola".format(lib1b_path),
                             "drink {0}/brownie".format(lib2_path)
                         })

        # We do care about ordering here.
        # Our filter should put the techfile first and sort the rest.
        print("Tool.filter_output = " + str(Tool.filter_output))
        tech_lef_result = [
            # tech lef
            "drink {0}/tea".format(tech_dir)
        ]
        base_lib_results = [
            "drink {0}/grapefruit".format(tech_dir),
            "drink {0}/juice".format(tech_dir),
            "drink {0}/orange".format(tech_dir)
        ]
        extra_libs_results = [
            "drink {0}/cake".format(lib2_path)
        ]
        self.assertEqual(Tool.filter_output, tech_lef_result + sorted(base_lib_results + extra_libs_results))

        # Cleanup
        shutil.rmtree(tech_dir_base)
        shutil.rmtree(test.run_dir)
Beispiel #19
0
    def __init__(self,
                 options: HammerDriverOptions,
                 extra_project_config: dict = {}) -> None:
        """
        Create a hammer-vlsi driver, which is a higher level convenience function
        for quickly using hammer-vlsi. It imports and uses the hammer-vlsi blocks.

        Set up logging, databases, context, etc.

        :param options: Driver options.
        :param extra_project_config: An extra flattened config for the project. Optional.
        """

        # Create global logging context.
        file_logger = HammerVLSIFileLogger(options.log_file)
        HammerVLSILogging.add_callback(file_logger.callback)
        self.log = HammerVLSILogging.context(
        )  # type: HammerVLSILoggingContext

        # Create a new hammer database.
        self.database = hammer_config.HammerDatabase(
        )  # type: hammer_config.HammerDatabase

        self.log.info("Loading hammer-vlsi libraries and reading settings")

        # Store the run dir.
        self.obj_dir = options.obj_dir  # type: str

        # Load in builtins.
        self.database.update_builtins([
            hammer_config.load_config_from_file(os.path.join(
                HammerVLSISettings.hammer_vlsi_path, "builtins.yml"),
                                                strict=True),
            HammerVLSISettings.get_config()
        ])

        # Read in core defaults.
        self.database.update_core(
            hammer_config.load_config_from_defaults(
                HammerVLSISettings.hammer_vlsi_path))

        # Read in the environment config for paths to CAD tools, etc.
        for config in options.environment_configs:
            if not os.path.exists(config):
                self.log.error("Environment config %s does not exist!" %
                               (config))
        self.database.update_environment(
            hammer_config.load_config_from_paths(options.environment_configs,
                                                 strict=True))

        # Read in the project config to find the syn, par, and tech.
        project_configs = hammer_config.load_config_from_paths(
            options.project_configs, strict=True)
        project_configs.append(extra_project_config)
        self.project_configs = []  # type: List[dict]
        self.update_project_configs(project_configs)

        # Get the technology and load technology settings.
        self.tech = None  # type: Optional[hammer_tech.HammerTechnology]
        self.load_technology()

        # Keep track of what the synthesis and par configs are since
        # update_tools() just takes a whole list.
        self.tool_configs = {}  # type: Dict[str, List[dict]]

        # Initialize tool fields.
        self.syn_tool = None  # type: Optional[HammerSynthesisTool]
        self.par_tool = None  # type: Optional[HammerPlaceAndRouteTool]

        # Initialize tool hooks. Used to specify resume/pause hooks after custom hooks have been registered.
        self.post_custom_syn_tool_hooks = [
        ]  # type: List[HammerToolHookAction]
        self.post_custom_par_tool_hooks = [
        ]  # type: List[HammerToolHookAction]
Beispiel #20
0
    def __init__(self, options: HammerDriverOptions, extra_project_config: dict = {}) -> None:
        """
        Create a hammer-vlsi driver, which is a higher level convenience function
        for quickly using hammer-vlsi. It imports and uses the hammer-vlsi blocks.

        Set up logging, databases, context, etc.

        :param options: Driver options.
        :param extra_project_config: An extra flattened config for the project. Optional.
        """

        # Create global logging context.
        file_logger = HammerVLSIFileLogger(options.log_file)
        HammerVLSILogging.add_callback(file_logger.callback)
        self.log = HammerVLSILogging.context()  # type: HammerVLSILoggingContext

        # Create a new hammer database.
        self.database = hammer_config.HammerDatabase()  # type: hammer_config.HammerDatabase

        self.log.info("Loading hammer-vlsi libraries and reading settings")

        # Store the run dir.
        self.obj_dir = options.obj_dir  # type: str

        # Load builtins and core into the database.
        HammerVLSISettings.load_builtins_and_core(self.database)

        # Read in the environment config for paths to CAD tools, etc.
        for config in options.environment_configs:
            if not os.path.exists(config):
                self.log.error("Environment config %s does not exist!" % (config))
        self.database.update_environment(hammer_config.load_config_from_paths(options.environment_configs, strict=True))

        # Read in the project config to find the syn, par, and tech.
        project_configs = hammer_config.load_config_from_paths(options.project_configs, strict=True)
        project_configs.append(extra_project_config)
        self.project_configs = []  # type: List[dict]
        self.update_project_configs(project_configs)

        # Get the technology and load technology settings.
        self.tech = None  # type: Optional[hammer_tech.HammerTechnology]
        self.load_technology()

        # Keep track of what the synthesis and par configs are since
        # update_tools() just takes a whole list.
        self.tool_configs = {}  # type: Dict[str, List[dict]]

        # Initialize tool fields.
        self.syn_tool = None  # type: Optional[HammerSynthesisTool]
        self.par_tool = None  # type: Optional[HammerPlaceAndRouteTool]
        self.drc_tool = None  # type: Optional[HammerDRCTool]
        self.lvs_tool = None  # type: Optional[HammerLVSTool]
        self.sram_generator_tool = None  # type: Optional[HammerSRAMGeneratorTool]

        # Initialize tool hooks. Used to specify resume/pause hooks after custom hooks have been registered.
        self.post_custom_syn_tool_hooks = []  # type: List[HammerToolHookAction]
        self.post_custom_par_tool_hooks = []  # type: List[HammerToolHookAction]
        self.post_custom_drc_tool_hooks = []  # type: List[HammerToolHookAction]
        self.post_custom_lvs_tool_hooks = []  # type: List[HammerToolHookAction]
        self.post_custom_sram_generator_tool_hooks = []  # type: List[HammerToolHookAction]
        self.post_custom_pcb_tool_hooks = []  # type: List[HammerToolHookAction]
Beispiel #21
0
    def test_bumps(self) -> None:
         """
         Test that HammerTool bump support works.
         """
         import hammer_config

         tech_dir, tech_dir_base = HammerToolTestHelpers.create_tech_dir("dummy28")
         tech_json_filename = os.path.join(tech_dir, "dummy28.tech.json")
         HammerToolTestHelpers.write_tech_json(tech_json_filename)
         tech = self.get_tech(hammer_tech.HammerTechnology.load_from_dir("dummy28", tech_dir))
         tech.cache_dir = tech_dir
         tech.logger = HammerVLSILogging.context("")

         test = DummyTool()
         test.logger = HammerVLSILogging.context("")
         test.run_dir = tempfile.mkdtemp()
         test.technology = tech
         database = hammer_config.HammerDatabase()
         # Check bad mode string doesn't look at null dict
         settings = """
{
     "vlsi.inputs.bumps_mode": "auto"
}
"""
         database.update_project([hammer_config.load_config_from_string(settings, is_yaml=False)])
         test.set_database(database)

         with HammerLoggingCaptureContext() as c:
             my_bumps = test.get_bumps()
         self.assertTrue(c.log_contains("Invalid bumps_mode"))
         assert my_bumps is None, "Invalid bumps_mode should assume empty bumps"

         settings = """
 {
     "vlsi.inputs.bumps_mode": "manual",
     "vlsi.inputs.bumps": {
                     "x": 14,
                     "y": 14,
                     "pitch": 200,
                     "cell": "MY_REDACTED_BUMP_CELL",
                     "assignments": [
                         {"name": "reset", "x": 5, "y": 3},
                         {"no_connect": true, "x": 5, "y": 4},
                         {"name": "VDD", "x": 2, "y": 1},
                         {"name": "VSS", "x": 1, "y": 1},
                         {"name": "VSS", "no_connect": true, "x": 2, "y": 2},
                         {"x": 3, "y": 3},
                         {"name": "VSS", "x": 14, "y": 14}
                     ]
                 }
 }
 """
         database.update_project([hammer_config.load_config_from_string(settings, is_yaml=False)])
         test.set_database(database)

         with HammerLoggingCaptureContext() as c:
             my_bumps = test.get_bumps()
         self.assertTrue(c.log_contains("Invalid bump assignment"))
         assert my_bumps is not None
         # Only one of the assignments is invalid so the above 7 becomes 6
         self.assertEqual(len(my_bumps.assignments), 6)

         # Cleanup
         shutil.rmtree(tech_dir_base)
         shutil.rmtree(test.run_dir)