From 3143c428b73d8a5b80ac7218d17a04f5583208e5 Mon Sep 17 00:00:00 2001 From: Rajsekhar Setaluri Date: Tue, 26 May 2020 11:23:50 -0700 Subject: [PATCH 1/5] Remove unused file --- tests/doit | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 tests/doit diff --git a/tests/doit b/tests/doit deleted file mode 100644 index 62625aee5..000000000 --- a/tests/doit +++ /dev/null @@ -1,3 +0,0 @@ -unset MANTLE -unset MANTLE_TARGET -pytest From 06e9b5ad32f31f07b50f004f4a2ed21f80477340 Mon Sep 17 00:00:00 2001 From: Rajsekhar Setaluri Date: Tue, 26 May 2020 12:09:25 -0700 Subject: [PATCH 2/5] Add BlackBox pass and tests --- magma/passes/black_box.py | 17 ++++++ .../gold/test_passes_black_box_basic.json | 29 ++++++++++ .../gold/test_passes_black_box_noop.json | 32 +++++++++++ tests/test_passes/test_black_box.py | 54 +++++++++++++++++++ .../test_passes_black_box_noop.json | 32 +++++++++++ 5 files changed, 164 insertions(+) create mode 100644 magma/passes/black_box.py create mode 100644 tests/test_passes/gold/test_passes_black_box_basic.json create mode 100644 tests/test_passes/gold/test_passes_black_box_noop.json create mode 100644 tests/test_passes/test_black_box.py create mode 100644 tests/test_passes/test_passes_black_box_noop.json diff --git a/magma/passes/black_box.py b/magma/passes/black_box.py new file mode 100644 index 000000000..e87571163 --- /dev/null +++ b/magma/passes/black_box.py @@ -0,0 +1,17 @@ +from typing import Iterable + +from magma.circuit import CircuitKind +from magma.passes.passes import CircuitPass + + +class BlackBoxPass(CircuitPass): + def __init__(self, main: CircuitKind, black_boxes: Iterable[CircuitKind]): + super().__init__(main) + self._black_boxes = set(black_boxes) + + def __call__(self, cls): + try: + self._black_boxes.remove(cls) + except KeyError: + return # @cls not in black_boxes, don't need to do anything + cls._is_definition = False diff --git a/tests/test_passes/gold/test_passes_black_box_basic.json b/tests/test_passes/gold/test_passes_black_box_basic.json new file mode 100644 index 000000000..e7fc6f869 --- /dev/null +++ b/tests/test_passes/gold/test_passes_black_box_basic.json @@ -0,0 +1,29 @@ +{"top":"global._Top", +"namespaces":{ + "global":{ + "modules":{ + "_Foo":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]] + }, + "_Top":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "_Foo_inst0":{ + "modref":"global._Foo" + } + }, + "connections":[ + ["self.I","_Foo_inst0.I"], + ["self.O","_Foo_inst0.O"] + ] + } + } + } +} +} diff --git a/tests/test_passes/gold/test_passes_black_box_noop.json b/tests/test_passes/gold/test_passes_black_box_noop.json new file mode 100644 index 000000000..322a201d1 --- /dev/null +++ b/tests/test_passes/gold/test_passes_black_box_noop.json @@ -0,0 +1,32 @@ +{"top":"global._Top", +"namespaces":{ + "global":{ + "modules":{ + "_Foo":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "connections":[ + ["self.O","self.I"] + ] + }, + "_Top":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "_Foo_inst0":{ + "modref":"global._Foo" + } + }, + "connections":[ + ["self.I","_Foo_inst0.I"], + ["self.O","_Foo_inst0.O"] + ] + } + } + } +} +} diff --git a/tests/test_passes/test_black_box.py b/tests/test_passes/test_black_box.py new file mode 100644 index 000000000..6d16cdd3e --- /dev/null +++ b/tests/test_passes/test_black_box.py @@ -0,0 +1,54 @@ +import pytest + +import magma as m +from magma.passes.black_box import BlackBoxPass +from magma.testing import check_files_equal + + +# NOTE(rsetaluri): We need this fixture per function, since each function may +# run a pass to modify the circuits. However, the setup is identical for each so +# we reuse this fixture across all the test. +@pytest.fixture(scope="function") +def ckts(): + + class _Foo(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= io.I + + + class _Bar(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= io.I + + + class _Top(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= _Foo()(io.I) + + return (_Foo, _Bar, _Top) + + +def test_noop(ckts): + _Foo, _Bar, _Top = ckts + m.compile("build/test_passes_black_box_noop", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_black_box_noop.json", + f"gold/test_passes_black_box_noop.json") + + +def test_basic(ckts): + _Foo, _Bar, _Top = ckts + BlackBoxPass(_Top, (_Foo,)).run() + m.compile("build/test_passes_black_box_basic", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_black_box_basic.json", + f"gold/test_passes_black_box_basic.json") + + +def test_unused(ckts): + _Foo, _Bar, _Top = ckts + BlackBoxPass(_Top, (_Bar,)).run() + m.compile("build/test_passes_black_box_unused", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_black_box_unused.json", + f"gold/test_passes_black_box_noop.json") diff --git a/tests/test_passes/test_passes_black_box_noop.json b/tests/test_passes/test_passes_black_box_noop.json new file mode 100644 index 000000000..322a201d1 --- /dev/null +++ b/tests/test_passes/test_passes_black_box_noop.json @@ -0,0 +1,32 @@ +{"top":"global._Top", +"namespaces":{ + "global":{ + "modules":{ + "_Foo":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "connections":[ + ["self.O","self.I"] + ] + }, + "_Top":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "_Foo_inst0":{ + "modref":"global._Foo" + } + }, + "connections":[ + ["self.I","_Foo_inst0.I"], + ["self.O","_Foo_inst0.O"] + ] + } + } + } +} +} From 754f3a901fca61437ab0f9b9d27e5933221757c2 Mon Sep 17 00:00:00 2001 From: Rajsekhar Setaluri Date: Tue, 26 May 2020 12:15:26 -0700 Subject: [PATCH 3/5] Add compiler option for black boxing --- magma/compile.py | 28 +++++++++++++++++++++------- tests/test_passes/test_black_box.py | 9 +++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/magma/compile.py b/magma/compile.py index 24be23595..05def969f 100644 --- a/magma/compile.py +++ b/magma/compile.py @@ -1,14 +1,17 @@ from inspect import getouterframes, currentframe from pathlib import PurePath -from .backend import verilog, blif, firrtl, dot, coreir_compiler -from .compiler import Compiler -from .config import get_compile_dir -from .uniquification import uniquification_pass, UniquificationMode -from .passes.clock import WireClockPass -from .passes.drive_undriven import DriveUndrivenPass -from .passes.terminate_unused import TerminateUnusedPass + +from magma.backend import verilog, blif, firrtl, dot, coreir_compiler from magma.bind import BindPass +from magma.compiler import Compiler +from magma.config import get_compile_dir from magma.inline_verilog import ProcessInlineVerilogPass +from magma.passes.black_box import BlackBoxPass +from magma.passes.clock import WireClockPass +from magma.passes.drive_undriven import DriveUndrivenPass +from magma.passes.terminate_unused import TerminateUnusedPass +from magma.uniquification import uniquification_pass, UniquificationMode + __all__ = ["compile"] @@ -38,6 +41,14 @@ def _get_basename(basename): return basename +def _run_if_in(dct, key, fn): + try: + value = dct[key] + except KeyError: + return + fn(value) + + def compile(basename, main, output="coreir-verilog", **kwargs): if hasattr(main, "circuit_definition"): main = main.circuit_definition @@ -54,6 +65,9 @@ def compile(basename, main, output="coreir-verilog", **kwargs): # Bind after uniquification so the bind logic works on unique modules BindPass(main, compile).run() + # Black box circuits if requested. + _run_if_in(opts, "black_boxes", lambda bb: BlackBoxPass(main, bb).run()) + if opts.get("drive_undriven", False): DriveUndrivenPass(main).run() if opts.get("terminate_unused", False): diff --git a/tests/test_passes/test_black_box.py b/tests/test_passes/test_black_box.py index 6d16cdd3e..39820f10a 100644 --- a/tests/test_passes/test_black_box.py +++ b/tests/test_passes/test_black_box.py @@ -52,3 +52,12 @@ def test_unused(ckts): assert check_files_equal(__file__, f"build/test_passes_black_box_unused.json", f"gold/test_passes_black_box_noop.json") + + +def test_compiler_args(ckts): + _Foo, _Bar, _Top = ckts + m.compile("build/test_passes_black_box_compiler_args", _Top, + output="coreir", black_boxes=(_Foo,)) + assert check_files_equal(__file__, + f"build/test_passes_black_box_compiler_args.json", + f"gold/test_passes_black_box_basic.json") From 4199637700f4f8fce9c61989ff318a9af1c217fd Mon Sep 17 00:00:00 2001 From: Rajsekhar Setaluri Date: Tue, 26 May 2020 13:09:15 -0700 Subject: [PATCH 4/5] Add Stub pass and tests --- magma/passes/stub.py | 30 +++++++++++ .../gold/test_passes_stub_basic.json | 37 +++++++++++++ .../gold/test_passes_stub_noop.json | 32 +++++++++++ tests/test_passes/test_stub.py | 54 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 magma/passes/stub.py create mode 100644 tests/test_passes/gold/test_passes_stub_basic.json create mode 100644 tests/test_passes/gold/test_passes_stub_noop.json create mode 100644 tests/test_passes/test_stub.py diff --git a/magma/passes/stub.py b/magma/passes/stub.py new file mode 100644 index 000000000..ddc77ed00 --- /dev/null +++ b/magma/passes/stub.py @@ -0,0 +1,30 @@ +from typing import Iterable + +from magma.circuit import CircuitKind +from magma.passes.passes import CircuitPass + + +def _drive_if_undriven_input(port): + if port.is_mixed(): + for p in port: + _drive_if_undriven_input(p) + return + # NOTE(rsetaluri): This may override previously wired inputs, resulting in a + # warning. In this case, this warning is benign. + if port.is_input(): + port.undriven() + + +class StubPass(CircuitPass): + def __init__(self, main: CircuitKind, stubs: Iterable[CircuitKind]): + super().__init__(main) + self._stubs = set(stubs) + + def __call__(self, cls): + try: + self._stubs.remove(cls) + except KeyError: + return # @cls not in stubs, don't need to do anything + with cls.open(): + for port in cls.interface.ports.values(): + _drive_if_undriven_input(port) diff --git a/tests/test_passes/gold/test_passes_stub_basic.json b/tests/test_passes/gold/test_passes_stub_basic.json new file mode 100644 index 000000000..9a3003978 --- /dev/null +++ b/tests/test_passes/gold/test_passes_stub_basic.json @@ -0,0 +1,37 @@ +{"top":"global._Top", +"namespaces":{ + "global":{ + "modules":{ + "_Foo":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "corebit_undriven_inst0":{ + "modref":"corebit.undriven" + } + }, + "connections":[ + ["self.O","corebit_undriven_inst0.out"] + ] + }, + "_Top":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "_Foo_inst0":{ + "modref":"global._Foo" + } + }, + "connections":[ + ["self.I","_Foo_inst0.I"], + ["self.O","_Foo_inst0.O"] + ] + } + } + } +} +} diff --git a/tests/test_passes/gold/test_passes_stub_noop.json b/tests/test_passes/gold/test_passes_stub_noop.json new file mode 100644 index 000000000..322a201d1 --- /dev/null +++ b/tests/test_passes/gold/test_passes_stub_noop.json @@ -0,0 +1,32 @@ +{"top":"global._Top", +"namespaces":{ + "global":{ + "modules":{ + "_Foo":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "connections":[ + ["self.O","self.I"] + ] + }, + "_Top":{ + "type":["Record",[ + ["I","BitIn"], + ["O","Bit"] + ]], + "instances":{ + "_Foo_inst0":{ + "modref":"global._Foo" + } + }, + "connections":[ + ["self.I","_Foo_inst0.I"], + ["self.O","_Foo_inst0.O"] + ] + } + } + } +} +} diff --git a/tests/test_passes/test_stub.py b/tests/test_passes/test_stub.py new file mode 100644 index 000000000..aa50a361e --- /dev/null +++ b/tests/test_passes/test_stub.py @@ -0,0 +1,54 @@ +import pytest + +import magma as m +from magma.passes.stub import StubPass +from magma.testing import check_files_equal + + +# NOTE(rsetaluri): We need this fixture per function, since each function may +# run a pass to modify the circuits. However, the setup is identical for each so +# we reuse this fixture across all the test. +@pytest.fixture(scope="function") +def ckts(): + + class _Foo(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= io.I + + + class _Bar(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= io.I + + + class _Top(m.Circuit): + io = m.IO(I=m.In(m.Bit), O=m.Out(m.Bit)) + io.O @= _Foo()(io.I) + + return (_Foo, _Bar, _Top) + + +def test_noop(ckts): + _Foo, _Bar, _Top = ckts + m.compile("build/test_passes_stub_noop", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_stub_noop.json", + f"gold/test_passes_stub_noop.json") + + +def test_basic(ckts): + _Foo, _Bar, _Top = ckts + StubPass(_Top, (_Foo,)).run() + m.compile("build/test_passes_stub_basic", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_stub_basic.json", + f"gold/test_passes_stub_basic.json") + + +def test_unused(ckts): + _Foo, _Bar, _Top = ckts + StubPass(_Top, (_Bar,)).run() + m.compile("build/test_passes_stub_unused", _Top, output="coreir") + assert check_files_equal(__file__, + f"build/test_passes_stub_unused.json", + f"gold/test_passes_stub_noop.json") From 674511cbbd25efa8972228e867407400754b7b3c Mon Sep 17 00:00:00 2001 From: Rajsekhar Setaluri Date: Tue, 26 May 2020 13:11:36 -0700 Subject: [PATCH 5/5] Add compiler option for stubbing --- magma/compile.py | 4 ++++ tests/test_passes/test_stub.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/magma/compile.py b/magma/compile.py index 05def969f..d3ba54601 100644 --- a/magma/compile.py +++ b/magma/compile.py @@ -7,6 +7,7 @@ from magma.config import get_compile_dir from magma.inline_verilog import ProcessInlineVerilogPass from magma.passes.black_box import BlackBoxPass +from magma.passes.stub import StubPass from magma.passes.clock import WireClockPass from magma.passes.drive_undriven import DriveUndrivenPass from magma.passes.terminate_unused import TerminateUnusedPass @@ -68,6 +69,9 @@ def compile(basename, main, output="coreir-verilog", **kwargs): # Black box circuits if requested. _run_if_in(opts, "black_boxes", lambda bb: BlackBoxPass(main, bb).run()) + # Black box circuits if requested. + _run_if_in(opts, "stubs", lambda stub: StubPass(main, stub).run()) + if opts.get("drive_undriven", False): DriveUndrivenPass(main).run() if opts.get("terminate_unused", False): diff --git a/tests/test_passes/test_stub.py b/tests/test_passes/test_stub.py index aa50a361e..c4f3c2515 100644 --- a/tests/test_passes/test_stub.py +++ b/tests/test_passes/test_stub.py @@ -52,3 +52,12 @@ def test_unused(ckts): assert check_files_equal(__file__, f"build/test_passes_stub_unused.json", f"gold/test_passes_stub_noop.json") + + +def test_compiler_args(ckts): + _Foo, _Bar, _Top = ckts + m.compile("build/test_passes_stub_compiler_args", _Top, + output="coreir", stubs=(_Foo,)) + assert check_files_equal(__file__, + f"build/test_passes_stub_compiler_args.json", + f"gold/test_passes_stub_basic.json")