From db27b06f9a67abd1bb9e6ba01aa0fd22b3623419 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Fri, 7 Jul 2023 19:29:00 -0700 Subject: [PATCH 1/8] Update test_csr.py --- examples/riscv_mini/tests/test_csr.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/riscv_mini/tests/test_csr.py b/examples/riscv_mini/tests/test_csr.py index 9bf698c28..940e668b4 100644 --- a/examples/riscv_mini/tests/test_csr.py +++ b/examples/riscv_mini/tests/test_csr.py @@ -110,8 +110,12 @@ class CSR_DUT(m.Circuit): csr = CSRGen(x_len)() ctrl = Control.Control(x_len)() +<<<<<<< HEAD <<<<<<< HEAD counter = Counter(n, has_cout=True, reset_type=m.Reset)() +======= + counter = Counter(n, has_cout=True)() +>>>>>>> 85818f26 (Update test_csr.py) ======= counter = Counter(n, has_cout=True)() >>>>>>> 85818f26 (Update test_csr.py) From 39ff8b253ae5bc7175001b606332bb3b2dbd6dfb Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Mon, 10 Jul 2023 19:32:31 -0700 Subject: [PATCH 2/8] Update tests --- tests/test_verilog/test_inline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_verilog/test_inline.py b/tests/test_verilog/test_inline.py index dd624c02d..80b84ca55 100644 --- a/tests/test_verilog/test_inline.py +++ b/tests/test_verilog/test_inline.py @@ -1,5 +1,3 @@ -import pytest - import magma as m import magma.testing from magma.inline_verilog import InlineVerilogError From 9c3a5fb00e04082239126361cedac01f67999ce3 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Mon, 10 Jul 2023 19:40:58 -0700 Subject: [PATCH 3/8] Fix collection issue --- tests/test_verilog/test_inline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_verilog/test_inline.py b/tests/test_verilog/test_inline.py index 80b84ca55..dd624c02d 100644 --- a/tests/test_verilog/test_inline.py +++ b/tests/test_verilog/test_inline.py @@ -1,3 +1,5 @@ +import pytest + import magma as m import magma.testing from magma.inline_verilog import InlineVerilogError From 2cd5a7e10787644e7aec6e1ffb84e19e3fa53516 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Tue, 8 Aug 2023 16:03:16 -0700 Subject: [PATCH 4/8] [Mantle] Init ice40 primitives Provides an example of latest magma style for @phanrahan who will start extending this platform for the new mantle library. --- magma/backend/mlir/hardware_module.py | 15 +++-- magma/circuit.py | 10 +++ magma/mantle/lattice/__init__.py | 0 magma/mantle/lattice/ice40/__init__.py | 0 magma/mantle/lattice/ice40/adder.py | 41 ++++++++++++ magma/mantle/lattice/ice40/lut.py | 39 ++++++++++++ magma/mantle/lattice/ice40/plb.py | 60 ++++++++++++++++++ .../test_ice40/gold/test_ice40_full_adder.v | 62 +++++++++++++++++++ .../test_ice40/gold/test_ice40_half_adder.v | 57 +++++++++++++++++ .../test_ice40/gold/test_sb_carry.v | 19 ++++++ .../test_ice40/gold/test_sb_dff.v | 16 +++++ .../test_ice40/gold/test_sb_lut4.v | 22 +++++++ .../test_lattice/test_ice40/test_adder.py | 38 ++++++++++++ .../test_lattice/test_ice40/test_lut.py | 25 ++++++++ .../test_lattice/test_ice40/test_plb.py | 56 +++++++++++++++++ 15 files changed, 454 insertions(+), 6 deletions(-) create mode 100644 magma/mantle/lattice/__init__.py create mode 100644 magma/mantle/lattice/ice40/__init__.py create mode 100644 magma/mantle/lattice/ice40/adder.py create mode 100644 magma/mantle/lattice/ice40/lut.py create mode 100644 magma/mantle/lattice/ice40/plb.py create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_full_adder.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_half_adder.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_sb_carry.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_sb_dff.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_sb_lut4.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/test_adder.py create mode 100644 tests/test_mantle/test_lattice/test_ice40/test_lut.py create mode 100644 tests/test_mantle/test_lattice/test_ice40/test_plb.py diff --git a/magma/backend/mlir/hardware_module.py b/magma/backend/mlir/hardware_module.py index 6491e646f..a50e7bfaa 100644 --- a/magma/backend/mlir/hardware_module.py +++ b/magma/backend/mlir/hardware_module.py @@ -7,6 +7,8 @@ from typing import Any, List, Mapping, Optional, Tuple, Union import weakref +import hwtypes as ht + from magma.array import Array, ArrayMeta from magma.backend.mlir.build_magma_graph import ( BuildMagmaGrahOpts, build_magma_graph @@ -151,17 +153,19 @@ def magma_type_to_mlir_type(type: Kind) -> MlirType: @wrap_with_not_implemented_error @functools.lru_cache() def python_type_to_mlir_type(type_: type) -> MlirType: - # NOTE(rsetaluri): We only support integer attribtue types right now. All - # integer parameter types are assumed to be int32's. + # NOTE(rsetaluri): All integer parameter types are assumed to be int32's. if type_ is int: return builtin.IntegerType(32) + if issubclass(type_, ht.BitVector): + return builtin.IntegerType(len(type_)) @wrap_with_not_implemented_error def python_value_to_mlir_attribtue(value: Any) -> MlirAttribute: - # NOTE(rsetaluri): We only support integer attribute types right now. if isinstance(value, int): return builtin.IntegerAttr(value) + if isinstance(value, ht.BitVector): + return builtin.IntegerAttr(int(value)) def get_module_interface( @@ -1343,9 +1347,8 @@ def new_values(fn, ports): def _add_module_parameters(self, hw_module: hw.ModuleOpBase): defn_or_decl = self._magma_defn_or_decl - try: - param_types = defn_or_decl.coreir_config_param_types - except AttributeError: + param_types = defn_or_decl.get_param_types() + if param_types is None: return for name, type in param_types.items(): type = python_type_to_mlir_type(type) diff --git a/magma/circuit.py b/magma/circuit.py index f7a265f70..a94b85210 100644 --- a/magma/circuit.py +++ b/magma/circuit.py @@ -428,6 +428,16 @@ def inline_verilog(cls, inline_str, **kwargs): with definition_context_manager(cls._context_): m_inline_verilog(inline_str, **kwargs) + def get_param_types(self): + try: + return self.param_types + except AttributeError: + try: + # try old API + return self.coreir_config_param_types + except AttributeError: + return None + class AnonymousCircuitType(object, metaclass=CircuitKind): """Abstract base class for circuits""" diff --git a/magma/mantle/lattice/__init__.py b/magma/mantle/lattice/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/magma/mantle/lattice/ice40/__init__.py b/magma/mantle/lattice/ice40/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/magma/mantle/lattice/ice40/adder.py b/magma/mantle/lattice/ice40/adder.py new file mode 100644 index 000000000..eb0e4aa83 --- /dev/null +++ b/magma/mantle/lattice/ice40/adder.py @@ -0,0 +1,41 @@ +from magma.bit import Bit +from magma.circuit import Circuit +from magma.interface import IO +from magma.mantle.lattice.ice40.plb import SB_CARRY, A0, A1, A2 +from magma.mantle.lattice.ice40.lut import LUT2, LUT3 +from magma.t import In, Out + + +def half_adder(I0, I1): + """Returns (sum, carry)""" + return LUT2(A0 ^ A1)()(I0, I1), SB_CARRY()(I0, I1, 0) + + +class HalfAdder(Circuit): + io = IO( + I0=In(Bit), + I1=In(Bit), + O=Out(Bit), + COUT=Out(Bit), + ) + sum, carry = half_adder(io.I0, io.I1) + io.O @= sum + io.COUT @= carry + + +def full_adder(I0, I1, CIN): + """Returns (sum, carry)""" + return LUT3(A0 ^ A1 ^ A2)()(I0, I1, CIN), SB_CARRY()(I0, I1, CIN) + + +class FullAdder(Circuit): + io = IO( + I0=In(Bit), + I1=In(Bit), + CIN=In(Bit), + O=Out(Bit), + COUT=Out(Bit), + ) + sum, carry = full_adder(io.I0, io.I1, io.CIN) + io.O @= sum + io.COUT @= carry diff --git a/magma/mantle/lattice/ice40/lut.py b/magma/mantle/lattice/ice40/lut.py new file mode 100644 index 000000000..8fc240449 --- /dev/null +++ b/magma/mantle/lattice/ice40/lut.py @@ -0,0 +1,39 @@ +""" +Convenience wrappers around SB_LUT4 +""" +from magma.bit import Bit +from magma.interface import IO +from magma.generator import Generator2 +from magma.mantle.lattice.ice40.plb import SB_LUT4 +from magma.t import In, Out + + +class LUT2(Generator2): + def __init__(self, contents): + self.io = IO( + I0=In(Bit), + I1=In(Bit), + O=Out(Bit), + ) + self.io.O @= SB_LUT4(LUT_INIT=contents)( + self.io.I0, + self.io.I1, + 0, + 0 + ) + + +class LUT3(Generator2): + def __init__(self, contents): + self.io = IO( + I0=In(Bit), + I1=In(Bit), + I2=In(Bit), + O=Out(Bit), + ) + self.io.O @= SB_LUT4(LUT_INIT=contents)( + self.io.I0, + self.io.I1, + self.io.I2, + 0 + ) diff --git a/magma/mantle/lattice/ice40/plb.py b/magma/mantle/lattice/ice40/plb.py new file mode 100644 index 000000000..00c7000da --- /dev/null +++ b/magma/mantle/lattice/ice40/plb.py @@ -0,0 +1,60 @@ +import hwtypes as ht + +from magma.bit import Bit +from magma.circuit import Circuit +from magma.clock import Clock +from magma.interface import IO +from magma.t import In, Out + + +# Useful variables for programming LUTs +LUTS_PER_LOGICBLOCK = 2 +LOG_BITS_PER_LUT = 4 +BITS_PER_LUT = 1 << LOG_BITS_PER_LUT + +ZERO = 0 +ONE = (1 << BITS_PER_LUT) - 1 + +A0 = ht.BitVector[16](0xAAAA) +A1 = ht.BitVector[16](0xCCCC) +A2 = ht.BitVector[16](0xF0F0) +A3 = ht.BitVector[16](0xFF00) + +I0 = A0 +I1 = A1 +I2 = A2 +I3 = A3 + +ALL = A0 & A1 & A2 & A3 +ANY = A0 | A1 | A2 | A3 +PARITY = A0 ^ A1 ^ A2 ^ A3 + + +class SB_LUT4(Circuit): + io = IO( + I0=In(Bit), + I1=In(Bit), + I2=In(Bit), + I3=In(Bit), + O=Out(Bit) + ) + param_types = {"LUT_INIT": ht.BitVector[16]} + + +class SB_CARRY(Circuit): + """Implements (I0&I1)|(I1&I2)|(I2&I0)""" + io = IO( + I0=In(Bit), # must be the same as SB_LUT4 I1 to pack + I1=In(Bit), # must be the same as SB_LUT4 I2 to pack + CI=In(Bit), # must be from previous SB_LUT4 to pack + CO=Out(Bit) + ) + + +class SB_DFF(Circuit): + """D Flip-Flop""" + io = IO( + C=In(Clock), + D=In(Bit), + Q=Out(Bit) + ) diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_full_adder.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_full_adder.v new file mode 100644 index 000000000..881585142 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_full_adder.v @@ -0,0 +1,62 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_LUT4 + +// external module SB_CARRY + +module LUT3( + input I0, + I1, + I2, + output O +); + + SB_LUT4 #( + .LUT_INIT(38550) + ) SB_LUT4_inst0 ( + .I0 (I0), + .I1 (I1), + .I2 (I2), + .I3 (1'h0), + .O (O) + ); +endmodule + +module FullAdder( + input I0, + I1, + CIN, + output O, + COUT +); + + LUT3 LUT3_inst0 ( + .I0 (I0), + .I1 (I1), + .I2 (CIN), + .O (O) + ); + SB_CARRY SB_CARRY_inst0 ( + .I0 (I0), + .I1 (I1), + .CI (CIN), + .CO (COUT) + ); +endmodule + +module Top( + input I0, + I1, + CIN, + output O, + COUT +); + + FullAdder FullAdder_inst0 ( + .I0 (I0), + .I1 (I1), + .CIN (CIN), + .O (O), + .COUT (COUT) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_half_adder.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_half_adder.v new file mode 100644 index 000000000..fcffcbbbf --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_ice40_half_adder.v @@ -0,0 +1,57 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_LUT4 + +// external module SB_CARRY + +module LUT2( + input I0, + I1, + output O +); + + SB_LUT4 #( + .LUT_INIT(26214) + ) SB_LUT4_inst0 ( + .I0 (I0), + .I1 (I1), + .I2 (1'h0), + .I3 (1'h0), + .O (O) + ); +endmodule + +module HalfAdder( + input I0, + I1, + output O, + COUT +); + + LUT2 LUT2_inst0 ( + .I0 (I0), + .I1 (I1), + .O (O) + ); + SB_CARRY SB_CARRY_inst0 ( + .I0 (I0), + .I1 (I1), + .CI (1'h0), + .CO (COUT) + ); +endmodule + +module Top( + input I0, + I1, + output O, + COUT +); + + HalfAdder HalfAdder_inst0 ( + .I0 (I0), + .I1 (I1), + .O (O), + .COUT (COUT) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_carry.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_carry.v new file mode 100644 index 000000000..c98194604 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_carry.v @@ -0,0 +1,19 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_CARRY + +module Top( + input I0, + I1, + I2, + CI, + output CO +); + + SB_CARRY SB_CARRY_inst0 ( + .I0 (I0), + .I1 (I1), + .CI (CI), + .CO (CO) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_dff.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_dff.v new file mode 100644 index 000000000..c7953f083 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_dff.v @@ -0,0 +1,16 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_DFF + +module Top( + input C, + D, + output Q +); + + SB_DFF SB_DFF_inst0 ( + .C (C), + .D (D), + .Q (Q) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_lut4.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_lut4.v new file mode 100644 index 000000000..374f4d914 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_lut4.v @@ -0,0 +1,22 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_LUT4 + +module Top( + input I0, + I1, + I2, + I3, + output O +); + + SB_LUT4 #( + .LUT_INIT(48879) + ) SB_LUT4_inst0 ( + .I0 (I0), + .I1 (I1), + .I2 (I2), + .I3 (I3), + .O (O) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/test_adder.py b/tests/test_mantle/test_lattice/test_ice40/test_adder.py new file mode 100644 index 000000000..66c1072a5 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/test_adder.py @@ -0,0 +1,38 @@ +import operator + +import magma as m +from magma.mantle.lattice.ice40.adder import HalfAdder, FullAdder +from magma.testing.utils import check_gold + + +def test_ice40_half_adder(): + class Top(m.Circuit): + io = m.IO( + I0=m.In(m.Bit), + I1=m.In(m.Bit), + O=m.Out(m.Bit), + COUT=m.Out(m.Bit), + ) + O, COUT = HalfAdder()(io.I0, io.I1) + io.O @= O + io.COUT @= COUT + + m.compile("build/test_ice40_half_adder", Top, output="mlir-verilog") + assert check_gold(__file__, "test_ice40_half_adder.v") + + +def test_ice40_fulladder(): + class Top(m.Circuit): + io = m.IO( + I0=m.In(m.Bit), + I1=m.In(m.Bit), + CIN=m.In(m.Bit), + O=m.Out(m.Bit), + COUT=m.Out(m.Bit), + ) + O, COUT = FullAdder()(io.I0, io.I1, io.CIN) + io.O @= O + io.COUT @= COUT + + m.compile("build/test_ice40_full_adder", Top, output="mlir-verilog") + assert check_gold(__file__, "test_ice40_full_adder.v") diff --git a/tests/test_mantle/test_lattice/test_ice40/test_lut.py b/tests/test_mantle/test_lattice/test_ice40/test_lut.py new file mode 100644 index 000000000..a5e2538b1 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/test_lut.py @@ -0,0 +1,25 @@ +import operator + +import magma as m +from magma.mantle.lattice.ice40.lut import LUT2, LUT3 +from magma.mantle.lattice.ice40.plb import A0, A1, A2, SB_LUT4 + + +def test_ice40_lut2(): + lut = LUT2(A0 ^ A1) + assert all(map(operator.is_, lut.interface.outputs(), (lut.I0, lut.I1))) + assert all(map(operator.is_, lut.interface.inputs(), (lut.O,))) + assert len(lut.instances) == 1 + assert isinstance(lut.instances[0], SB_LUT4) + assert lut.instances[0].kwargs == {"LUT_INIT": A0 ^ A1} + + +def test_ice40_lut3(): + lut = LUT3(A0 ^ A1 ^ A2) + assert all( + map(operator.is_, lut.interface.outputs(), (lut.I0, lut.I1, lut.I2)) + ) + assert all(map(operator.is_, lut.interface.inputs(), (lut.O,))) + assert len(lut.instances) == 1 + assert isinstance(lut.instances[0], SB_LUT4) + assert lut.instances[0].kwargs == {"LUT_INIT": A0 ^ A1 ^ A2} diff --git a/tests/test_mantle/test_lattice/test_ice40/test_plb.py b/tests/test_mantle/test_lattice/test_ice40/test_plb.py new file mode 100644 index 000000000..a604f842d --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/test_plb.py @@ -0,0 +1,56 @@ +import hwtypes as ht + +import magma as m +from magma.mantle.lattice.ice40.plb import SB_LUT4, SB_CARRY, SB_DFF +from magma.testing.utils import check_gold + + +def test_sb_lut4(): + + class Top(m.Circuit): + io = m.IO( + I0=m.In(m.Bit), + I1=m.In(m.Bit), + I2=m.In(m.Bit), + I3=m.In(m.Bit), + O=m.Out(m.Bit) + ) + io.O @= SB_LUT4(LUT_INIT=ht.BitVector[16](0xBEEF))( + io.I0, + io.I1, + io.I2, + io.I3 + ) + + m.compile("build/test_sb_lut4", Top, output="mlir-verilog") + assert check_gold(__file__, "test_sb_lut4.v") + + +def test_sb_carry(): + + class Top(m.Circuit): + io = m.IO( + I0=m.In(m.Bit), + I1=m.In(m.Bit), + I2=m.In(m.Bit), + CI=m.In(m.Bit), + CO=m.Out(m.Bit) + ) + io.CO @= SB_CARRY()(io.I0, io.I1, io.CI) + + m.compile("build/test_sb_carry", Top, output="mlir-verilog") + assert check_gold(__file__, "test_sb_carry.v") + + +def test_sb_dff(): + + class Top(m.Circuit): + io = m.IO( + C=m.In(m.Clock), + D=m.In(m.Bit), + Q=m.Out(m.Bit), + ) + io.Q @= SB_DFF()(io.D) + + m.compile("build/test_sb_dff", Top, output="mlir-verilog") + assert check_gold(__file__, "test_sb_dff.v") From b2efd2b566110f99f9ddba384923ecd8e4fed9c2 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Tue, 8 Aug 2023 16:06:22 -0700 Subject: [PATCH 5/8] Fix name collision --- .../test_lattice/test_ice40/{test_lut.py => test_ice40_lut.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/test_mantle/test_lattice/test_ice40/{test_lut.py => test_ice40_lut.py} (100%) diff --git a/tests/test_mantle/test_lattice/test_ice40/test_lut.py b/tests/test_mantle/test_lattice/test_ice40/test_ice40_lut.py similarity index 100% rename from tests/test_mantle/test_lattice/test_ice40/test_lut.py rename to tests/test_mantle/test_lattice/test_ice40/test_ice40_lut.py From c0bdb603d37b34cf41447e1ffbfc74ceff080e6e Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Tue, 8 Aug 2023 16:19:16 -0700 Subject: [PATCH 6/8] Add gitignore --- tests/test_mantle/test_lattice/test_ice40/build/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/test_mantle/test_lattice/test_ice40/build/.gitignore diff --git a/tests/test_mantle/test_lattice/test_ice40/build/.gitignore b/tests/test_mantle/test_lattice/test_ice40/build/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/build/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From bb0b76b53ec8b7ab7f5ece2861320254f8d30ea2 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Tue, 8 Aug 2023 16:24:07 -0700 Subject: [PATCH 7/8] Fix rebase artifact --- examples/riscv_mini/tests/test_csr.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/riscv_mini/tests/test_csr.py b/examples/riscv_mini/tests/test_csr.py index 940e668b4..a0153d447 100644 --- a/examples/riscv_mini/tests/test_csr.py +++ b/examples/riscv_mini/tests/test_csr.py @@ -110,15 +110,7 @@ class CSR_DUT(m.Circuit): csr = CSRGen(x_len)() ctrl = Control.Control(x_len)() -<<<<<<< HEAD -<<<<<<< HEAD counter = Counter(n, has_cout=True, reset_type=m.Reset)() -======= - counter = Counter(n, has_cout=True)() ->>>>>>> 85818f26 (Update test_csr.py) -======= - counter = Counter(n, has_cout=True)() ->>>>>>> 85818f26 (Update test_csr.py) inst = m.mux(insts, counter.O) ctrl.inst @= inst csr.inst @= inst From 91ad707f8486809ac25869bf9dbd2451c2c907a1 Mon Sep 17 00:00:00 2001 From: Lenny Truong Date: Fri, 11 Aug 2023 16:26:05 -0700 Subject: [PATCH 8/8] Add pll and support str parameters --- magma/backend/mlir/hardware_module.py | 8 +- magma/backend/mlir/hw.py | 6 + magma/mantle/lattice/ice40/pll.py | 112 ++++++++++++++++++ .../test_ice40/gold/test_sb_pll.v | 44 +++++++ .../test_lattice/test_ice40/test_pll.py | 24 ++++ 5 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 magma/mantle/lattice/ice40/pll.py create mode 100644 tests/test_mantle/test_lattice/test_ice40/gold/test_sb_pll.v create mode 100644 tests/test_mantle/test_lattice/test_ice40/test_pll.py diff --git a/magma/backend/mlir/hardware_module.py b/magma/backend/mlir/hardware_module.py index a50e7bfaa..5b5b48d4b 100644 --- a/magma/backend/mlir/hardware_module.py +++ b/magma/backend/mlir/hardware_module.py @@ -158,14 +158,18 @@ def python_type_to_mlir_type(type_: type) -> MlirType: return builtin.IntegerType(32) if issubclass(type_, ht.BitVector): return builtin.IntegerType(len(type_)) + if type_ is str: + return hw.StringType() @wrap_with_not_implemented_error -def python_value_to_mlir_attribtue(value: Any) -> MlirAttribute: +def python_value_to_mlir_attribute(value: Any) -> MlirAttribute: if isinstance(value, int): return builtin.IntegerAttr(value) if isinstance(value, ht.BitVector): return builtin.IntegerAttr(int(value)) + if isinstance(value, str): + return builtin.StringAttr(str(value)) def get_module_interface( @@ -223,7 +227,7 @@ def _visit_input(i): def make_hw_param_decl(name: str, value: Any): type_ = python_type_to_mlir_type(type(value)) - value = python_value_to_mlir_attribtue(value) + value = python_value_to_mlir_attribute(value) return hw.ParamDeclAttr(name, type_, value) diff --git a/magma/backend/mlir/hw.py b/magma/backend/mlir/hw.py index e577d8ddd..9c78b6062 100644 --- a/magma/backend/mlir/hw.py +++ b/magma/backend/mlir/hw.py @@ -53,6 +53,12 @@ def emit(self) -> str: return f"!hw.inout<{self.T.emit()}>" +@dataclasses.dataclass(frozen=True) +class StringType(MlirType): + def emit(self) -> str: + return f"!hw.string" + + @dataclasses.dataclass(frozen=True) class InnerRefAttr(MlirAttribute): module: MlirSymbol diff --git a/magma/mantle/lattice/ice40/pll.py b/magma/mantle/lattice/ice40/pll.py new file mode 100644 index 000000000..4d7c1679b --- /dev/null +++ b/magma/mantle/lattice/ice40/pll.py @@ -0,0 +1,112 @@ +import hwtypes as ht + +from magma.bit import Bit +from magma.circuit import Circuit +from magma.clock import Clock +from magma.interface import IO +from magma.t import In, Out +from magma.generator import Generator2 + + +def _filter_range(freq_in, divr, divf): + pfd = freq_in / (divr + 1) + vco = pfd * (divf + 1) + + if pfd < 17: + return 1 + if pfd < 26: + return 2 + if pfd < 44: + return 3 + if pfd < 66: + return 4 + if pfd < 101: + return 5 + return 6 + + +def _compute_params(freq_in, freq_out): + freq_in /= 1000000 + freq_out /= 1000000 + + best_freq_out = 0. + for divr in range(16): + pfd = freq_in / (divr + 1) + if pfd < 10 or pfd > 133: + continue + + for divf in range(64): + vco = pfd * (divf + 1) + if vco < 533 or vco > 1066: + continue + + # The valid range for DIVQ is 1..6. + # + # This is correctly documented in the ICE Technology Library + # Document, but unfortunately incorrectly documented as 0..7 + # in the iCE40 sysCLOCK PLL Design and Usage Guide. + for divq in range(1, 7): + fout = vco / (1 << divq) + + # simple mode + if abs(fout - freq_out) < abs(best_freq_out - freq_out): + best_div_r = divr + best_div_f = divf + best_div_q = divq + best_freq_out = fout + return ( + best_div_r, + best_div_f, + best_div_q, + _filter_range(freq_in, best_div_r, best_div_f) + ) + + +def _make_pll_io(): + return IO( + REFERENCECLK=In(Clock), + RESETB=In(Bit), + BYPASS=In(Bit), + PLLOUTCORE=Out(Bit), + PLLOUTGLOBAL=Out(Clock) + ) + + +class SB_PLL40_CORE(Circuit): + io = _make_pll_io() + + param_types = { + "FEEDBACK_PATH": str, + "PLLOUT_SELECT": str, + "DIVR": ht.BitVector[4], # Reference clock divider (div+1) [0, ..., 15] + "DIVF": ht.BitVector[7], # Feedback divider (div+1) [0, ..., 63] + "DIVQ": ht.BitVector[3], # VCO divider (divq+1) [0, ..., 6] + "FILTER_RANGE": ht.BitVector[3] + } + + +class SB_PLL(Generator2): + def __init__(self, freq_out, freq_in=12000000): + """ + TODO(leonardt): This is a param wrapper, so shouldn't necessarily be a + generator + """ + self.name = "SB_PLL" + self.io = _make_pll_io() + + divr, divf, divq, filter = _compute_params(freq_in, freq_out) + + pll = SB_PLL40_CORE( + FEEDBACK_PATH="SIMPLE", + PLLOUT_SELECT="GENCLK", + DIVR=ht.BitVector[4](divr), + DIVF=ht.BitVector[7](divf), + DIVQ=ht.BitVector[3](divf), + FILTER_RANGE=ht.BitVector[3](filter) + ) + + pll.REFERENCECLK @= self.io.REFERENCECLK + pll.RESETB @= self.io.RESETB + pll.BYPASS @= self.io.BYPASS + self.io.PLLOUTCORE @= pll.PLLOUTCORE + self.io.PLLOUTGLOBAL @= pll.PLLOUTGLOBAL diff --git a/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_pll.v b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_pll.v new file mode 100644 index 000000000..c598c07bc --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/gold/test_sb_pll.v @@ -0,0 +1,44 @@ +// Generated by CIRCT firtool-1.48.0-34-g7018fb13b +// external module SB_PLL40_CORE + +module SB_PLL( + input REFERENCECLK, + RESETB, + BYPASS, + output PLLOUTCORE, + PLLOUTGLOBAL +); + + SB_PLL40_CORE #( + .FEEDBACK_PATH("SIMPLE"), + .PLLOUT_SELECT("GENCLK"), + .DIVR(0), + .DIVF(63), + .DIVQ(7), + .FILTER_RANGE(1) + ) SB_PLL40_CORE_inst0 ( + .REFERENCECLK (REFERENCECLK), + .RESETB (RESETB), + .BYPASS (BYPASS), + .PLLOUTCORE (PLLOUTCORE), + .PLLOUTGLOBAL (PLLOUTGLOBAL) + ); +endmodule + +module Top( + input REFERENCECLK, + RESETB, + BYPASS, + output PLLOUTCORE, + PLLOUTGLOBAL +); + + SB_PLL SB_PLL_inst0 ( + .REFERENCECLK (REFERENCECLK), + .RESETB (RESETB), + .BYPASS (BYPASS), + .PLLOUTCORE (PLLOUTCORE), + .PLLOUTGLOBAL (PLLOUTGLOBAL) + ); +endmodule + diff --git a/tests/test_mantle/test_lattice/test_ice40/test_pll.py b/tests/test_mantle/test_lattice/test_ice40/test_pll.py new file mode 100644 index 000000000..06a570585 --- /dev/null +++ b/tests/test_mantle/test_lattice/test_ice40/test_pll.py @@ -0,0 +1,24 @@ +import magma as m +from magma.mantle.lattice.ice40.pll import SB_PLL +from magma.testing.utils import check_gold + + +def test_sb_pll(): + + class Top(m.Circuit): + io = m.IO( + REFERENCECLK=m.In(m.Clock), + RESETB=m.In(m.Bit), + BYPASS=m.In(m.Bit), + PLLOUTCORE=m.Out(m.Bit), + PLLOUTGLOBAL=m.Out(m.Clock) + ) + pll = SB_PLL(32000000, 16000000)() + pll.REFERENCECLK @= io.REFERENCECLK + pll.RESETB @= io.RESETB + pll.BYPASS @= io.BYPASS + io.PLLOUTCORE @= pll.PLLOUTCORE + io.PLLOUTGLOBAL @= pll.PLLOUTGLOBAL + + m.compile("build/test_sb_pll", Top, output="mlir-verilog") + assert check_gold(__file__, "test_sb_pll.v")