From dd2effd28d8bfebc0a9c3ed3adb9a01b0cba28cc Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 16 Feb 2022 10:54:39 -0800 Subject: [PATCH] Initial work on separate delay and func simulation --- compiler/base/design.py | 1 - compiler/gen_stimulus.py | 40 +++++++++----------- compiler/openram.py | 11 +++--- compiler/sram/sram.py | 72 +++++++++++++++++++----------------- compiler/sram/sram_base.py | 14 ++----- compiler/sram/sram_config.py | 53 +++++++++++++++++++++++++- 6 files changed, 116 insertions(+), 75 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 70a9047b..12fd6c56 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -318,4 +318,3 @@ class design(hierarchy_design): design.setup_drc_constants() design.setup_layer_constants() - diff --git a/compiler/gen_stimulus.py b/compiler/gen_stimulus.py index 69e53cd8..d69d867d 100755 --- a/compiler/gen_stimulus.py +++ b/compiler/gen_stimulus.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # See LICENSE for licensing information. # # Copyright (c) 2016-2021 Regents of the University of California and The Board @@ -15,6 +15,7 @@ corner, but should probably be extended. import sys from globals import * +from importlib import reload (OPTS, args) = parse_args() @@ -41,36 +42,30 @@ slew = float(args[3]) import debug init_openram(config_file=config_file, is_unit_test=False) + +from sram_config import sram_config +c = sram_config(word_size=OPTS.word_size, + num_words=OPTS.num_words, + write_size=OPTS.write_size, + num_banks=OPTS.num_banks, + words_per_row=OPTS.words_per_row, + num_spare_rows=OPTS.num_spare_rows, + num_spare_cols=OPTS.num_spare_cols) + +OPTS.netlist_only = True OPTS.check_lvsdrc = False # Put the temp output in the output path since it is what we want to generate! old_openram_temp = OPTS.openram_temp OPTS.openram_temp = OPTS.output_path - - -import sram -class fake_sram(sram.sram): - """ This is an SRAM that doesn't actually create itself, just computes - the sizes. """ - def __init__(self, word_size, num_words, num_banks, name, num_spare_rows): - self.name = name - self.word_size = word_size - self.num_words = num_words - self.num_banks = num_banks - self.num_spare_rows = num_spare_rows - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() - # to get the row, col, etc. - self.compute_sizes() - -sram = fake_sram(OPTS.word_size, OPTS.num_words, OPTS.num_banks, OPTS.output_name) -sp_file = OPTS.output_path+OPTS.output_name + ".sp" +from sram import sram +s = sram(name=OPTS.output_name, sram_config=c) +s.create() from characterizer import delay import tech # Set up the delay and set to the nominal corner -d = delay.delay(sram, sp_file, ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"])) +d = delay(s, s.get_sp_name(), ("TT", tech.spice["nom_supply_voltage"], tech.spice["nom_temperature"])) # Set the period d.period = period # Set the load of outputs and slew of inputs @@ -91,4 +86,3 @@ print("Output files are:\n{0}stim.sp\n{0}sram.sp\n{0}reduced.sp".format(OPTS.out OPTS.openram_temp = old_openram_temp # Delete temp files, remove the dir, etc. end_openram() - diff --git a/compiler/openram.py b/compiler/openram.py index 089c0f3a..74f80128 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -48,7 +48,7 @@ g.print_time("Start", start_time) g.report_status() from sram_config import sram_config - +from sram import sram # Configure the SRAM organization c = sram_config(word_size=OPTS.word_size, @@ -73,9 +73,10 @@ for path in output_files: debug.print_raw(path) -from sram import sram -s = sram(sram_config=c, - name=OPTS.output_name) +s = sram(name=OPTS.output_name, sram_config=c) + +# Actually build the SRAM +s.create() # Output the files for the resulting SRAM s.save() @@ -83,5 +84,3 @@ s.save() # Delete temp files etc. g.end_openram() g.print_time("End", datetime.datetime.now(), start_time) - - diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 90855d8e..afd57f48 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -21,30 +21,39 @@ class sram(): results. We can later add visualizer and other high-level functions as needed. """ - def __init__(self, sram_config, name): + def __init__(self, name, sram_config): + self.name = name + self.config = sram_config sram_config.set_local_config(self) + self.sp_name = OPTS.output_path + self.name + ".sp" + self.lvs_name = OPTS.output_path + self.name + ".lvs.sp" + self.pex_name = OPTS.output_path + self.name + ".pex.sp" + self.gds_name = OPTS.output_path + self.name + ".gds" + self.lef_name = OPTS.output_path + self.name + ".lef" + self.v_name = OPTS.output_path + self.name + ".v" + # reset the static duplicate name checker for unit tests # in case we create more than one SRAM from design import design design.name_map=[] + def create(self): debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size, self.num_words, self.num_banks)) start_time = datetime.datetime.now() - self.name = name - if self.num_banks == 1: - from sram_1bank import sram_1bank as sram + from sram_1bank import sram_1bank as sram_banked elif self.num_banks == 2: - from sram_2bank import sram_2bank as sram + from sram_2bank import sram_2bank as sram_banked else: debug.error("Invalid number of banks.", -1) - self.s = sram(name, sram_config) + self.s = sram_banked(name=self.name, + sram_config=self.config) self.s.create_netlist() if not OPTS.netlist_only: self.s.create_layout() @@ -52,6 +61,14 @@ class sram(): if not OPTS.is_unit_test: print_time("SRAM creation", datetime.datetime.now(), start_time) + def get_sp_name(self): + if OPTS.use_pex: + # Use the extracted spice file + return self.pex_name + else: + # Use generated spice file for characterization + return self.sp_name + def sp_write(self, name, lvs=False, trim=False): self.s.sp_write(name, lvs, trim) @@ -101,11 +118,10 @@ class sram(): # Save the spice file start_time = datetime.datetime.now() - spname = OPTS.output_path + self.s.name + ".sp" - debug.print_raw("SP: Writing to {0}".format(spname)) - self.sp_write(spname) + debug.print_raw("SP: Writing to {0}".format(self.sp_name)) + self.sp_write(self.sp_name) functional(self.s, - os.path.basename(spname), + os.path.basename(self.sp_name), cycles=200, output_path=OPTS.output_path) print_time("Spice writing", datetime.datetime.now(), start_time) @@ -113,12 +129,11 @@ class sram(): if not OPTS.netlist_only: # Write the layout start_time = datetime.datetime.now() - gdsname = OPTS.output_path + self.s.name + ".gds" - debug.print_raw("GDS: Writing to {0}".format(gdsname)) - self.gds_write(gdsname) + debug.print_raw("GDS: Writing to {0}".format(self.gds_name)) + self.gds_write(self.gds_name) if OPTS.check_lvsdrc: verify.write_drc_script(cell_name=self.s.name, - gds_name=os.path.basename(gdsname), + gds_name=os.path.basename(self.gds_name), extract=True, final_verification=True, output_path=OPTS.output_path) @@ -126,20 +141,18 @@ class sram(): # Create a LEF physical model start_time = datetime.datetime.now() - lefname = OPTS.output_path + self.s.name + ".lef" - debug.print_raw("LEF: Writing to {0}".format(lefname)) - self.lef_write(lefname) + debug.print_raw("LEF: Writing to {0}".format(self.lef_name)) + self.lef_write(self.lef_name) print_time("LEF", datetime.datetime.now(), start_time) # Save the LVS file start_time = datetime.datetime.now() - lvsname = OPTS.output_path + self.s.name + ".lvs.sp" - debug.print_raw("LVS: Writing to {0}".format(lvsname)) - self.sp_write(lvsname, lvs=True) + debug.print_raw("LVS: Writing to {0}".format(self.lvs_name)) + self.sp_write(self.lvs_name, lvs=True) if not OPTS.netlist_only and OPTS.check_lvsdrc: verify.write_lvs_script(cell_name=self.s.name, - gds_name=os.path.basename(gdsname), - sp_name=os.path.basename(lvsname), + gds_name=os.path.basename(self.gds_name), + sp_name=os.path.basename(self.lvs_name), final_verification=True, output_path=OPTS.output_path) print_time("LVS writing", datetime.datetime.now(), start_time) @@ -148,14 +161,8 @@ class sram(): if OPTS.use_pex: start_time = datetime.datetime.now() # Output the extracted design if requested - pexname = OPTS.output_path + self.s.name + ".pex.sp" - spname = OPTS.output_path + self.s.name + ".sp" - verify.run_pex(self.s.name, gdsname, spname, output=pexname) - sp_file = pexname + verify.run_pex(self.s.name, self.gds_name, self.sp_name, output=self.pex_name) print_time("Extraction", datetime.datetime.now(), start_time) - else: - # Use generated spice file for characterization - sp_file = spname # Save a functional simulation file @@ -163,7 +170,7 @@ class sram(): start_time = datetime.datetime.now() from characterizer import lib debug.print_raw("LIB: Characterizing... ") - lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file) + lib(out_dir=OPTS.output_path, sram=self.s, sp_file=self.get_sp_name()) print_time("Characterization", datetime.datetime.now(), start_time) # Write the config file @@ -183,9 +190,8 @@ class sram(): # Write a verilog model start_time = datetime.datetime.now() - vname = OPTS.output_path + self.s.name + ".v" - debug.print_raw("Verilog: Writing to {0}".format(vname)) - self.verilog_write(vname) + debug.print_raw("Verilog: Writing to {0}".format(self.v_name)) + self.verilog_write(self.v_name) print_time("Verilog", datetime.datetime.now(), start_time) # Write out options if specified diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 72c5e3fe..6ecc3a5a 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -7,7 +7,7 @@ # import datetime import debug -from math import log, ceil +from math import log from importlib import reload from vector import vector from globals import OPTS, print_time @@ -20,8 +20,7 @@ from tech import spice class sram_base(design, verilog, lef): """ - Dynamically generated SRAM by connecting banks to control logic. The - number of banks should be 1 , 2 or 4 + Dynamically generated SRAM by connecting banks to control logic. """ def __init__(self, name, sram_config): design.__init__(self, name) @@ -30,17 +29,10 @@ class sram_base(design, verilog, lef): self.sram_config = sram_config sram_config.set_local_config(self) + sram_config.compute_sizes() self.bank_insts = [] - if self.write_size: - self.num_wmasks = int(ceil(self.word_size / self.write_size)) - else: - self.num_wmasks = 0 - - if not self.num_spare_cols: - self.num_spare_cols = 0 - try: from tech import power_grid self.supply_stack = power_grid diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index 4c1bb117..a65387fb 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -14,7 +14,8 @@ from sram_factory import factory class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ - def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0): + def __init__(self, word_size, num_words, write_size=None, num_banks=1, + words_per_row=None, num_spare_rows=0, num_spare_cols=0): self.word_size = word_size self.num_words = num_words # Don't add a write mask if it is the same size as the data word @@ -37,6 +38,16 @@ class sram_config: except ImportError: self.array_col_multiple = 1 + if self.write_size: + self.num_wmasks = int(ceil(self.word_size / self.write_size)) + else: + self.num_wmasks = 0 + + if not self.num_spare_cols: + self.num_spare_cols = 0 + + if not self.num_spare_rows: + self.num_spare_rows = 0 # This will get over-written when we determine the organization self.words_per_row = words_per_row @@ -167,3 +178,43 @@ class sram_config: return int(words_per_row * tentative_num_rows / 16) return words_per_row + + def setup_multiport_constants(self): + """ + These are contants and lists that aid multiport design. + Ports are always in the order RW, W, R. + Port indices start from 0 and increment. + A first RW port will have clk0, csb0, web0, addr0, data0 + A first W port (with no RW ports) will be: clk0, csb0, addr0, data0 + + """ + total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports + + # These are the read/write port indices. + self.readwrite_ports = [] + # These are the read/write and write-only port indices + self.write_ports = [] + # These are the write-only port indices. + self.writeonly_ports = [] + # These are the read/write and read-only port indices + self.read_ports = [] + # These are the read-only port indices. + self.readonly_ports = [] + # These are all the ports + self.all_ports = list(range(total_ports)) + + # The order is always fixed as RW, W, R + port_number = 0 + for port in range(OPTS.num_rw_ports): + self.readwrite_ports.append(port_number) + self.write_ports.append(port_number) + self.read_ports.append(port_number) + port_number += 1 + for port in range(OPTS.num_w_ports): + self.write_ports.append(port_number) + self.writeonly_ports.append(port_number) + port_number += 1 + for port in range(OPTS.num_r_ports): + self.read_ports.append(port_number) + self.readonly_ports.append(port_number) + port_number += 1