diff --git a/tools/FakeRAM2.0/orfs_asap7/generate.py b/tools/FakeRAM2.0/orfs_asap7/generate.py index be30f8f927..e1ba6eacb6 100644 --- a/tools/FakeRAM2.0/orfs_asap7/generate.py +++ b/tools/FakeRAM2.0/orfs_asap7/generate.py @@ -23,6 +23,15 @@ "column_mux_factor": 1, "snap_width_nm": 190, "snap_height_nm": 1400, + # A macro's power pins are horizontal M4 rails, which the platform's + # macro grid connects to the core's vertical M5 straps + # (openRoad/pdn/grid_strategy-M1-M2-M5-M6.tcl: each net every 5.4 um, + # 0.12 um wide). A narrower macro can sit between two straps of a + # net, its grid gets no shapes and pdngen fails the whole design + # (PDN-0233, or PDN-0179 when it cannot repair the channels). One pitch plus a strap, plus the rails' 0.048 um inset + # at both edges, puts a strap of each net across the rails wherever + # the macro lands. + "min_width_um": 5.4 + 0.12 + 2 * 0.048, } ASAP7_TIMING_CONFIG = { diff --git a/tools/FakeRAM2.0/test/macro_dim_test.py b/tools/FakeRAM2.0/test/macro_dim_test.py index 849fc04516..11d1b5317d 100755 --- a/tools/FakeRAM2.0/test/macro_dim_test.py +++ b/tools/FakeRAM2.0/test/macro_dim_test.py @@ -71,6 +71,29 @@ def test_macro_dim_add_height(self): self.assertAlmostEqual(height, exp_height, delta=self._delta) self.assertAlmostEqual(width, exp_width, delta=self._delta) + def test_macro_dim_min_width(self): + """A narrow macro is widened to min_width_um; a wide one is not""" + + process_data = TestUtils.get_base_process_data().copy() + process_data["min_width_um"] = 10.0 + process = Process(process_data) + # 39 bits at 2048 deep is 5.054 um wide, below the floor + width, height = process.get_macro_dimensions(39, 2048, 1, 0) + self.assertAlmostEqual(width, 10.0, delta=self._delta) + self.assertAlmostEqual(height, 663.552, delta=self._delta) + # four banks make it 20.216 um wide, above the floor + width, _ = process.get_macro_dimensions(39, 2048, 4, 0) + self.assertAlmostEqual(width, 5.054 * 4, delta=self._delta) + + def test_min_width_must_be_a_width(self): + """A min_width_um that is not a non-negative number is refused""" + + for bad in (None, "5.6", -1.0): + process_data = TestUtils.get_base_process_data().copy() + process_data["min_width_um"] = bad + with self.assertRaises(Exception): + Process(process_data) + def test_macro_dim_invalid_banks(self): """Tests detection that an invalid bank value was given""" diff --git a/tools/FakeRAM2.0/utils/class_process.py b/tools/FakeRAM2.0/utils/class_process.py index 487a853e6a..b66e5e2f5e 100644 --- a/tools/FakeRAM2.0/utils/class_process.py +++ b/tools/FakeRAM2.0/utils/class_process.py @@ -60,6 +60,17 @@ def __init__(self, json_data): self._calc_y_step() self.bitcell_width_um = json_data.get("bitcell_width_um", None) self.bitcell_height_um = json_data.get("bitcell_height_um", None) + # The narrowest macro the platform's power grid can reach; 0 for + # no floor. See ASAP7_PROCESS_CONFIG in orfs_asap7/generate.py. + self.min_width_um = json_data.get("min_width_um", 0.0) + if ( + not isinstance(self.min_width_um, (int, float)) + or isinstance(self.min_width_um, bool) + or self.min_width_um < 0 + ): + raise Exception( + "min_width_um %r is not a width in um" % (self.min_width_um,) + ) # Set to True when we want to use the process parameters or bitcell # sizes to calculate the macro dimensions. Set to False for spreadsheet @@ -118,6 +129,7 @@ def get_macro_dimensions(self, width_in_bits, depth, num_banks, additional_heigh total_width = all_bitcell_width * 1.2 total_height += additional_height + total_width = max(total_width, self.min_width_um) return (total_width, total_height)