diff --git a/tools/FakeRAM2.0/spreadsheet_ram.py b/tools/FakeRAM2.0/spreadsheet_ram.py index 51c221e59b..0bee0b224f 100755 --- a/tools/FakeRAM2.0/spreadsheet_ram.py +++ b/tools/FakeRAM2.0/spreadsheet_ram.py @@ -1,50 +1,21 @@ #!/usr/bin/env python3 -import re import sys -import csv -import argparse import importlib.util -from utils.timing_data import TimingData -from utils.memory_config import MemoryConfig -from utils.class_process import Process -from utils.run_utils import RunUtils from utils.rw_port_group import RWPortGroup -from utils.ss_port_creator import SSPortCreator -from utils.ss_port_organizer import SSPortOrganizer -from utils.single_port_ssram import SinglePortSSRAM - -# TODO -# support reg file # # Class to generate a single port RAM from customer-specific spreadsheet input # -# Usage: spreadsheet_ram.py --config --physical -# --mem_config -# --mapping --output_dir -# -# where -# fakeram_config - standard FakeRAM2.0 JSON config -# physical_csv - CSV file containing physical data such as size, pins (layer -# and rect) and obstructions -# metrics_csv - CSV file containing power and timing characteristics -# custom_mapping - Python3 file containing two mapping routines that are -# custom-specific (see below) -# output_dir - output directory name -# class SSRAMGenerator: """Container class for generating a spreadsheet-based memory""" - def __init__(self, config_file, util_file): + def __init__(self, util_file): """Initializer""" self._import_custom_mappings(util_file) - if config_file: - # Use config to get voltage - self._process = Process(RunUtils.get_config(config_file)) def _import_custom_mappings(self, file_name): """ @@ -69,31 +40,6 @@ def _import_custom_mappings(self, file_name): "VDD": "power", } - get_key_map - returns a dictionary that maps the CSV column to a - dictionary that helps the SSRAMGenerator properly handle - the data in its own structures. The dictionary recognizes - the following keys: - - key: name of the field in the functional or timing - data object - type: object type to convert into - conversion: optional field for unit conversion (csv - value is multiplied by the specified value - - Example: - key_map = { - "Num Words": { "key": "depth", "type": int }, - "Num Bits": { "key": "width", "type": int }, - "Num Banks": { "key": "banks", "type": int }, - "Memory Name": { "key": "name", "type": str }, - "cin (pf)":{ "key": "cap_input_pf", "type": float }, - "corner.Ts (ns)": { "key": "t_setup_ns", "type": float }, - "corner.Th (ns)": { "key": "t_hold_ns", "type": float }, - "corner.Ta (ns)": { "key": "access_time_ns", "type": float }, - "corner.Tc (ns)": { "key": "cycle_time_ns", "type": float }, - "Static Power (uW)": { "key": "standby_leakage_per_bank_mW", "type": float, "conversion": 1e-3 }, - "Dynamic Power (uW/MHz)": { "key": "pin_dynamic_power_mW", "type": float , "conversion": 1e-3}, - } """ module_name = "spreadsheet_utils" @@ -102,135 +48,6 @@ def _import_custom_mappings(self, file_name): sys.modules[module_name] = self._util_module spec.loader.exec_module(self._util_module) self._pin_type_map = self._util_module.get_pin_type_map() - self._key_map = self._util_module.get_key_map() - - def create_memory(self, mem_config, physical): - """Extracts the data from the CSV files and returns the memory object""" - - # Get the physical data and organize it - phys_data = self.read_physical_file(physical) - pin_org = SSPortOrganizer(self._pin_type_map) - pin_org.organize_ports(phys_data) - num_pins = len(phys_data["pin_data"]) - - # Get the metrics data and organize it - macro_metrics = self.read_metrics_file(mem_config, phys_data["name"]) - timing_data = TimingData(macro_metrics) - mem_config = MemoryConfig.from_json(macro_metrics) - - mem = SinglePortSSRAM(mem_config, self._process, timing_data, num_pins) - self.set_logical_pins(mem, pin_org) - port_creator = SSPortCreator(mem, self._pin_type_map) - port_creator.create_ports(phys_data["pin_data"]) - if "obs" in phys_data: - port_creator.create_obs(phys_data["obs"]) - mem.get_physical_data().set_extents( - float(phys_data["width"]), float(phys_data["height"]) - ) - # snap to grid to sync up the physical data fields - mem.get_physical_data().snap_to_grid(1, 1) - return mem - - def read_physical_file(self, file_name): - """ - Reads the physical data CSV file and returns a dictionary that includes - the pin and obstruction data - """ - - macro_data = {"pin_data": {}, "obs": []} - with open(file_name, "r", encoding="utf-8-sig") as csv_fh: - reader = csv.DictReader(csv_fh) - is_first = True - for row in reader: - # MACRO,SIZE_WIDTH,SIZE_HEIGHT,SOURCE,PIN,USE,LAYER,x1,y1,x2,y2 - if is_first: - macro_data["name"] = row["MACRO"] - macro_data["width"] = row["SIZE_WIDTH"] - macro_data["height"] = row["SIZE_HEIGHT"] - is_first = False - source = row["SOURCE"] - if source == "PIN": - pin_data = { - "name": row["PIN"], - "use": row["USE"], - "layer": row["LAYER"], - "rect": [ - float(row["x1"]), - float(row["y1"]), - float(row["x2"]), - float(row["y2"]), - ], - } - if pin_data["name"] not in macro_data["pin_data"]: - macro_data["pin_data"][pin_data["name"]] = pin_data - else: # pragma: no cover - raise Exception( - "{} had multiple pin shapes".format(pin_data["name"]) - ) - elif source == "OBS": - obs_data = { - "layer": row["LAYER"], - "layer_attr": None, - "rect": [ - float(row["x1"]), - float(row["y1"]), - float(row["x2"]), - float(row["y2"]), - ], - } - macro_data["obs"].append(obs_data) - else: - print( - "Skipping {} since source is {}".format( - row["PIN"], row["SOURCE"] - ) - ) - return macro_data - - def get_size_keys(self): - """Returns the keys that map to depth and width""" - - depth_key = width_key = None - for key, val in self._key_map.items(): - if val.get("key") == "depth": - depth_key = key - elif val.get("key") == "width": - width_key = key - return (depth_key, width_key) - - def read_metrics_file(self, file_name, macro_name): - """ - Reads the metrics CSV file to extract the power and timing data. - - Returns a dictionary that has been normalized to our expected metrics - and Process/TimingData names - - The depth and width are present on the first row and apply to all - subsequent rows until they are set again on a subsequent row. - Effectively, the cells should have been merged, but weren't. - """ - macro_metrics = {} - depth = width = None - depth_key, width_key = self.get_size_keys() - with open(file_name, "r", encoding="utf-8-sig") as csv_fh: - reader = csv.DictReader(csv_fh) - for row in reader: - if row[depth_key]: - depth = row[depth_key] - if row[width_key]: - width = row[width_key] - if row["memory_name"] == macro_name: - row[depth_key] = depth - row[width_key] = width - for csv_key, metric_key_data in self._key_map.items(): - if csv_key in row and row[csv_key] != "N/A": - metric_key = metric_key_data["key"] - metric_type_fn = metric_key_data["type"] - metric_conv_factor = metric_key_data.get("conversion", 1) - macro_metrics[metric_key] = ( - metric_type_fn(row[csv_key]) * metric_conv_factor - ) - return macro_metrics def set_logical_pins(self, mem, pin_org): """Sets the pins to be used for Verilog and Liberty output""" @@ -261,44 +78,3 @@ def set_logical_pins(self, mem, pin_org): for src in pin_org.get_misc_ports(): if src["type"] not in ["power", "ground"]: mem.add_misc_port(src["name"]) - - @staticmethod - def main(): - """Main driver""" - parser = argparse.ArgumentParser( - description="Create a set of memory colllateral from a spreadsheet input" - ) - parser.add_argument( - "--config", - help="Input configuration file containing technology parameters", - required=True, - ) - parser.add_argument( - "--mem_config", - help="CSV file containing technical parameters such as size, timing, power", - required=True, - ) - parser.add_argument( - "--physical", - help="CSV file containing physical data such as pin locations and layers", - required=True, - ) - parser.add_argument( - "--mapping", help="Custom Python mapping file", required=True - ) - parser.add_argument( - "--output_dir", - action="store", - help="Output directory ", - required=False, - default="results", - ) - - args = parser.parse_args() - rep = SSRAMGenerator(args.config, args.mapping) - mem = rep.create_memory(args.mem_config, args.physical) - RunUtils.write_memory(mem, args.output_dir) - - -if __name__ == "__main__": - SSRAMGenerator.main() diff --git a/tools/FakeRAM2.0/test/dpsram_ss_flow_test.py b/tools/FakeRAM2.0/test/dpsram_ss_flow_test.py deleted file mode 100755 index 0b9c1eb8a3..0000000000 --- a/tools/FakeRAM2.0/test/dpsram_ss_flow_test.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import unittest -import subprocess -from test_utils import TestUtils -from ss_flow_test_base import SSFlowTestBase - - -class SSDPSRAMFlowTest(SSFlowTestBase): - """Flow test for spreadsheet input dual port RAM""" - - def setUp(self): - """Sets up paths to validate results""" - self._tag = "dpsram" - SSFlowTestBase.set_up(self, self._tag) - - def test_example_input(self): - """Tests the example input run""" - - test_config = { - "ss_dpsram_128x64": { - "physical_csv": "ss_dpsram_128x64_physical.csv", - "metrics_csv": "ss_metrics.csv", - "mapping_file": "csv_map.py", - }, - } - for test_name, file_config in test_config.items(): - self._execute_run( - self._tag, - file_config["physical_csv"], - file_config["metrics_csv"], - file_config["mapping_file"], - [test_name], - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/FakeRAM2.0/test/spsram_mask_test.py b/tools/FakeRAM2.0/test/spsram_mask_test.py old mode 100644 new mode 100755 diff --git a/tools/FakeRAM2.0/test/spsram_ss_flow_test.py b/tools/FakeRAM2.0/test/spsram_ss_flow_test.py deleted file mode 100755 index a0931e912e..0000000000 --- a/tools/FakeRAM2.0/test/spsram_ss_flow_test.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import unittest -import subprocess -from test_utils import TestUtils -from ss_flow_test_base import SSFlowTestBase - - -class SSSPSRAMFlowTest(SSFlowTestBase): - """Flow test for spreadsheet input single port RAM""" - - def setUp(self): - """Sets up paths to validate results""" - self._tag = "spsram" - SSFlowTestBase.set_up(self, self._tag) - - def test_example_input(self): - """Tests the example input run""" - - test_config = { - "sssram_64x256": { - "physical_csv": "sssram_64x256_physical.csv", - "metrics_csv": "ss_metrics.csv", - "mapping_file": "csv_map.py", - }, - } - for test_name, file_config in test_config.items(): - self._execute_run( - self._tag, - file_config["physical_csv"], - file_config["metrics_csv"], - file_config["mapping_file"], - [test_name], - ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/FakeRAM2.0/test/ss_flow_test_base.py b/tools/FakeRAM2.0/test/ss_flow_test_base.py deleted file mode 100644 index 5653c9cdbd..0000000000 --- a/tools/FakeRAM2.0/test/ss_flow_test_base.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -import os -import shutil -import unittest -import subprocess -from test_utils import TestUtils -from flow_test_base import FlowTestBase - - -class SSFlowTestBase(FlowTestBase): - """Spreadsheet input flow test base class""" - - def set_up(self, tag): - result_dir = f"{tag}_results" - self._test_dir = os.path.abspath(os.path.dirname(__file__)) - self._script_dir = os.path.abspath(os.path.join(self._test_dir, "..")) - self._golden_dir = os.path.abspath(os.path.join(self._test_dir, "au")) - self._exec = os.path.join(self._script_dir, "spreadsheet_ram.py") - self._results_dir = os.path.join(self._test_dir, result_dir) - if os.path.isdir(self._results_dir): - shutil.rmtree(self._results_dir) - - def _execute_run( - self, tag, physical_csv, metrics_csv, mapping_file, expected_ram_list - ): - cfg_file_name = f"{tag}_example.cfg" - - exec_cmd = TestUtils.get_exec_name(self._exec) - cmd = ( - exec_cmd - + " --config " - + os.path.join(self._test_dir, "cfg", cfg_file_name) - + " --physical " - + os.path.join(self._test_dir, "cfg", physical_csv) - + " --mem_config " - + os.path.join(self._test_dir, "cfg", metrics_csv) - + " --mapping " - + os.path.join(self._test_dir, "cfg", mapping_file) - + " --output_dir " - + self._results_dir - ) - out = subprocess.run(cmd, check=True, shell=True) - self.assertEqual(out.returncode, 0) - self._check_results_dir(expected_ram_list)