diff --git a/.gitignore b/.gitignore index a045c64a..cb5e29e1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ sky130A/ sky130B/ skywater-pdk/ sky130_fd_bd_sram/ +docker/openram-ubuntu.log diff --git a/compiler/base/design.py b/compiler/base/design.py index fe9b5495..69d213d0 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -126,5 +126,3 @@ class design(hierarchy_design): for inst in self.insts: total_module_power += inst.mod.analytical_power(corner, load) return total_module_power - - diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index acca174f..e8fe532c 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -358,11 +358,16 @@ class spice(): " ".join(inst.get_connections()))) sp.write("\n") else: - wrapped_connections = "\n+ ".join(tr.wrap(" ".join(inst.get_connections()))) - - sp.write("X{0}\n+ {1}\n+ {2}\n".format(inst.name, - wrapped_connections, - inst.mod.cell_name)) + if trim and inst.name in self.trim_insts: + wrapped_connections = "\n*+ ".join(tr.wrap(" ".join(inst.get_connections()))) + sp.write("X{0}\n*+ {1}\n*+ {2}\n".format(inst.name, + wrapped_connections, + inst.mod.cell_name)) + else: + wrapped_connections = "\n+ ".join(tr.wrap(" ".join(inst.get_connections()))) + sp.write("X{0}\n+ {1}\n+ {2}\n".format(inst.name, + wrapped_connections, + inst.mod.cell_name)) sp.write(".ENDS {0}\n".format(self.cell_name)) diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 0920d4ea..9913173e 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -19,11 +19,12 @@ from .simulation import * from .measurements import * from .model_check import * from .analytical_util import * +from .fake_sram import * debug.info(1, "Initializing characterizer...") OPTS.spice_exe = "" -if not OPTS.analytical_delay: +if not OPTS.analytical_delay or OPTS.top_process in ["memfunc", "memchar"]: if OPTS.spice_name: # Capitalize Xyce if OPTS.spice_name == "xyce": diff --git a/compiler/characterizer/charutils.py b/compiler/characterizer/charutils.py index 872901b7..1c365fd5 100644 --- a/compiler/characterizer/charutils.py +++ b/compiler/characterizer/charutils.py @@ -7,6 +7,7 @@ # import os import re +from enum import Enum from openram import debug from openram import OPTS @@ -107,3 +108,33 @@ def check_dict_values_is_float(dict): if type(value)!=float: return False return True + + +def bidir_search(func, upper, lower, time_out=9): + """ + Performs bidirectional search over given function with given + upper and lower bounds. + """ + time_count = 0 + while time_count < time_out: + val = (upper + lower) / 2 + if func(val): + return (True, val) + time_count += 1 + return (False, 0) + + +class bit_polarity(Enum): + NONINVERTING = 0 + INVERTING = 1 + + +class sram_op(Enum): + READ_ZERO = 0 + READ_ONE = 1 + WRITE_ZERO = 2 + WRITE_ONE = 3 + DISABLED_READ_ZERO = 4 + DISABLED_READ_ONE = 5 + DISABLED_WRITE_ZERO = 6 + DISABLED_WRITE_ONE = 7 diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 90ebf80d..c1259cc0 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -13,10 +13,10 @@ from openram import OPTS from .stimuli import * from .trim_spice import * from .charutils import * -from .sram_op import * -from .bit_polarity import * from .simulation import simulation from .measurements import * +from os import path +import re class delay(simulation): @@ -37,7 +37,7 @@ class delay(simulation): """ - def __init__(self, sram, spfile, corner): + def __init__(self, sram, spfile, corner, output_path=None): super().__init__(sram, spfile, corner) self.targ_read_ports = [] @@ -47,10 +47,17 @@ class delay(simulation): self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 + + if output_path is None: + self.output_path = OPTS.openram_temp + else: + self.output_path = output_path + self.set_load_slew(0, 0) self.set_corner(corner) self.create_signal_names() self.add_graph_exclusions() + self.meas_id = 0 def create_measurement_objects(self): """ Create the measurements used for read and write ports """ @@ -79,10 +86,12 @@ class delay(simulation): self.clk_frmt = "clk{0}" # Unformatted clock name targ_name = "{0}{{}}_{1}".format(self.dout_name, self.probe_data) # Empty values are the port and probe data bit self.delay_meas = [] - self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9)) + self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "FALL", "RISE", measure_scale=1e9)) self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file. + self.delay_meas[-1].meta_add_delay = False self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9)) self.delay_meas[-1].meta_str = sram_op.READ_ZERO + self.delay_meas[-1].meta_add_delay = False self.read_lib_meas+=self.delay_meas self.slew_meas = [] @@ -103,9 +112,10 @@ class delay(simulation): self.read_lib_meas[-1].meta_str = "disabled_read0" # This will later add a half-period to the spice time delay. Only for reading 0. - for obj in self.read_lib_meas: - if obj.meta_str is sram_op.READ_ZERO: - obj.meta_add_delay = True + # FIXME: Removed this to check, see if it affects anything + #for obj in self.read_lib_meas: + # if obj.meta_str is sram_op.READ_ZERO: + # obj.meta_add_delay = True read_measures = [] read_measures.append(self.read_lib_meas) @@ -113,7 +123,9 @@ class delay(simulation): read_measures.append(self.create_bitline_measurement_objects()) read_measures.append(self.create_debug_measurement_objects()) read_measures.append(self.create_read_bit_measures()) - read_measures.append(self.create_sen_and_bitline_path_measures()) + # TODO: Maybe don't do this here (?) + if OPTS.top_process != "memchar": + read_measures.append(self.create_sen_and_bitline_path_measures()) return read_measures @@ -158,6 +170,7 @@ class delay(simulation): write_measures = [] write_measures.append(self.write_lib_meas) write_measures.append(self.create_write_bit_measures()) + return write_measures def create_debug_measurement_objects(self): @@ -216,8 +229,12 @@ class delay(simulation): bit_col = self.get_data_bit_column_number(probe_address, probe_data) bit_row = self.get_address_row_number(probe_address) - (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col) - storage_names = cell_inst.mod.get_storage_net_names() + if OPTS.top_process == "memchar": + cell_name = self.cell_name.format(bit_row, bit_col) + storage_names = ("Q", "Q_bar") + else: + (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col) + storage_names = cell_inst.mod.get_storage_net_names() debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" "supported for characterization. Storage nets={0}").format(storage_names)) if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": @@ -239,8 +256,8 @@ class delay(simulation): def create_sen_and_bitline_path_measures(self): """Create measurements for the s_en and bitline paths for individual delays per stage.""" - # FIXME: There should be a default_read_port variable in this case, pathing is done with this - # but is never mentioned otherwise +# # FIXME: There should be a default_read_port variable in this case, pathing is done with this +# # but is never mentioned otherwise port = self.read_ports[0] sen_and_port = self.sen_name + str(port) bl_and_port = self.bl_name.format(port) # bl_name contains a '{}' for the port @@ -255,8 +272,8 @@ class delay(simulation): bitline_path = bl_paths[0] # Get the measures - self.sen_path_meas = self.create_delay_path_measures(sen_path) - self.bl_path_meas = self.create_delay_path_measures(bitline_path) + self.sen_path_meas = self.create_delay_path_measures(sen_path, "sen") + self.bl_path_meas = self.create_delay_path_measures(bitline_path, "bl") all_meas = self.sen_path_meas + self.bl_path_meas # Paths could have duplicate measurements, remove them before they go to the stim file @@ -278,7 +295,7 @@ class delay(simulation): return unique_measures - def create_delay_path_measures(self, path): + def create_delay_path_measures(self, path, process): """Creates measurements for each net along given path.""" # Determine the directions (RISE/FALL) of signals @@ -290,6 +307,8 @@ class delay(simulation): cur_net, next_net = path[i], path[i + 1] cur_dir, next_dir = path_dirs[i], path_dirs[i + 1] meas_name = "delay_{0}_to_{1}".format(cur_net, next_net) + meas_name += "_" + process + "_id" + str(self.meas_id) + self.meas_id += 1 if i + 1 != len(path) - 1: path_meas.append(delay_measure(meas_name, cur_net, next_net, cur_dir, next_dir, measure_scale=1e9, has_port=False)) else: # Make the last measurement always measure on FALL because is a read 0 @@ -385,15 +404,20 @@ class delay(simulation): # creates and opens stimulus file for writing self.delay_stim_sp = "delay_stim.sp" - temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.delay_stim_sp) + temp_stim = path.join(self.output_path, self.delay_stim_sp) self.sf = open(temp_stim, "w") + # creates and opens measure file for writing + self.delay_meas_sp = "delay_meas.sp" + temp_meas = path.join(self.output_path, self.delay_meas_sp) + self.mf = open(temp_meas, "w") + if OPTS.spice_name == "spectre": self.sf.write("simulator lang=spice\n") self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period, self.load, self.slew)) - self.stim = stimuli(self.sf, self.corner) + self.stim = stimuli(self.sf, self.mf, self.corner) # include files in stimulus file self.stim.write_include(self.trim_sp_file) @@ -418,6 +442,7 @@ class delay(simulation): t_rise=self.slew, t_fall=self.slew) + self.sf.write(".include {0}".format(temp_meas)) # self.load_all_measure_nets() self.write_delay_measures() # self.write_simulation_saves() @@ -426,6 +451,7 @@ class delay(simulation): self.stim.write_control(self.cycle_times[-1] + self.period) self.sf.close() + self.mf.close() def write_power_stimulus(self, trim): """ Creates a stimulus file to measure leakage power only. @@ -435,10 +461,15 @@ class delay(simulation): # creates and opens stimulus file for writing self.power_stim_sp = "power_stim.sp" - temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.power_stim_sp) + temp_stim = path.join(self.output_path, self.power_stim_sp) self.sf = open(temp_stim, "w") self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period)) - self.stim = stimuli(self.sf, self.corner) + + # creates and opens measure file for writing + self.power_meas_sp = "power_meas.sp" + temp_meas = path.join(self.output_path, self.power_meas_sp) + self.mf = open(temp_meas, "w") + self.stim = stimuli(self.sf, self.mf, self.corner) # include UNTRIMMED files in stimulus file if trim: @@ -470,12 +501,14 @@ class delay(simulation): for port in self.all_ports: self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) + self.sf.write(".include {}".format(temp_meas)) self.write_power_measures() # run until the end of the cycle time self.stim.write_control(2 * self.period) self.sf.close() + self.mf.close() def get_measure_variants(self, port, measure_obj, measure_type=None): """ @@ -587,15 +620,15 @@ class delay(simulation): # Output some comments to aid where cycles start and # what is happening for comment in self.cycle_comments: - self.sf.write("* {0}\n".format(comment)) + self.mf.write("* {0}\n".format(comment)) self.sf.write("\n") for read_port in self.targ_read_ports: - self.sf.write("* Read ports {0}\n".format(read_port)) + self.mf.write("* Read ports {0}\n".format(read_port)) self.write_delay_measures_read_port(read_port) for write_port in self.targ_write_ports: - self.sf.write("* Write ports {0}\n".format(write_port)) + self.mf.write("* Write ports {0}\n".format(write_port)) self.write_delay_measures_write_port(write_port) def load_pex_net(self, net: str): @@ -605,8 +638,8 @@ class delay(simulation): return net original_net = net net = net[len(prefix):] - net = net.replace(".", "_").replace("[", "\[").replace("]", "\]") - for pattern in ["\sN_{}_[MXmx]\S+_[gsd]".format(net), net]: + net = net.replace(".", "_").replace("[", r"\[").replace("]", r"\]") + for pattern in [r"\sN_{}_[MXmx]\S+_[gsd]".format(net), net]: try: match = check_output(["grep", "-m1", "-o", "-iE", pattern, self.sp_file]) return prefix + match.decode().strip() @@ -616,8 +649,8 @@ class delay(simulation): def load_all_measure_nets(self): measurement_nets = set() - for port, meas in zip(self.targ_read_ports * len(self.read_meas_lists) + - self.targ_write_ports * len(self.write_meas_lists), + for port, meas in zip(self.targ_read_ports * len(self.read_meas_lists) + + self.targ_write_ports * len(self.write_meas_lists), self.read_meas_lists + self.write_meas_lists): for measurement in meas: visited = getattr(measurement, 'pex_visited', False) @@ -684,6 +717,8 @@ class delay(simulation): self.sf.write("\n* Measure statements for idle leakage power\n") # add measure statements for power + # TODO: Convert to measure statement insted of using stimuli + # measure = power_measure('leakage_power', t_initial = self.period t_final = 2 * self.period self.stim.gen_meas_power(meas_name="leakage_power", @@ -791,7 +826,7 @@ class delay(simulation): for port in self.targ_write_ports: if not self.check_bit_measures(self.write_bit_meas, port): - return(False, {}) + return (False, {}) debug.info(2, "Checking write values for port {0}".format(port)) write_port_dict = {} @@ -805,7 +840,7 @@ class delay(simulation): for port in self.targ_read_ports: # First, check that the memory has the right values at the right times if not self.check_bit_measures(self.read_bit_meas, port): - return(False, {}) + return (False, {}) debug.info(2, "Checking read delay values for port {0}".format(port)) # Check sen timing, then bitlines, then general measurements. @@ -828,7 +863,8 @@ class delay(simulation): result[port].update(read_port_dict) - self.path_delays = self.check_path_measures() + if self.sen_path_meas and self.bl_path_meas: + self.path_delays = self.check_path_measures() return (True, result) @@ -919,7 +955,7 @@ class delay(simulation): def check_bitline_meas(self, v_discharged_bl, v_charged_bl): """ Checks the value of the discharging bitline. Confirms s_en timing errors. - Returns true if the bitlines are at there expected value. + Returns true if the bitlines are at there their value. """ # The inputs looks at discharge/charged bitline rather than left or right (bl/br) # Performs two checks, discharging bitline is at least 10% away from vdd and there is a @@ -942,7 +978,7 @@ class delay(simulation): if type(val) != float or val > self.period / 2: debug.info(1, 'Failed measurement:{}={}'.format(meas.name, val)) value_dict[meas.name] = val - #debug.info(0, "value_dict={}".format(value_dict)) + # debug.info(0, "value_dict={}".format(value_dict)) return value_dict def run_power_simulation(self): @@ -992,8 +1028,8 @@ class delay(simulation): slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh) # high-to-low delays start at neg. clk edge, so they need to be less than half_period half_period = self.period / 2 - if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ - or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0: + if abs(delay_hl)>half_period or abs(delay_lh)>half_period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ + or (delay_hl<0 and delay_lh<0) or slew_hl<0 or slew_lh<0: debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, delays_str, slews_str)) @@ -1003,6 +1039,13 @@ class delay(simulation): delays_str, slews_str)) + if delay_lh < 0 and delay_hl > 0: + result_dict["delay_lh"] = result_dict["delay_hl"] + debug.info(2, "delay_lh captured precharge, using delay_hl instead") + elif delay_hl < 0 and delay_lh > 0: + result_dict["delay_hl"] = result_dict["delay_lh"] + debug.info(2, "delay_hl captured precharge, using delay_lh instead") + return True def find_min_period(self, feasible_delays): @@ -1108,32 +1151,143 @@ class delay(simulation): Netlist reduced for simulation. """ super().set_probe(probe_address, probe_data) - self.prepare_netlist() def prepare_netlist(self): """ Prepare a trimmed netlist and regular netlist. """ # Set up to trim the netlist here if that is enabled + # TODO: Copy old netlist if memchar if OPTS.trim_netlist: + #self.trim_sp_file = "{0}trimmed.sp".format(self.output_path) self.trim_sp_file = "{0}trimmed.sp".format(OPTS.openram_temp) - self.sram.sp_write(self.trim_sp_file, lvs=False, trim=True) + # Only genrate spice when running openram process + if OPTS.top_process != "memchar": + self.sram.sp_write(self.trim_sp_file, lvs=False, trim=True) else: # The non-reduced netlist file when it is disabled - self.trim_sp_file = "{0}sram.sp".format(OPTS.openram_temp) + self.trim_sp_file = "{0}sram.sp".format(self.output_path) # The non-reduced netlist file for power simulation - self.sim_sp_file = "{0}sram.sp".format(OPTS.openram_temp) + self.sim_sp_file = "{0}sram.sp".format(self.output_path) # Make a copy in temp for debugging - shutil.copy(self.sp_file, self.sim_sp_file) + if self.sp_file != self.sim_sp_file: + shutil.copy(self.sp_file, self.sim_sp_file) + + def recover_measurment_objects(self): + mf_path = path.join(OPTS.output_path, "delay_meas.sp") + self.sen_path_meas = None + self.bl_path_meas = None + if not path.exists(mf_path): + debug.info(1, "Delay measure file not found. Skipping measure recovery") + return + mf = open(mf_path, "r") + measure_text = mf.read() + port_iter = re.finditer(r"\* (Read|Write) ports (\d*)", measure_text) + port_measure_lines = [] + loc = 0 + port_name = '' + for port in port_iter: + port_measure_lines.append((port_name, measure_text[loc:port.end(0)])) + loc = port.start(0) + port_name = port.group(1) + port.group(2) + + mf.close() + # Cycle comments, not sure if i need this + # cycle_lines = port_measure_lines.pop(0)[1] + # For now just recover the bit_measures and sen_and_bitline_path_measures + self.read_meas_lists.append([]) + self.read_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []} + self.write_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []} +# bit_measure_rule = re.compile(r"\.meas tran (v_q_a\d+_b\d+_(read|write)_(zero|one)\d+) FIND v\((.*)\) AT=(\d+(\.\d+)?)n") +# for measures in port_measure_lines: +# port_name = measures[0] +# text = measures[1] +# bit_measure_iter = bit_measure_rule.finditer(text) +# for bit_measure in bit_measure_iter: +# meas_name = bit_measure.group(1) +# read = bit_measure.group(2) == "read" +# cycle = bit_measure.group(3) +# probe = bit_measure.group(4) +# polarity = bit_polarity.NONINVERTING +# if "q_bar" in meas_name: +# polarity = bit_polarity.INVERTING +# meas = voltage_at_measure(meas_name, probe) +# if read: +# if cycle == "one": +# meas.meta_str = sram_op.READ_ONE +# else: +# meas.meta_str = sram_op.READ_ZERO +# self.read_bit_meas[polarity].append(meas) +# self.read_meas_lists[-1].append(meas) +# else: +# if cycle == "one": +# meas.meta_str = sram_op.WRITE_ONE +# else: +# meas.meta_str = sram_op.WRITE_ZERO +# self.write_bit_meas[polarity].append(meas) +# self.write_meas_lists[-1].append(meas) + + delay_path_rule = re.compile(r"\.meas tran delay_(.*)_to_(.*)_(sen|bl)_(id\d*) TRIG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n TARG v\((.*)\) VAL=(\d+(\.\d+)?) (RISE|FALL)=(\d+) TD=(\d+(\.\d+)?)n") + port = self.read_ports[0] + meas_buff = [] + self.sen_path_meas = [] + self.bl_path_meas = [] + for measures in port_measure_lines: + text = measures[1] + delay_path_iter = delay_path_rule.finditer(text) + for delay_path_measure in delay_path_iter: + from_ = delay_path_measure.group(1) + to_ = delay_path_measure.group(2) + path_ = delay_path_measure.group(3) + id_ = delay_path_measure.group(4) + trig_rise = delay_path_measure.group(8) + targ_rise = delay_path_measure.group(15) + meas_name = "delay_{0}_to_{1}_{2}_{3}".format(from_, to_, path_, id_) + meas = delay_measure(meas_name, from_, to_, trig_rise, targ_rise, measure_scale=1e9, has_port=False) + meas.meta_str = sram_op.READ_ZERO + meas.meta_add_delay = True + meas_buff.append(meas) + if path_ == "sen": + self.sen_path_meas.extend(meas_buff.copy()) + meas_buff.clear() + elif path_ == "bl": + self.bl_path_meas.extend(meas_buff.copy()) + meas_buff.clear() + self.read_meas_lists.append(self.sen_path_meas + self.bl_path_meas) + + def set_spice_names(self): + """This is run in place of set_internal_spice_names function from + simulation.py when running stand-alone characterizer.""" + self.bl_name = OPTS.bl_format.format(name=self.sram.name, + hier_sep=OPTS.hier_seperator, + row="{}", + col=self.bitline_column) + self.br_name = OPTS.br_format.format(name=self.sram.name, + hier_sep=OPTS.hier_seperator, + row="{}", + col=self.bitline_column) + self.sen_name = OPTS.sen_format.format(name=self.sram.name, + hier_sep=OPTS.hier_seperator) + self.cell_name = OPTS.cell_format.format(name=self.sram.name, + hier_sep=OPTS.hier_seperator, + row="{}", + col="{}") def analysis_init(self, probe_address, probe_data): """Sets values which are dependent on the data address/bit being tested.""" self.set_probe(probe_address, probe_data) - self.create_graph() - self.set_internal_spice_names() - self.create_measurement_names() - self.create_measurement_objects() + self.prepare_netlist() + if OPTS.top_process == "memchar": + self.set_spice_names() + self.create_measurement_names() + self.create_measurement_objects() + self.recover_measurment_objects() + else: + self.create_graph() + self.set_internal_spice_names() + self.create_measurement_names() + self.create_measurement_objects() def analyze(self, probe_address, probe_data, load_slews): """ @@ -1145,7 +1299,7 @@ class delay(simulation): self.analysis_init(probe_address, probe_data) loads = [] slews = [] - for load,slew in load_slews: + for load, slew in load_slews: loads.append(load) slews.append(slew) self.load=max(loads) @@ -1168,15 +1322,16 @@ class delay(simulation): # 4) At the minimum period, measure the delay, slew and power for all slew/load pairs. self.period = min_period char_port_data = self.simulate_loads_and_slews(load_slews, leakage_offset) - if OPTS.use_specified_load_slew != None and len(load_slews) > 1: + if OPTS.use_specified_load_slew is not None and len(load_slews) > 1: debug.warning("Path delay lists not correctly generated for characterizations of more than 1 load,slew") # Get and save the path delays - bl_names, bl_delays, sen_names, sen_delays = self.get_delay_lists(self.path_delays) + if self.sen_path_meas and self.bl_path_meas: + bl_names, bl_delays, sen_names, sen_delays = self.get_delay_lists(self.path_delays) # Removed from characterization output temporarily - #char_sram_data["bl_path_measures"] = bl_delays - #char_sram_data["sen_path_measures"] = sen_delays - #char_sram_data["bl_path_names"] = bl_names - #char_sram_data["sen_path_names"] = sen_names + # char_sram_data["bl_path_measures"] = bl_delays + # char_sram_data["sen_path_measures"] = sen_delays + # char_sram_data["bl_path_names"] = bl_names + # char_sram_data["sen_path_names"] = sen_names # FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate. self.alter_lh_char_data(char_port_data) @@ -1185,7 +1340,7 @@ class delay(simulation): def alter_lh_char_data(self, char_port_data): """Copies high-to-low data to low-to-high data to make them consistent on the same clock edge.""" - # This is basically a hack solution which should be removed/fixed later. + # This is basically a hack solution which should be removed/fixed later. for port in self.all_ports: char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl'] char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl'] @@ -1194,7 +1349,6 @@ class delay(simulation): """Simulate all specified output loads and input slews pairs of all ports""" measure_data = self.get_empty_measure_data_dict() - path_dict = {} # Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways. self.targ_read_ports = self.read_ports self.targ_write_ports = self.write_ports @@ -1352,9 +1506,9 @@ class delay(simulation): # Get any available read/write port in case only a single write or read ports is being characterized. cur_read_port = self.get_available_port(get_read_port=True) cur_write_port = self.get_available_port(get_read_port=False) - debug.check(cur_read_port != None, + debug.check(cur_read_port is not None, "Characterizer requires at least 1 read port") - debug.check(cur_write_port != None, + debug.check(cur_write_port is not None, "Characterizer requires at least 1 write port") # Create test cycles for specified target ports. @@ -1402,3 +1556,6 @@ class delay(simulation): self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05) if port in self.readwrite_ports: self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05) + if self.sram.num_wmasks: + for bit in range(self.sram.num_wmasks): + self.stim.gen_pwl("WMASK{0}_{1}".format(port, bit), self.cycle_times, self.wmask_values[port][bit], self.period, self.slew, 0.05) diff --git a/compiler/characterizer/fake_sram.py b/compiler/characterizer/fake_sram.py new file mode 100644 index 00000000..07309295 --- /dev/null +++ b/compiler/characterizer/fake_sram.py @@ -0,0 +1,108 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +from openram import sram_config +from math import ceil +from openram import OPTS + + +class fake_sram(sram_config): + """ + This is an SRAM class that doesn't actually create an instance. + It will read neccessary members from HTML file from a previous run. + """ + def __init__(self, name, word_size, num_words, write_size=None, num_banks=1, + words_per_row=None, num_spare_rows=0, num_spare_cols=0): + sram_config.__init__(self, word_size, num_words, write_size, + num_banks, words_per_row, num_spare_rows, + num_spare_cols) + self.name = name + if write_size and self.write_size != self.word_size: + self.num_wmasks = int(ceil(self.word_size / self.write_size)) + else: + self.num_wmasks = 0 + + def setup_multiport_constants(self): + """ + Taken from ../base/design.py + 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 + + def generate_pins(self): + self.pins = ['vdd', 'gnd'] + self.pins.extend(['clk{}'.format(port) for port in range( + OPTS.num_rw_ports + OPTS.num_r_ports + OPTS.num_w_ports)]) + for port in range(OPTS.num_rw_ports): + self.pins.extend(['din{0}[{1}]'.format(port, bit) + for bit in range(self.word_size + self.num_spare_cols)]) + self.pins.extend(['dout{0}[{1}]'.format(port, bit) + for bit in range(self.word_size + self.num_spare_cols)]) + self.pins.extend(['addr{0}[{1}]'.format(port, bit) + for bit in range(self.addr_size)]) + self.pins.extend(['spare_wen{0}[{1}]'.format(port, bit) + for bit in range(self.num_spare_cols)]) + if self.num_wmasks != 0: + self.pins.extend(['wmask{0}[{1}]'.format(port, bit) + for bit in range(self.num_wmasks)]) + + self.pins.extend(['csb{}'.format(port), 'web{}'.format(port)]) + + start_port = OPTS.num_rw_ports + for port in range(start_port, start_port + OPTS.num_r_ports): + self.pins.extend(['dout{0}[{1}]'.format(port, bit) + for bit in range(self.word_size + self.num_spare_cols)]) + self.pins.extend(['addr{0}[{1}]'.format(port, bit) + for bit in range(self.word_size)]) + + self.pins.extend(['csb{}'.format(port)]) + + start_port += OPTS.num_r_ports + for port in range(start_port, start_port + OPTS.num_w_ports): + self.pins.extend(['din{0}[{1}]'.format(port, bit) + for bit in range(self.word_size + self.num_spare_cols)]) + self.pins.extend(['spare_wen{0}[{1}]'.format(port, bit) + for bit in range(self.num_spare_cols)]) + self.pins.extend(['addr{0}[{1}]'.format(port, bit) + for bit in range(self.addr_size)]) + if self.num_wmasks != 0: + self.pins.extend(['wmask{0}[{1}]'.format(port, bit) + for bit in range(self.num_wmasks)]) + + self.pins.extend(['csb{}'.format(port), 'web{}'.format(port)]) diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index ddf0d588..c5d5d865 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -8,12 +8,15 @@ import math import random import collections +from os import path +import shutil from numpy import binary_repr from openram import debug from openram import OPTS from .stimuli import * from .charutils import * from .simulation import simulation +from .measurements import voltage_at_measure class functional(simulation): @@ -32,13 +35,13 @@ class functional(simulation): if not spfile: # self.sp_file is assigned in base class sram.sp_write(self.sp_file, trim=OPTS.trim_netlist) + # Copy sp file to temp dir + self.temp_spice = path.join(OPTS.openram_temp, "sram.sp") + shutil.copy(self.sp_file, self.temp_spice) if not corner: corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - if period: - self.period = period - if not output_path: self.output_path = OPTS.openram_temp else: @@ -73,13 +76,20 @@ class functional(simulation): self.set_spice_constants() self.set_stimulus_variables() + # Override default period + if period: + self.period = period + # For the debug signal names self.wordline_row = 0 self.bitline_column = 0 self.create_signal_names() - self.add_graph_exclusions() - self.create_graph() - self.set_internal_spice_names() + #self.add_graph_exclusions() + #self.create_graph() + #self.set_internal_spice_names() + self.bl_name = "xsram:xbank0:bl_0_{}" + self.br_name = "xsram:xbank0:br_0_{}" + self.sen_name = "xsram:s_en" self.q_name, self.qbar_name = self.get_bit_name() debug.info(2, "q:\t\t{0}".format(self.q_name)) debug.info(2, "qbar:\t{0}".format(self.qbar_name)) @@ -145,7 +155,6 @@ class functional(simulation): comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.bank_addr_size, "0" * self.num_wmasks, 0, self.t_current) self.add_noop_all_ports(comment) - # 1. Write all the write ports 2x to seed a bunch of locations. for i in range(3): for port in self.write_ports: @@ -267,7 +276,7 @@ class functional(simulation): self.read_check.append([word, "{0}{1}".format(self.dout_name, port), self.t_current + self.period, - int(self.t_current/self.period)]) + int(self.t_current / self.period)]) def read_stim_results(self): # Extract dout values from spice timing.lis @@ -275,7 +284,8 @@ class functional(simulation): sp_read_value = "" for bit in range(self.word_size + self.num_spare_cols): measure_name = "v{0}_{1}ck{2}".format(dout_port.lower(), bit, cycle) - value = parse_spice_list("timing", measure_name) + # value = parse_spice_list("timing", measure_name) + value = self.measures[measure_name].retrieve_measure(port=0) # FIXME: Ignore the spare columns for now if bit >= self.word_size: value = 0 @@ -294,10 +304,11 @@ class functional(simulation): self.v_low, self.v_high) except ValueError: - error ="FAILED: {0}_{1} value {2} at time {3}n is not a float.".format(dout_port, + error ="FAILED: {0}_{1} value {2} at time {3}n is not a float. Measure: {4}".format(dout_port, bit, value, - eo_period) + eo_period, + measure_name) return (0, error) self.read_results.append([sp_read_value, dout_port, eo_period, cycle]) @@ -318,8 +329,8 @@ class functional(simulation): cycle, self.read_results[i][2], check_name) - return(0, error) - return(1, "SUCCESS") + return (0, error) + return (1, "SUCCESS") def gen_wmask(self): wmask = "" @@ -347,7 +358,7 @@ class functional(simulation): def gen_data(self): """ Generates a random word to write. """ # Don't use 0 or max value - random_value = random.randint(1, self.max_data - 1) + random_value = random.randint(1, self.max_data) data_bits = binary_repr(random_value, self.word_size) if self.num_spare_cols>0: random_value = random.randint(0, self.max_col_data) @@ -380,13 +391,16 @@ class functional(simulation): def write_functional_stimulus(self): """ Writes SPICE stimulus. """ self.stim_sp = "functional_stim.sp" - temp_stim = "{0}/{1}".format(self.output_path, self.stim_sp) + temp_stim = path.join(self.output_path, self.stim_sp) self.sf = open(temp_stim, "w") self.sf.write("* Functional test stimulus file for {0}ns period\n\n".format(self.period)) - self.stim = stimuli(self.sf, self.corner) + self.meas_sp = "functional_meas.sp" + temp_meas = path.join(self.output_path, self.meas_sp) + self.mf = open(temp_meas, "w") + self.stim = stimuli(self.sf, self.mf, self.corner) # Write include statements - self.stim.write_include(self.sp_file) + self.stim.write_include(self.temp_spice) # Write Vdd/Gnd statements self.sf.write("\n* Global Power Supplies\n") @@ -470,6 +484,7 @@ class functional(simulation): # Generate dout value measurements self.sf.write("\n * Generation of dout measurements\n") + self.measures = {} for (word, dout_port, eo_period, cycle) in self.read_check: t_initial = eo_period @@ -477,28 +492,37 @@ class functional(simulation): num_bits = self.word_size + self.num_spare_cols for bit in range(num_bits): signal_name = "{0}_{1}".format(dout_port, bit) - measure_name = "V{0}ck{1}".format(signal_name, cycle) + measure_name = "v{0}ck{1}".format(signal_name, cycle) voltage_value = self.stim.get_voltage(word[num_bits - bit - 1]) self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name, measure_name, voltage_value, eo_period)) - self.stim.gen_meas_value(meas_name=measure_name, - dout=signal_name, - t_initial=t_initial, - t_final=t_final) + # TODO: Convert to measurement statement instead of stimuli + meas = voltage_at_measure(measure_name, signal_name) + self.measures[measure_name] = meas + meas.write_measure(self.stim, ((t_initial + t_final) / 2, 0)) + # self.stim.gen_meas_value(meas_name=measure_name, + # dout=signal_name, + # t_initial=t_initial, + # t_final=t_final + self.sf.write(".include {0}\n".format(temp_meas)) self.stim.write_control(self.cycle_times[-1] + self.period) self.sf.close() + self.mf.close() # FIXME: Similar function to delay.py, refactor this def get_bit_name(self): """ Get a bit cell name """ - (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0) - storage_names = cell_inst.mod.get_storage_net_names() - debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" - "supported for characterization. Storage nets={0}").format(storage_names)) + # TODO: Find a way to get the cell_name and storage_names statically + # (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0) + # storage_names = cell_inst.mod.get_storage_net_names() + # debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" + # "supported for characterization. Storage nets={0}").format(storage_names)) + cell_name = "xsram:xbank0:xbitcell_array:xbitcell_array:xbit_r0_c0" + storage_names = ("Q", "Q_bar") q_name = cell_name + OPTS.hier_seperator + str(storage_names[0]) qbar_name = cell_name + OPTS.hier_seperator + str(storage_names[1]) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 7816e00b..68cc08b1 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -82,6 +82,7 @@ class lib: debug.info(1, "Slews: {0}".format(self.slews)) debug.info(1, "Loads: {0}".format(self.loads)) debug.info(1, "self.load_slews : {0}".format(self.load_slews)) + def create_corners(self): """ Create corners for characterization. """ # Get the corners from the options file @@ -801,7 +802,8 @@ class lib: # information of checks # run it only the first time - datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors)) + if OPTS.top_process != "memchar": + datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors)) # write area datasheet.write(str(self.sram.width * self.sram.height) + ',') diff --git a/compiler/characterizer/measurements.py b/compiler/characterizer/measurements.py index 83eb5f39..75ceb8a5 100644 --- a/compiler/characterizer/measurements.py +++ b/compiler/characterizer/measurements.py @@ -15,15 +15,16 @@ from .charutils import * class spice_measurement(ABC): """Base class for spice stimulus measurements.""" def __init__(self, measure_name, measure_scale=None, has_port=True): - #Names must be unique for correct spice simulation, but not enforced here. + # Names must be unique for correct spice simulation, but not enforced here. self.name = measure_name self.measure_scale = measure_scale - self.has_port = has_port #Needed for error checking - #Some meta values used externally. variables are added here for consistency accross the objects + self.has_port = has_port # Needed for error checking + # Some meta values used externally. variables are added here for consistency accross the objects self.meta_str = None self.meta_add_delay = False + @abstractmethod - def get_measure_function(self): + def measure_function(self): return None @abstractmethod @@ -31,28 +32,25 @@ class spice_measurement(ABC): return None def write_measure(self, stim_obj, input_tuple): - measure_func = self.get_measure_function() - if measure_func == None: - debug.error("Did not set measure function",1) measure_vals = self.get_measure_values(*input_tuple) - measure_func(stim_obj, *measure_vals) + self.measure_function(stim_obj, *measure_vals) def retrieve_measure(self, port=None): self.port_error_check(port) - if port != None: + if port is not None: value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port)) else: value = parse_spice_list("timing", "{0}".format(self.name.lower())) - if type(value)!=float or self.measure_scale == None: + if type(value)!=float or self.measure_scale is None: return value else: - return value*self.measure_scale + return value * self.measure_scale def port_error_check(self, port): - if self.has_port and port == None: - debug.error("Cannot retrieve measurement, port input was expected.",1) - elif not self.has_port and port != None: - debug.error("Unexpected port input received during measure retrieval.",1) + if self.has_port and port is None: + debug.error("Cannot retrieve measurement, port input was expected.", 1) + elif not self.has_port and port is not None: + debug.error("Unexpected port input received during measure retrieval.", 1) class delay_measure(spice_measurement): @@ -71,8 +69,18 @@ class delay_measure(spice_measurement): spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) - def get_measure_function(self): - return stimuli.gen_meas_delay + def measure_function(self, stim_obj, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): + """ Creates the .meas statement for the measurement of delay """ + measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" + stim_obj.mf.write(measure_string.format(meas_name.lower(), + trig_name, + trig_val, + trig_dir, + trig_td, + targ_name, + targ_val, + targ_dir, + targ_td)) def set_meas_constants(self, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd): """Set the constants for this measurement: signal names, directions, and trigger scales""" @@ -91,7 +99,7 @@ class delay_measure(spice_measurement): trig_val = self.trig_val_of_vdd * vdd_voltage targ_val = self.targ_val_of_vdd * vdd_voltage - if port != None: + if port is not None: # For dictionary indexing reasons, the name is formatted differently than the signals meas_name = "{}{}".format(self.name, port) trig_name = self.trig_name_no_port.format(port) @@ -121,7 +129,7 @@ class slew_measure(delay_measure): self.trig_val_of_vdd = 0.9 self.targ_val_of_vdd = 0.1 else: - debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1) + debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str), 1) self.trig_name_no_port = signal_name self.targ_name_no_port = signal_name @@ -135,8 +143,18 @@ class power_measure(spice_measurement): spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(power_type) - def get_measure_function(self): - return stimuli.gen_meas_power + def measure_function(self, stim_obj, meas_name, t_initial, t_final): + """ Creates the .meas statement for the measurement of avg power """ + # power mea cmd is different in different spice: + if OPTS.spice_name == "hspice": + power_exp = "power" + else: + # FIXME: Obtain proper vdd and gnd name + power_exp = "par('(-1*v(" + "vdd" + ")*I(v" + "vdd" + "))')" + stim_obj.mf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(), + power_exp, + t_initial, + t_final)) def set_meas_constants(self, power_type): """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" @@ -146,7 +164,7 @@ class power_measure(spice_measurement): def get_measure_values(self, t_initial, t_final, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" self.port_error_check(port) - if port != None: + if port is not None: meas_name = "{}{}".format(self.name, port) else: meas_name = self.name @@ -160,8 +178,15 @@ class voltage_when_measure(spice_measurement): spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) - def get_measure_function(self): - return stimuli.gen_meas_find_voltage + def measure_function(self, stim_obj, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td): + """ Creates the .meas statement for the measurement of delay """ + measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n" + stim_obj.mf.write(measure_string.format(meas_name.lower(), + targ_name, + trig_name, + trig_val, + trig_dir, + trig_td)) def set_meas_constants(self, trig_name, targ_name, trig_dir_str, trig_vdd): """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" @@ -173,7 +198,7 @@ class voltage_when_measure(spice_measurement): def get_measure_values(self, trig_td, vdd_voltage, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" self.port_error_check(port) - if port != None: + if port is not None: # For dictionary indexing reasons, the name is formatted differently than the signals meas_name = "{}{}".format(self.name, port) trig_name = self.trig_name_no_port.format(port) @@ -194,8 +219,12 @@ class voltage_at_measure(spice_measurement): spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(targ_name) - def get_measure_function(self): - return stimuli.gen_meas_find_voltage_at_time + def measure_function(self, stim_obj, meas_name, targ_name, time_at): + """ Creates the .meas statement for voltage at time""" + measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n" + stim_obj.mf.write(measure_string.format(meas_name.lower(), + targ_name, + time_at)) def set_meas_constants(self, targ_name): """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" @@ -204,7 +233,7 @@ class voltage_at_measure(spice_measurement): def get_measure_values(self, time_at, port=None): """Constructs inputs to stimulus measurement function. Variant values are inputs here.""" self.port_error_check(port) - if port != None: + if port is not None: # For dictionary indexing reasons, the name is formatted differently than the signals meas_name = "{}{}".format(self.name, port) targ_name = self.targ_name_no_port.format(port) diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index ca811ba2..9a26b2a4 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -42,7 +42,13 @@ class setup_hold(): self.stim_sp = "sh_stim.sp" temp_stim = OPTS.openram_temp + self.stim_sp self.sf = open(temp_stim, "w") - self.stim = stimuli(self.sf, self.corner) + + # creates and opens the measure file for writing + self.meas_sp = "sh_meas.sp" + temp_meas = OPTS.openram_temp + self.meas_sp + self.mf = open(temp_meas, "w") + + self.stim = stimuli(self.sf, self.mf, self.corner) self.write_header(correct_value) @@ -56,6 +62,7 @@ class setup_hold(): correct_value=correct_value) self.write_clock() + self.sf.write(".include {}\n".format(temp_meas)) self.write_measures(mode=mode, correct_value=correct_value) @@ -63,6 +70,7 @@ class setup_hold(): self.stim.write_control(4 * self.period) self.sf.close() + self.mf.close() def write_header(self, correct_value): """ Write the header file with all the models and the power supplies. """ @@ -131,7 +139,7 @@ class setup_hold(): else: dout_rise_or_fall = "FALL" - self.sf.write("\n* Measure statements for pass/fail verification\n") + self.mf.write("\n* Measure statements for pass/fail verification\n") trig_name = "clk" targ_name = "Q" trig_val = targ_val = 0.5 * self.vdd_voltage @@ -168,29 +176,33 @@ class setup_hold(): target_time=feasible_bound, correct_value=correct_value) self.stim.run_sim(self.stim_sp) - ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) + ideal_clk_to_q = convert_to_float(parse_spice_list("timing", + "clk2q_delay")) # We use a 1/2 speed clock for some reason... setuphold_time = (feasible_bound - 2 * self.period) if mode == "SETUP": # SETUP is clk-din, not din-clk passing_setuphold_time = -1 * setuphold_time else: passing_setuphold_time = setuphold_time - debug.info(2, "*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, - correct_value, - ideal_clk_to_q, - setuphold_time)) + debug.info(2, "*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}" + .format(mode, + correct_value, + ideal_clk_to_q, + setuphold_time)) if type(ideal_clk_to_q)!=float: debug.error("Initial hold time fails for data value feasible " - "bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound, - ideal_clk_to_q, - setuphold_time), + "bound {0} Clk-to-Q {1} Setup/Hold {2}" + .format(feasible_bound, + ideal_clk_to_q, + setuphold_time), 2) - debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, - setuphold_time, - feasible_bound, - 2 * self.period)) + debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} " + .format(mode, + setuphold_time, + feasible_bound, + 2 * self.period)) while True: target_time = (feasible_bound + infeasible_bound) / 2 @@ -198,11 +210,12 @@ class setup_hold(): target_time=target_time, correct_value=correct_value) - debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode, - correct_value, - target_time, - infeasible_bound, - feasible_bound)) + debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}" + .format(mode, + correct_value, + target_time, + infeasible_bound, + feasible_bound)) self.stim.run_sim(self.stim_sp) clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index c49f0e63..770aeb1a 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -235,7 +235,7 @@ class simulation(): self.add_wmask(wmask, port) self.add_spare_wen("1" * self.num_spare_cols, port) - #Add noops to all other ports. + # Add noops to all other ports. for unselected_port in self.all_ports: if unselected_port != port: self.add_noop_one_port(unselected_port) @@ -267,7 +267,7 @@ class simulation(): self.add_wmask("0" * self.num_wmasks, port) self.add_spare_wen("0" * self.num_spare_cols, port) - #Add noops to all other ports. + # Add noops to all other ports. for unselected_port in self.all_ports: if unselected_port != port: self.add_noop_one_port(unselected_port) @@ -356,14 +356,14 @@ class simulation(): self.add_noop_one_port(port) - #Add noops to all other ports. + # Add noops to all other ports. for unselected_port in self.all_ports: if unselected_port != port: self.add_noop_one_port(unselected_port) def append_cycle_comment(self, port, comment): """Add comment to list to be printed in stimulus file""" - #Clean up time before appending. Make spacing dynamic as well. + # Clean up time before appending. Make spacing dynamic as well. time = "{0:.2f} ns:".format(self.t_current) time_spacing = len(time) + 6 self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times), @@ -388,7 +388,7 @@ class simulation(): split_word2 = [x + '_' * (n != 0 and n % 4 == 0) for n, x in enumerate(split_word)] # Join the word unreversed back together new_word = ''.join(reversed(split_word2)) - return(new_word) + return (new_word) # Split extra cols if self.num_spare_cols > 0: @@ -414,9 +414,9 @@ class simulation(): comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, addr, port, - int(t_current/self.period), + int(t_current / self.period), t_current, - t_current+self.period) + t_current + self.period) elif op == "partial_write": str = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)" comment = str.format(word, @@ -454,7 +454,7 @@ class simulation(): for i in range(abits): pin_names.append("{0}{1}_{2}".format(addr_name, port, i)) - #Control signals not finalized. + # Control signals not finalized. for port in range(total_ports): pin_names.append("CSB{0}".format(port)) for port in range(total_ports): @@ -493,11 +493,12 @@ class simulation(): # other initializations can only be done during analysis when a bit has been selected # for testing. - self.sram.bank.graph_exclude_precharge() - self.sram.graph_exclude_addr_dff() - self.sram.graph_exclude_data_dff() - self.sram.graph_exclude_ctrl_dffs() - self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() + if OPTS.top_process != 'memchar': + self.sram.bank.graph_exclude_precharge() + self.sram.graph_exclude_addr_dff() + self.sram.graph_exclude_data_dff() + self.sram.graph_exclude_ctrl_dffs() + self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() def set_internal_spice_names(self): """ @@ -515,9 +516,9 @@ class simulation(): self.sen_name = sen_with_port debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") - column_addr = self.get_column_addr() + # column_addr = self.get_column_addr() bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) - port_pos = -1 - len(str(column_addr)) - len(str(port)) + # port_pos = -1 - len(str(column_addr)) - len(str(port)) if bl_name_port.endswith(str(port) + "_" + str(self.bitline_column)): # single port SRAM case, bl will not be numbered eg bl_0 self.bl_name = bl_name_port @@ -535,7 +536,7 @@ class simulation(): '{}{}_{}'.format(self.dout_name, port, self.probe_data)) self.sen_name = self.get_sen_name(self.graph.all_paths) - #debug.info(2, "s_en {}".format(self.sen_name)) + # debug.info(2, "s_en {}".format(self.sen_name)) self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1) self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1) @@ -563,10 +564,10 @@ class simulation(): Creates timing graph to generate the timing paths for the SRAM output. """ - #Make exclusions dependent on the bit being tested. + # Make exclusions dependent on the bit being tested. self.sram.clear_exclude_bits() # Removes previous bit exclusions self.sram.graph_exclude_bits(self.wordline_row, self.bitline_column) - port=self.read_ports[0] #FIXME, port_data requires a port specification, assuming single port for now + port=self.read_ports[0] # FIXME, port_data requires a port specification, assuming single port for now if self.words_per_row > 1: self.sram.graph_clear_column_mux(port) self.sram.graph_exclude_column_mux(self.bitline_column, port) diff --git a/compiler/characterizer/sram_op.py b/compiler/characterizer/sram_op.py deleted file mode 100644 index 3aeca925..00000000 --- a/compiler/characterizer/sram_op.py +++ /dev/null @@ -1,15 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# - -from enum import Enum - -class sram_op(Enum): - READ_ZERO = 0 - READ_ONE = 1 - WRITE_ZERO = 2 - WRITE_ONE = 3 diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 514c4c4e..45997b7e 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -22,7 +22,7 @@ from openram import OPTS class stimuli(): """ Class for providing stimuli functions """ - def __init__(self, stim_file, corner): + def __init__(self, stim_file, meas_file, corner): self.vdd_name = "vdd" self.gnd_name = "gnd" self.pmos_name = tech.spice["pmos"] @@ -31,6 +31,7 @@ class stimuli(): self.tx_length = tech.drc["minlength_channel"] self.sf = stim_file + self.mf = meas_file (self.process, self.voltage, self.temperature) = corner found = False @@ -136,7 +137,7 @@ class stimuli(): offset, t_rise, t_fall, - 0.5*period-0.5*t_rise-0.5*t_fall, + 0.5 * period - 0.5 * t_rise - 0.5 * t_fall, period)) def gen_pwl(self, sig_name, clk_times, data_values, period, slew, setup): @@ -181,7 +182,7 @@ class stimuli(): def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): """ Creates the .meas statement for the measurement of delay """ measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" - self.sf.write(measure_string.format(meas_name.lower(), + self.mf.write(measure_string.format(meas_name.lower(), trig_name, trig_val, trig_dir, @@ -194,7 +195,7 @@ class stimuli(): def gen_meas_find_voltage(self, meas_name, trig_name, targ_name, trig_val, trig_dir, trig_td): """ Creates the .meas statement for the measurement of delay """ measure_string=".meas tran {0} FIND v({1}) WHEN v({2})={3}v {4}=1 TD={5}n \n\n" - self.sf.write(measure_string.format(meas_name.lower(), + self.mf.write(measure_string.format(meas_name.lower(), targ_name, trig_name, trig_val, @@ -204,7 +205,7 @@ class stimuli(): def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at): """ Creates the .meas statement for voltage at time""" measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n" - self.sf.write(measure_string.format(meas_name.lower(), + self.mf.write(measure_string.format(meas_name.lower(), targ_name, time_at)) @@ -215,15 +216,15 @@ class stimuli(): power_exp = "power" else: power_exp = "par('(-1*v(" + str(self.vdd_name) + ")*I(v" + str(self.vdd_name) + "))')" - self.sf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(), + self.mf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name.lower(), power_exp, t_initial, t_final)) def gen_meas_value(self, meas_name, dout, t_initial, t_final): measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2) - #measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) - self.sf.write(measure_string) + # measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) + self.mf.write(measure_string) def write_control(self, end_time, runlvl=4): """ Write the control cards to run and end the simulation """ @@ -278,7 +279,7 @@ class stimuli(): self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature)) self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n") self.sf.write(".OPTIONS LINSOL type=klu\n") - self.sf.write(".OPTIONS TIMEINT RELTOL=1e-6 ABSTOL=1e-10 method=gear minorder=2\n") + self.sf.write(".OPTIONS TIMEINT RELTOL=1e-3 ABSTOL=1e-6 method=gear minorder=2\n") # Format: .TRAN self.sf.write(".TRAN {0}p {1}n 0n {0}p\n".format(timestep, end_time)) elif OPTS.spice_name: @@ -411,12 +412,12 @@ class stimuli(): from openram import CONDA_HOME cmd = "source {0}/bin/activate && {1} && conda deactivate".format(CONDA_HOME, cmd) debug.info(2, cmd) - retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) + proc = subprocess.run(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) spice_stdout.close() spice_stderr.close() - if (retcode > valid_retcode): + if (proc.returncode > valid_retcode): debug.error("Spice simulation error: " + cmd, -1) else: end_time = datetime.datetime.now() diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index 73f0da65..ba606cf3 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -85,14 +85,15 @@ class trim_spice(): wl_regex = r"wl\d*_{}".format(wl_address) bl_regex = r"bl\d*_{}".format(int(self.words_per_row*data_bit + col_address)) + bl_no_port_regex = r"bl_{}".format(int(self.words_per_row*data_bit + col_address)) + self.remove_insts("bitcell_array",[wl_regex,bl_regex]) # 2. Keep sense amps basd on BL - # FIXME: The bit lines are not indexed the same in sense_amp_array - #self.remove_insts("sense_amp_array",[bl_regex]) + self.remove_insts("sense_amp_array",[bl_no_port_regex]) # 3. Keep column muxes basd on BL - self.remove_insts("column_mux_array", [bl_regex]) + self.remove_insts("single_level_column_mux_array", [bl_no_port_regex]) # 4. Keep write driver based on DATA data_regex = r"data_{}".format(data_bit) diff --git a/compiler/gen_stimulus.py b/compiler/gen_stimulus.py index 0dbc65b8..969f4fb8 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-2023 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,29 @@ 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) 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 +85,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/options.py b/compiler/options.py index 3a9bb3a8..4a5f7dde 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -104,6 +104,8 @@ class options(optparse.Values): sim_data_path = None # A list of load/slew tuples use_specified_load_slew = None + # Spice simulation raw file + spice_raw_file = None ################### # Run-time vs accuracy options. @@ -126,14 +128,18 @@ class options(optparse.Values): # Output config with all options output_extended_config = False # Output temporary file used to format HTML page - output_datasheet_info = False + output_datasheet_info = True # Determines which analytical model to use. # Available Models: elmore, linear_regression model_name = "elmore" + # Write graph to a file + write_graph = False ################### # Tool options ################### + # Top process that was ran (openram, memchar, memfunc) + top_process = None # Use conda to install the default tools # (existing tools will be used if disabled) use_conda = True @@ -174,6 +180,11 @@ class options(optparse.Values): # Purge the temp directory after a successful # run (doesn't purge on errors, anyhow) + # Bitline, s_en and cell names used in characterizer + bl_format = "X{name}{hier_sep}xbank0{hier_sep}bl_{row}_{col}" + br_format = "X{name}{hier_sep}xbank0{hier_sep}br_{row}_{col}" + sen_format = "X{name}{hier_sep}xbank0{hier_sep}s_en" + cell_format = "X{name}{hier_sep}xbank0{hier_sep}xbitcell_array{hier_sep}xreplica_bitcell_array{hier_sep}xbitcell_array{hier_sep}xbit_r{row}_c{col}" # Route the input/output pins to the perimeter perimeter_pins = True diff --git a/compiler/sram.py b/compiler/sram.py index 7b807d66..cc269d8f 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -60,6 +60,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) @@ -95,18 +103,40 @@ class sram(): # is loaded and the right tools are selected from openram import verify from openram.characterizer import functional + from openram.characterizer import delay # 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) + + # Save a functional simulation file with default period functional(self.s, - os.path.basename(spname), + spname, cycles=200, output_path=OPTS.output_path) print_time("Spice writing", datetime.datetime.now(), start_time) + # Save stimulus and measurement file + start_time = datetime.datetime.now() + debug.print_raw("DELAY: Writing stimulus...") + d = delay(self.s, spname, ("TT", 5, 25), output_path=OPTS.output_path) + if (self.s.num_spare_rows == 0): + probe_address = "1" * self.s.addr_size + else: + probe_address = "0" + "1" * (self.s.addr_size - 1) + probe_data = self.s.word_size - 1 + d.analysis_init(probe_address, probe_data) + d.targ_read_ports.extend(self.s.read_ports) + d.targ_write_ports = [self.s.write_ports[0]] + d.write_delay_stimulus() + print_time("DELAY", datetime.datetime.now(), start_time) + + # Save trimmed spice file + temp_trim_sp = "{0}trimmed.sp".format(OPTS.output_path) + self.sp_write(temp_trim_sp, lvs=False, trim=True) + if not OPTS.netlist_only: # Write the layout start_time = datetime.datetime.now() @@ -154,8 +184,6 @@ class sram(): # Use generated spice file for characterization sp_file = spname - # Save a functional simulation file - # Characterize the design start_time = datetime.datetime.now() from openram.characterizer import lib diff --git a/compiler/sram_config.py b/compiler/sram_config.py index 465d6434..afb660f0 100644 --- a/compiler/sram_config.py +++ b/compiler/sram_config.py @@ -14,7 +14,8 @@ from openram import OPTS 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 @@ -38,6 +39,11 @@ class sram_config: except ImportError: self.array_col_multiple = 1 + 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 @@ -175,3 +181,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 diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index 681f4fff..46e2e66f 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -25,6 +25,8 @@ class model_delay_test(openram_test): openram.init_openram(config_file, is_unit_test=True) OPTS.analytical_delay = False OPTS.netlist_only = True + OPTS.spice_name = "Xyce" + OPTS.num_sim_threads = 8 # This is a hack to reload the characterizer __init__ with the spice version from importlib import reload diff --git a/compiler/tests/21_ngspice_delay_extra_rows_test.py b/compiler/tests/21_ngspice_delay_extra_rows_test.py index bf2dc358..531816f5 100755 --- a/compiler/tests/21_ngspice_delay_extra_rows_test.py +++ b/compiler/tests/21_ngspice_delay_extra_rows_test.py @@ -61,35 +61,36 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'slew_lh': [0.2592187], - 'slew_hl': [0.2592187], - 'delay_lh': [0.2465583], - 'disabled_write0_power': [0.1924678], - 'disabled_read0_power': [0.152483], - 'write0_power': [0.3409064], - 'disabled_read1_power': [0.1737818], - 'read0_power': [0.3096708], - 'read1_power': [0.3107916], - 'delay_hl': [0.2465583], - 'write1_power': [0.26915849999999997], - 'leakage_power': 0.002044307, - 'min_period': 0.898, - 'disabled_write1_power': [0.201411]} + golden_data = {'delay_hl': [0.263898], + 'delay_lh': [0.263898], + 'disabled_read0_power': [0.06625703], + 'disabled_read1_power': [0.07531121], + 'disabled_write0_power': [0.09350641999999999], + 'disabled_write1_power': [0.09988823000000001], + 'leakage_power': 0.01192385, + 'min_period': 2.031, + 'read0_power': [0.14745439999999999], + 'read1_power': [0.1470831], + 'slew_hl': [0.027165], + 'slew_lh': [0.027165], + 'write0_power': [0.1630546], + 'write1_power': [0.1319501]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'read1_power': [12.11658], - 'write1_power': [10.52653], - 'read0_power': [11.956710000000001], - 'disabled_write0_power': [7.673665], - 'disabled_write1_power': [7.981922000000001], - 'slew_lh': [1.868836], - 'slew_hl': [1.868836], - 'delay_hl': [1.8598510000000001], - 'delay_lh': [1.8598510000000001], - 'leakage_power': 0.005457728, - 'disabled_read0_power': [5.904712], - 'min_period': 6.875, - 'disabled_read1_power': [7.132159], - 'write0_power': [13.406400000000001]} + golden_data = {'delay_hl': [1.8259260000000002], + 'delay_lh': [1.8259260000000002], + 'disabled_read0_power': [6.722809], + 'disabled_read1_power': [8.104113], + 'disabled_write0_power': [8.900671], + 'disabled_write1_power': [9.188668], + 'leakage_power': 0.6977637, + 'min_period': 6.562, + 'read0_power': [15.45948], + 'read1_power': [15.48587], + 'slew_hl': [0.1936536], + 'slew_lh': [0.1936536], + 'write0_power': [17.03442], + 'write1_power': [13.05424]} + else: self.assertTrue(False) # other techs fail diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 8f3e05be..eaf5d8a2 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -69,35 +69,36 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.24671600000000002], - 'delay_lh': [0.24671600000000002], - 'disabled_read0_power': [0.1749204], - 'disabled_read1_power': [0.1873704], - 'disabled_write0_power': [0.204619], - 'disabled_write1_power': [0.2262653], - 'leakage_power': 0.0021375310000000002, - 'min_period': 0.977, - 'read0_power': [0.3856875], - 'read1_power': [0.38856060000000003], - 'slew_hl': [0.2842019], - 'slew_lh': [0.2842019], - 'write0_power': [0.45274410000000004], - 'write1_power': [0.38727789999999995]} + golden_data = {'delay_hl': [0.2764415], + 'delay_lh': [0.2764415], + 'disabled_read0_power': [0.18364834], + 'disabled_read1_power': [0.20878333999999998], + 'disabled_write0_power': [0.24064433999999998], + 'disabled_write1_power': [0.27207664], + 'leakage_power': 0.0443369, + 'min_period': 0.938, + 'read0_power': [0.37790994], + 'read1_power': [0.37646214], + 'slew_hl': [0.0266144], + 'slew_lh': [0.0266144], + 'write0_power': [0.44694044], + 'write1_power': [0.36824544000000003]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.882508], - 'delay_lh': [1.882508], - 'disabled_read0_power': [7.487227], - 'disabled_read1_power': [8.749013], - 'disabled_write0_power': [9.268901], - 'disabled_write1_power': [9.962973], - 'leakage_power': 0.0046686359999999994, - 'min_period': 7.188, - 'read0_power': [16.64011], - 'read1_power': [17.20825], - 'slew_hl': [2.039655], - 'slew_lh': [2.039655], - 'write0_power': [19.31883], - 'write1_power': [15.297369999999999]} + golden_data = {'delay_hl': [1.905376], + 'delay_lh': [1.905376], + 'disabled_read0_power': [7.673850999999999], + 'disabled_read1_power': [10.051073], + 'disabled_write0_power': [10.638803], + 'disabled_write1_power': [10.385253], + 'leakage_power': 2.704021, + 'min_period': 6.875, + 'read0_power': [17.583853], + 'read1_power': [17.689162999999997], + 'slew_hl': [0.19331199999999998], + 'slew_lh': [0.19331199999999998], + 'write0_power': [20.607043], + 'write1_power': [16.107403]} + else: self.assertTrue(False) # other techs fail diff --git a/compiler/tests/21_xyce_delay_test.py b/compiler/tests/21_xyce_delay_test.py index be5a70ee..1c62ad1b 100755 --- a/compiler/tests/21_xyce_delay_test.py +++ b/compiler/tests/21_xyce_delay_test.py @@ -84,20 +84,20 @@ class timing_sram_test(openram_test): 'write0_power': [0.429895901], 'write1_power': [0.383337501]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.884186], - 'delay_lh': [1.884186], - 'disabled_read0_power': [20.86336], - 'disabled_read1_power': [22.10636], - 'disabled_write0_power': [22.62321], - 'disabled_write1_power': [23.316010000000002], - 'leakage_power': 13.351170000000002, - 'min_period': 7.188, - 'read0_power': [29.90159], - 'read1_power': [30.47858], - 'slew_hl': [2.042723], - 'slew_lh': [2.042723], - 'write0_power': [32.13199], - 'write1_power': [28.46703]} + golden_data = {'delay_hl': [1.78586], + 'delay_lh': [1.78586], + 'disabled_read0_power': [7.8296693788], + 'disabled_read1_power': [9.1464723788], + 'disabled_write0_power': [9.6889073788], + 'disabled_write1_power': [10.4123023788], + 'leakage_power': 0.0002442851, + 'min_period': 6.875, + 'read0_power': [16.995952378800002], + 'read1_power': [17.5845523788], + 'slew_hl': [2.039202], + 'slew_lh': [2.039202], + 'write0_power': [19.785462378800002], + 'write1_power': [15.742192378799999]} else: self.assertTrue(False) # other techs fail # Check if no too many or too few results diff --git a/compiler/tests/30_openram_sram_char_test.py b/compiler/tests/30_openram_sram_char_test.py new file mode 100755 index 00000000..748abecf --- /dev/null +++ b/compiler/tests/30_openram_sram_char_test.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os, re +import shutil +import getpass +import unittest +from testutils import * + +import openram +from openram import debug +from openram import OPTS + + +class sram_char_test(openram_test): + + def runTest(self): + global OPTS + out_file = "sram_2_16_1_{0}".format(OPTS.tech_name) + out_path = "{0}/testsram_{1}_{2}_{3}".format(OPTS.openram_temp, OPTS.tech_name, getpass.getuser(), os.getpid()) + OPTS.output_name = out_file + OPTS.output_path = out_path + + OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) + config_file = "{}/tests/configs/config_mem_char_func".format(OPENRAM_HOME) + + openram.init_openram(config_file, is_unit_test=False) + sp_file = "{0}/tests/sp_files/{1}.sp".format(OPENRAM_HOME, OPTS.output_name) + + debug.info(1, "Testing commandline characterizer script sram_char.py with 2-bit, 16 word SRAM.") + + # make sure we start without the files existing + if os.path.exists(out_path): + shutil.rmtree(out_path, ignore_errors=True) + self.assertEqual(os.path.exists(out_path), False) + + try: + os.makedirs(out_path, 0o0750) + except OSError as e: + if e.errno == 17: # errno.EEXIST + os.chmod(out_path, 0o0750) + + # specify the same verbosity for the system call + options = "" + for i in range(OPTS.verbose_level): + options += " -v" + + if OPTS.spice_name: + options += " -s {}".format(OPTS.spice_name) + + if OPTS.tech_name: + options += " -t {}".format(OPTS.tech_name) + + options += " -j 2" + + # Always perform code coverage + if OPTS.coverage == 0: + debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage") + exe_name = "{0}/../sram_char.py ".format(OPENRAM_HOME) + else: + exe_name = "{0}{1}/../sram_char.py ".format(OPTS.coverage_exe, OPENRAM_HOME) + config_name = "{0}/tests/configs/config_mem_char_func.py".format(OPENRAM_HOME) + cmd = "{0} -n -o {1} -p {2} {3} {4} {5} 2>&1 > {6}/output.log".format(exe_name, + out_file, + out_path, + options, + config_name, + sp_file, + out_path) + debug.info(1, cmd) + os.system(cmd) + + # grep any errors from the output + output_log = open("{0}/{1}.log".format(out_path, out_file), "r") + output = output_log.read() + output_log.close() + self.assertEqual(len(re.findall('ERROR', output)), 0) + self.assertEqual(len(re.findall('WARNING', output)), 0) + + # now clean up the directory + if not OPTS.keep_temp: + if os.path.exists(out_path): + shutil.rmtree(out_path, ignore_errors=True) + self.assertEqual(os.path.exists(out_path), False) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/30_openram_sram_func_test.py b/compiler/tests/30_openram_sram_func_test.py new file mode 100755 index 00000000..3a5d6283 --- /dev/null +++ b/compiler/tests/30_openram_sram_func_test.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os, re +import shutil +import getpass +import unittest +from testutils import * + +import openram +from openram import debug +from openram import OPTS + + +class sram_func_test(openram_test): + + def runTest(self): + global OPTS + out_file = "sram_2_16_1_{0}".format(OPTS.tech_name) + out_path = "{0}/testsram_{1}_{2}_{3}".format(OPTS.openram_temp, OPTS.tech_name, getpass.getuser(), os.getpid()) + OPTS.output_name = out_file + OPTS.output_path = out_path + + OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) + config_file = "{}/tests/configs/config_mem_char_func".format(OPENRAM_HOME) + + openram.init_openram(config_file, is_unit_test=False) + sp_file = "{0}/tests/sp_files/{1}.sp".format(OPENRAM_HOME, OPTS.output_name) + + debug.info(1, "Testing commandline functional simulator script sram_char.py with 2-bit, 16 word SRAM.") + + # make sure we start without the files existing + if os.path.exists(out_path): + shutil.rmtree(out_path, ignore_errors=True) + self.assertEqual(os.path.exists(out_path), False) + + try: + os.makedirs(out_path, 0o0750) + except OSError as e: + if e.errno == 17: # errno.EEXIST + os.chmod(out_path, 0o0750) + + # specify the same verbosity for the system call + options = "" + for i in range(OPTS.verbose_level): + options += " -v" + + if OPTS.spice_name: + options += " -s {}".format(OPTS.spice_name) + + if OPTS.tech_name: + options += " -t {}".format(OPTS.tech_name) + + options += " -j 2" + + # Always perform code coverage + if OPTS.coverage == 0: + debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage") + exe_name = "{0}/../sram_func.py ".format(OPENRAM_HOME) + else: + exe_name = "{0}{1}/../sram_func.py ".format(OPTS.coverage_exe, OPENRAM_HOME) + config_name = "{0}/tests/configs/config_mem_char_func.py".format(OPENRAM_HOME) + period_and_cycles = 10 + cmd = "{0} -n -o {1} -p {2} {3} {4} {5} {6} {6} 2>&1 > {7}/output.log".format(exe_name, + out_file, + out_path, + options, + config_name, + sp_file, + period_and_cycles, + out_path) + debug.info(1, cmd) + os.system(cmd) + + # grep any errors from the output + output_log = open("{0}/output.log".format(out_path), "r") + output = output_log.read() + output_log.close() + self.assertEqual(len(re.findall('ERROR', output)), 0) + self.assertEqual(len(re.findall('WARNING', output)), 0) + + # now clean up the directory + if not OPTS.keep_temp: + if os.path.exists(out_path): + shutil.rmtree(out_path, ignore_errors=True) + self.assertEqual(os.path.exists(out_path), False) + + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 5fd0929c..7f1bef57 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -180,6 +180,8 @@ BROKEN_STAMPS = \ sky130/30_openram_back_end_test.ok \ sky130/30_openram_front_end_library_test.ok \ sky130/30_openram_front_end_test.ok \ + sky130/30_openram_sram_char_test.ok \ + sky130/30_openram_sram_func_test.ok \ gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) diff --git a/compiler/tests/b3v3_1check.log b/compiler/tests/b3v3_1check.log new file mode 100644 index 00000000..6903570b --- /dev/null +++ b/compiler/tests/b3v3_1check.log @@ -0,0 +1,5 @@ +BSIM3V3.1 Parameter Check +Model = p +W = 6e-07, L = 8e-07 +Warning: Pd = 0 is less than W. +Warning: Ps = 0 is less than W. diff --git a/compiler/characterizer/bit_polarity.py b/compiler/tests/configs/config_mem_char_func.py similarity index 61% rename from compiler/characterizer/bit_polarity.py rename to compiler/tests/configs/config_mem_char_func.py index 5a6b6a06..767f2c75 100644 --- a/compiler/characterizer/bit_polarity.py +++ b/compiler/tests/configs/config_mem_char_func.py @@ -5,10 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from openram import OPTS +word_size = 2 +num_words = 16 -from enum import Enum - -class bit_polarity(Enum): - NONINVERTING = 0 - INVERTING = 1 +tech_name = OPTS.tech_name +output_name = "sram" +analytical_delay = False +nominal_corner_only = True +spice_name = "Xyce" diff --git a/compiler/tests/sp_files/sram_2_16_1_freepdk45.sp b/compiler/tests/sp_files/sram_2_16_1_freepdk45.sp new file mode 100644 index 00000000..c638e514 --- /dev/null +++ b/compiler/tests/sp_files/sram_2_16_1_freepdk45.sp @@ -0,0 +1,1748 @@ +************************************************** +* OpenRAM generated memory. +* Words: 16 +* Data bits: 2 +* Banks: 1 +* Column mux: 1:1 +* Trimmed: False +* LVS: False +************************************************** +* File: DFFPOSX1.pex.netlist +* Created: Wed Jan 2 18:36:24 2008 +* Program "Calibre xRC" +* Version "v2007.2_34.24" +* +.subckt dff D Q clk vdd gnd +* +MM21 Q a_66_6# gnd gnd NMOS_VTG L=5e-08 W=5e-07 +MM19 a_76_6# a_2_6# a_66_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM20 gnd Q a_76_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM18 a_66_6# clk a_61_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM17 a_61_6# a_34_4# gnd gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM10 gnd clk a_2_6# gnd NMOS_VTG L=5e-08 W=5e-07 +MM16 a_34_4# a_22_6# gnd gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM15 gnd a_34_4# a_31_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM14 a_31_6# clk a_22_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM13 a_22_6# a_2_6# a_17_6# gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM12 a_17_6# D gnd gnd NMOS_VTG L=5e-08 W=2.5e-07 +MM11 Q a_66_6# vdd vdd PMOS_VTG L=5e-08 W=1e-06 +MM9 vdd Q a_76_84# vdd PMOS_VTG L=5e-08 W=2.5e-07 +MM8 a_76_84# clk a_66_6# vdd PMOS_VTG L=5e-08 W=2.5e-07 +MM7 a_66_6# a_2_6# a_61_74# vdd PMOS_VTG L=5e-08 W=5e-07 +MM6 a_61_74# a_34_4# vdd vdd PMOS_VTG L=5e-08 W=5e-07 +MM0 vdd clk a_2_6# vdd PMOS_VTG L=5e-08 W=1e-06 +MM5 a_34_4# a_22_6# vdd vdd PMOS_VTG L=5e-08 W=5e-07 +MM4 vdd a_34_4# a_31_74# vdd PMOS_VTG L=5e-08 W=5e-07 +MM3 a_31_74# a_2_6# a_22_6# vdd PMOS_VTG L=5e-08 W=5e-07 +MM2 a_22_6# clk a_17_74# vdd PMOS_VTG L=5e-08 W=5e-07 +MM1 a_17_74# D vdd vdd PMOS_VTG L=5e-08 W=5e-07 +* c_9 a_66_6# 0 0.271997f +* c_20 clk 0 0.350944f +* c_27 Q 0 0.202617f +* c_32 a_76_84# 0 0.0210573f +* c_38 a_76_6# 0 0.0204911f +* c_45 a_34_4# 0 0.172306f +* c_55 a_2_6# 0 0.283119f +* c_59 a_22_6# 0 0.157312f +* c_64 D 0 0.0816386f +* c_73 gnd 0 0.254131f +* c_81 vdd 0 0.23624f +* +*.include "dff.pex.netlist.dff.pxi" +* +.ends +* +* + +.SUBCKT sram_2_16_1_freepdk45_data_dff ++ din_0 din_1 dout_0 dout_1 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* rows: 1 cols: 2 +Xdff_r0_c0 ++ din_0 dout_0 clk vdd gnd ++ dff +Xdff_r0_c1 ++ din_1 dout_1 clk vdd gnd ++ dff +.ENDS sram_2_16_1_freepdk45_data_dff + +* spice ptx M{0} {1} pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p + +* spice ptx M{0} {1} nmos_vtg m=1 w=0.09u l=0.05u pd=0.28u ps=0.28u as=0.01p ad=0.01p + +.SUBCKT sram_2_16_1_freepdk45_pinv_10 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.09u l=0.05u pd=0.28u ps=0.28u as=0.01p ad=0.01p +.ENDS sram_2_16_1_freepdk45_pinv_10 + +.SUBCKT sram_2_16_1_freepdk45_delay_chain ++ in out vdd gnd +* INPUT : in +* OUTPUT: out +* POWER : vdd +* GROUND: gnd +* fanouts: [4, 4, 4, 4, 4, 4, 4, 4, 4] +Xdinv0 ++ in dout_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_0_0 ++ dout_1 n_0_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_0_1 ++ dout_1 n_0_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_0_2 ++ dout_1 n_0_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_0_3 ++ dout_1 n_0_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv1 ++ dout_1 dout_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_1_0 ++ dout_2 n_1_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_1_1 ++ dout_2 n_1_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_1_2 ++ dout_2 n_1_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_1_3 ++ dout_2 n_1_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv2 ++ dout_2 dout_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_2_0 ++ dout_3 n_2_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_2_1 ++ dout_3 n_2_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_2_2 ++ dout_3 n_2_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_2_3 ++ dout_3 n_2_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv3 ++ dout_3 dout_4 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_3_0 ++ dout_4 n_3_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_3_1 ++ dout_4 n_3_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_3_2 ++ dout_4 n_3_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_3_3 ++ dout_4 n_3_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv4 ++ dout_4 dout_5 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_4_0 ++ dout_5 n_4_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_4_1 ++ dout_5 n_4_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_4_2 ++ dout_5 n_4_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_4_3 ++ dout_5 n_4_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv5 ++ dout_5 dout_6 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_5_0 ++ dout_6 n_5_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_5_1 ++ dout_6 n_5_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_5_2 ++ dout_6 n_5_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_5_3 ++ dout_6 n_5_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv6 ++ dout_6 dout_7 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_6_0 ++ dout_7 n_6_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_6_1 ++ dout_7 n_6_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_6_2 ++ dout_7 n_6_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_6_3 ++ dout_7 n_6_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv7 ++ dout_7 dout_8 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_7_0 ++ dout_8 n_7_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_7_1 ++ dout_8 n_7_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_7_2 ++ dout_8 n_7_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_7_3 ++ dout_8 n_7_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdinv8 ++ dout_8 out vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_8_0 ++ out n_8_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_8_1 ++ out n_8_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_8_2 ++ out n_8_2 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +Xdload_8_3 ++ out n_8_3 vdd gnd ++ sram_2_16_1_freepdk45_pinv_10 +.ENDS sram_2_16_1_freepdk45_delay_chain + +* spice ptx M{0} {1} pmos_vtg m=1 w=0.54u l=0.05u pd=1.18u ps=1.18u as=0.07p ad=0.07p + +* spice ptx M{0} {1} nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p + +.SUBCKT sram_2_16_1_freepdk45_pinv_0 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.54u l=0.05u pd=1.18u ps=1.18u as=0.07p ad=0.07p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pinv_0 + +* spice ptx M{0} {1} nmos_vtg m=2 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p + +* spice ptx M{0} {1} pmos_vtg m=2 w=0.54u l=0.05u pd=1.18u ps=1.18u as=0.07p ad=0.07p + +.SUBCKT sram_2_16_1_freepdk45_pinv_1 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=2 w=0.54u l=0.05u pd=1.18u ps=1.18u as=0.07p ad=0.07p +Mpinv_nmos Z A gnd gnd nmos_vtg m=2 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pinv_1 + +.SUBCKT sram_2_16_1_freepdk45_dff_buf_0 ++ D Q Qb clk vdd gnd +* INPUT : D +* OUTPUT: Q +* OUTPUT: Qb +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* inv1: 2 inv2: 4 +Xdff_buf_dff ++ D qint clk vdd gnd ++ dff +Xdff_buf_inv1 ++ qint Qb vdd gnd ++ sram_2_16_1_freepdk45_pinv_0 +Xdff_buf_inv2 ++ Qb Q vdd gnd ++ sram_2_16_1_freepdk45_pinv_1 +.ENDS sram_2_16_1_freepdk45_dff_buf_0 + +.SUBCKT sram_2_16_1_freepdk45_dff_buf_array ++ din_0 din_1 dout_0 dout_bar_0 dout_1 dout_bar_1 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* OUTPUT: dout_0 +* OUTPUT: dout_bar_0 +* OUTPUT: dout_1 +* OUTPUT: dout_bar_1 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* inv1: 2 inv2: 4 +Xdff_r0_c0 ++ din_0 dout_0 dout_bar_0 clk vdd gnd ++ sram_2_16_1_freepdk45_dff_buf_0 +Xdff_r1_c0 ++ din_1 dout_1 dout_bar_1 clk vdd gnd ++ sram_2_16_1_freepdk45_dff_buf_0 +.ENDS sram_2_16_1_freepdk45_dff_buf_array + +.SUBCKT sram_2_16_1_freepdk45_pinv_3 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.09u l=0.05u pd=0.28u ps=0.28u as=0.01p ad=0.01p +.ENDS sram_2_16_1_freepdk45_pinv_3 + +* spice ptx M{0} {1} pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p + +* spice ptx M{0} {1} nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p + +* spice ptx M{0} {1} nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p + +.SUBCKT sram_2_16_1_freepdk45_pnand2_1 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_pmos2 Z B vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_nmos1 Z B net1 gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +Mpnand2_nmos2 net1 A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pnand2_1 + +* spice ptx M{0} {1} pmos_vtg m=2 w=0.675u l=0.05u pd=1.45u ps=1.45u as=0.08p ad=0.08p + +* spice ptx M{0} {1} nmos_vtg m=2 w=0.225u l=0.05u pd=0.55u ps=0.55u as=0.03p ad=0.03p + +.SUBCKT sram_2_16_1_freepdk45_pinv_7 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=2 w=0.675u l=0.05u pd=1.45u ps=1.45u as=0.08p ad=0.08p +Mpinv_nmos Z A gnd gnd nmos_vtg m=2 w=0.225u l=0.05u pd=0.55u ps=0.55u as=0.03p ad=0.03p +.ENDS sram_2_16_1_freepdk45_pinv_7 + +.SUBCKT sram_2_16_1_freepdk45_pinv_5 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.09u l=0.05u pd=0.28u ps=0.28u as=0.01p ad=0.01p +.ENDS sram_2_16_1_freepdk45_pinv_5 + +.SUBCKT sram_2_16_1_freepdk45_pdriver_1 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 5] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_freepdk45_pinv_5 +Xbuf_inv2 ++ Zb1_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_7 +.ENDS sram_2_16_1_freepdk45_pdriver_1 + +.SUBCKT sram_2_16_1_freepdk45_pnand2_0 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_pmos2 Z B vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_nmos1 Z B net1 gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +Mpnand2_nmos2 net1 A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pnand2_0 + +* spice ptx M{0} {1} pmos_vtg m=4 w=0.81u l=0.05u pd=1.72u ps=1.72u as=0.10p ad=0.10p + +* spice ptx M{0} {1} nmos_vtg m=4 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p + +.SUBCKT sram_2_16_1_freepdk45_pinv_2 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=4 w=0.81u l=0.05u pd=1.72u ps=1.72u as=0.10p ad=0.10p +Mpinv_nmos Z A gnd gnd nmos_vtg m=4 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +.ENDS sram_2_16_1_freepdk45_pinv_2 + +.SUBCKT sram_2_16_1_freepdk45_pdriver ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [12] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_2 +.ENDS sram_2_16_1_freepdk45_pdriver + +.SUBCKT sram_2_16_1_freepdk45_pand2 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand2_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand2_0 +Xpand2_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pdriver +.ENDS sram_2_16_1_freepdk45_pand2 + +* spice ptx M{0} {1} pmos_vtg m=5 w=0.81u l=0.05u pd=1.72u ps=1.72u as=0.10p ad=0.10p + +* spice ptx M{0} {1} nmos_vtg m=5 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p + +.SUBCKT sram_2_16_1_freepdk45_pinv_8 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=5 w=0.81u l=0.05u pd=1.72u ps=1.72u as=0.10p ad=0.10p +Mpinv_nmos Z A gnd gnd nmos_vtg m=5 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +.ENDS sram_2_16_1_freepdk45_pinv_8 + +.SUBCKT sram_2_16_1_freepdk45_pinv_6 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.54u l=0.05u pd=1.18u ps=1.18u as=0.07p ad=0.07p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pinv_6 + +.SUBCKT sram_2_16_1_freepdk45_pdriver_0 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 2, 5, 15] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_freepdk45_pinv_5 +Xbuf_inv2 ++ Zb1_int Zb2_int vdd gnd ++ sram_2_16_1_freepdk45_pinv_6 +Xbuf_inv3 ++ Zb2_int Zb3_int vdd gnd ++ sram_2_16_1_freepdk45_pinv_7 +Xbuf_inv4 ++ Zb3_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_8 +.ENDS sram_2_16_1_freepdk45_pdriver_0 + +.SUBCKT sram_2_16_1_freepdk45_pdriver_4 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 1] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_freepdk45_pinv_5 +Xbuf_inv2 ++ Zb1_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_5 +.ENDS sram_2_16_1_freepdk45_pdriver_4 + +.SUBCKT sram_2_16_1_freepdk45_pdriver_3 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [2] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_6 +.ENDS sram_2_16_1_freepdk45_pdriver_3 + +* spice ptx M{0} {1} nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p + +.SUBCKT sram_2_16_1_freepdk45_pnand3_0 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand3_pmos1 vdd A Z vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand3_pmos2 Z B vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand3_pmos3 Z C vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand3_nmos1 Z C net1 gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +Mpnand3_nmos2 net1 B net2 gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +Mpnand3_nmos3 net2 A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pnand3_0 + +.SUBCKT sram_2_16_1_freepdk45_pand3_0 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand3_nand ++ A B C zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand3_0 +Xpand3_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pdriver_3 +.ENDS sram_2_16_1_freepdk45_pand3_0 + +* spice ptx M{0} {1} pmos_vtg m=3 w=0.9u l=0.05u pd=1.90u ps=1.90u as=0.11p ad=0.11p + +* spice ptx M{0} {1} nmos_vtg m=3 w=0.3u l=0.05u pd=0.70u ps=0.70u as=0.04p ad=0.04p + +.SUBCKT sram_2_16_1_freepdk45_pinv_9 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=3 w=0.9u l=0.05u pd=1.90u ps=1.90u as=0.11p ad=0.11p +Mpinv_nmos Z A gnd gnd nmos_vtg m=3 w=0.3u l=0.05u pd=0.70u ps=0.70u as=0.04p ad=0.04p +.ENDS sram_2_16_1_freepdk45_pinv_9 + +.SUBCKT sram_2_16_1_freepdk45_pdriver_2 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [10] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_freepdk45_pinv_9 +.ENDS sram_2_16_1_freepdk45_pdriver_2 + +.SUBCKT sram_2_16_1_freepdk45_pand3 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand3_nand ++ A B C zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand3_0 +Xpand3_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pdriver_2 +.ENDS sram_2_16_1_freepdk45_pand3 + +.SUBCKT sram_2_16_1_freepdk45_control_logic_rw ++ csb web clk rbl_bl s_en w_en p_en_bar wl_en clk_buf vdd gnd +* INPUT : csb +* INPUT : web +* INPUT : clk +* INPUT : rbl_bl +* OUTPUT: s_en +* OUTPUT: w_en +* OUTPUT: p_en_bar +* OUTPUT: wl_en +* OUTPUT: clk_buf +* POWER : vdd +* GROUND: gnd +* word_size 2 +Xctrl_dffs ++ csb web cs_bar cs we_bar we clk_buf vdd gnd ++ sram_2_16_1_freepdk45_dff_buf_array +Xclkbuf ++ clk clk_buf vdd gnd ++ sram_2_16_1_freepdk45_pdriver_0 +Xinv_clk_bar ++ clk_buf clk_bar vdd gnd ++ sram_2_16_1_freepdk45_pinv_3 +Xand2_gated_clk_bar ++ clk_bar cs gated_clk_bar vdd gnd ++ sram_2_16_1_freepdk45_pand2 +Xand2_gated_clk_buf ++ clk_buf cs gated_clk_buf vdd gnd ++ sram_2_16_1_freepdk45_pand2 +Xbuf_wl_en ++ gated_clk_bar wl_en vdd gnd ++ sram_2_16_1_freepdk45_pdriver_1 +Xrbl_bl_delay_inv ++ rbl_bl_delay rbl_bl_delay_bar vdd gnd ++ sram_2_16_1_freepdk45_pinv_3 +Xw_en_and ++ we rbl_bl_delay_bar gated_clk_bar w_en vdd gnd ++ sram_2_16_1_freepdk45_pand3 +Xbuf_s_en_and ++ rbl_bl_delay gated_clk_bar we_bar s_en vdd gnd ++ sram_2_16_1_freepdk45_pand3_0 +Xdelay_chain ++ rbl_bl rbl_bl_delay vdd gnd ++ sram_2_16_1_freepdk45_delay_chain +Xnand_p_en_bar ++ gated_clk_buf rbl_bl_delay p_en_bar_unbuf vdd gnd ++ sram_2_16_1_freepdk45_pnand2_1 +Xbuf_p_en_bar ++ p_en_bar_unbuf p_en_bar vdd gnd ++ sram_2_16_1_freepdk45_pdriver_4 +.ENDS sram_2_16_1_freepdk45_control_logic_rw + +.SUBCKT sram_2_16_1_freepdk45_row_addr_dff ++ din_0 din_1 din_2 din_3 dout_0 dout_1 dout_2 dout_3 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* INPUT : din_2 +* INPUT : din_3 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* OUTPUT: dout_2 +* OUTPUT: dout_3 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* rows: 4 cols: 1 +Xdff_r0_c0 ++ din_0 dout_0 clk vdd gnd ++ dff +Xdff_r1_c0 ++ din_1 dout_1 clk vdd gnd ++ dff +Xdff_r2_c0 ++ din_2 dout_2 clk vdd gnd ++ dff +Xdff_r3_c0 ++ din_3 dout_3 clk vdd gnd ++ dff +.ENDS sram_2_16_1_freepdk45_row_addr_dff + +.SUBCKT sram_2_16_1_freepdk45_pnand2 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_pmos2 Z B vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpnand2_nmos1 Z B net1 gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +Mpnand2_nmos2 net1 A gnd gnd nmos_vtg m=1 w=0.18u l=0.05u pd=0.46u ps=0.46u as=0.02p ad=0.02p +.ENDS sram_2_16_1_freepdk45_pnand2 + +.SUBCKT sram_2_16_1_freepdk45_pinv ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mpinv_nmos Z A gnd gnd nmos_vtg m=1 w=0.09u l=0.05u pd=0.28u ps=0.28u as=0.01p ad=0.01p +.ENDS sram_2_16_1_freepdk45_pinv + +.SUBCKT sram_2_16_1_freepdk45_and2_dec_0 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* size: 1 +Xpand2_dec_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand2 +Xpand2_dec_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv +.ENDS sram_2_16_1_freepdk45_and2_dec_0 + +.SUBCKT sram_2_16_1_freepdk45_and2_dec ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* size: 1 +Xpand2_dec_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand2 +Xpand2_dec_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv +.ENDS sram_2_16_1_freepdk45_and2_dec + +.SUBCKT sram_2_16_1_freepdk45_hierarchical_predecode2x4 ++ in_0 in_1 out_0 out_1 out_2 out_3 vdd gnd +* INPUT : in_0 +* INPUT : in_1 +* OUTPUT: out_0 +* OUTPUT: out_1 +* OUTPUT: out_2 +* OUTPUT: out_3 +* POWER : vdd +* GROUND: gnd +Xpre_inv_0 ++ in_0 inbar_0 vdd gnd ++ sram_2_16_1_freepdk45_pinv +Xpre_inv_1 ++ in_1 inbar_1 vdd gnd ++ sram_2_16_1_freepdk45_pinv +XXpre2x4_and_0 ++ inbar_0 inbar_1 out_0 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XXpre2x4_and_1 ++ in_0 inbar_1 out_1 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XXpre2x4_and_2 ++ inbar_0 in_1 out_2 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XXpre2x4_and_3 ++ in_0 in_1 out_3 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +.ENDS sram_2_16_1_freepdk45_hierarchical_predecode2x4 + +.SUBCKT sram_2_16_1_freepdk45_hierarchical_decoder ++ addr_0 addr_1 addr_2 addr_3 decode_0 decode_1 decode_2 decode_3 ++ decode_4 decode_5 decode_6 decode_7 decode_8 decode_9 decode_10 ++ decode_11 decode_12 decode_13 decode_14 decode_15 vdd gnd +* INPUT : addr_0 +* INPUT : addr_1 +* INPUT : addr_2 +* INPUT : addr_3 +* OUTPUT: decode_0 +* OUTPUT: decode_1 +* OUTPUT: decode_2 +* OUTPUT: decode_3 +* OUTPUT: decode_4 +* OUTPUT: decode_5 +* OUTPUT: decode_6 +* OUTPUT: decode_7 +* OUTPUT: decode_8 +* OUTPUT: decode_9 +* OUTPUT: decode_10 +* OUTPUT: decode_11 +* OUTPUT: decode_12 +* OUTPUT: decode_13 +* OUTPUT: decode_14 +* OUTPUT: decode_15 +* POWER : vdd +* GROUND: gnd +Xpre_0 ++ addr_0 addr_1 out_0 out_1 out_2 out_3 vdd gnd ++ sram_2_16_1_freepdk45_hierarchical_predecode2x4 +Xpre_1 ++ addr_2 addr_3 out_4 out_5 out_6 out_7 vdd gnd ++ sram_2_16_1_freepdk45_hierarchical_predecode2x4 +XDEC_AND_0 ++ out_0 out_4 decode_0 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_4 ++ out_0 out_5 decode_4 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_8 ++ out_0 out_6 decode_8 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_12 ++ out_0 out_7 decode_12 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_1 ++ out_1 out_4 decode_1 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_5 ++ out_1 out_5 decode_5 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_9 ++ out_1 out_6 decode_9 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_13 ++ out_1 out_7 decode_13 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_2 ++ out_2 out_4 decode_2 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_6 ++ out_2 out_5 decode_6 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_10 ++ out_2 out_6 decode_10 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_14 ++ out_2 out_7 decode_14 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_3 ++ out_3 out_4 decode_3 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_7 ++ out_3 out_5 decode_7 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_11 ++ out_3 out_6 decode_11 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +XDEC_AND_15 ++ out_3 out_7 decode_15 vdd gnd ++ sram_2_16_1_freepdk45_and2_dec +.ENDS sram_2_16_1_freepdk45_hierarchical_decoder + +.SUBCKT sram_2_16_1_freepdk45_wordline_driver ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xwld_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_freepdk45_pnand2 +Xwl_driver ++ zb_int Z vdd gnd ++ sram_2_16_1_freepdk45_pinv +.ENDS sram_2_16_1_freepdk45_wordline_driver + +.SUBCKT sram_2_16_1_freepdk45_wordline_driver_array ++ in_0 in_1 in_2 in_3 in_4 in_5 in_6 in_7 in_8 in_9 in_10 in_11 in_12 ++ in_13 in_14 in_15 wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 wl_7 wl_8 wl_9 ++ wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 en vdd gnd +* INPUT : in_0 +* INPUT : in_1 +* INPUT : in_2 +* INPUT : in_3 +* INPUT : in_4 +* INPUT : in_5 +* INPUT : in_6 +* INPUT : in_7 +* INPUT : in_8 +* INPUT : in_9 +* INPUT : in_10 +* INPUT : in_11 +* INPUT : in_12 +* INPUT : in_13 +* INPUT : in_14 +* INPUT : in_15 +* OUTPUT: wl_0 +* OUTPUT: wl_1 +* OUTPUT: wl_2 +* OUTPUT: wl_3 +* OUTPUT: wl_4 +* OUTPUT: wl_5 +* OUTPUT: wl_6 +* OUTPUT: wl_7 +* OUTPUT: wl_8 +* OUTPUT: wl_9 +* OUTPUT: wl_10 +* OUTPUT: wl_11 +* OUTPUT: wl_12 +* OUTPUT: wl_13 +* OUTPUT: wl_14 +* OUTPUT: wl_15 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* rows: 16 cols: 2 +Xwl_driver_and0 ++ in_0 en wl_0 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and1 ++ in_1 en wl_1 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and2 ++ in_2 en wl_2 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and3 ++ in_3 en wl_3 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and4 ++ in_4 en wl_4 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and5 ++ in_5 en wl_5 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and6 ++ in_6 en wl_6 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and7 ++ in_7 en wl_7 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and8 ++ in_8 en wl_8 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and9 ++ in_9 en wl_9 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and10 ++ in_10 en wl_10 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and11 ++ in_11 en wl_11 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and12 ++ in_12 en wl_12 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and13 ++ in_13 en wl_13 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and14 ++ in_14 en wl_14 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +Xwl_driver_and15 ++ in_15 en wl_15 vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver +.ENDS sram_2_16_1_freepdk45_wordline_driver_array + +.SUBCKT sram_2_16_1_freepdk45_port_address ++ addr_0 addr_1 addr_2 addr_3 wl_en wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 ++ wl_7 wl_8 wl_9 wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 rbl_wl vdd gnd +* INPUT : addr_0 +* INPUT : addr_1 +* INPUT : addr_2 +* INPUT : addr_3 +* INPUT : wl_en +* OUTPUT: wl_0 +* OUTPUT: wl_1 +* OUTPUT: wl_2 +* OUTPUT: wl_3 +* OUTPUT: wl_4 +* OUTPUT: wl_5 +* OUTPUT: wl_6 +* OUTPUT: wl_7 +* OUTPUT: wl_8 +* OUTPUT: wl_9 +* OUTPUT: wl_10 +* OUTPUT: wl_11 +* OUTPUT: wl_12 +* OUTPUT: wl_13 +* OUTPUT: wl_14 +* OUTPUT: wl_15 +* OUTPUT: rbl_wl +* POWER : vdd +* GROUND: gnd +Xrow_decoder ++ addr_0 addr_1 addr_2 addr_3 dec_out_0 dec_out_1 dec_out_2 dec_out_3 ++ dec_out_4 dec_out_5 dec_out_6 dec_out_7 dec_out_8 dec_out_9 dec_out_10 ++ dec_out_11 dec_out_12 dec_out_13 dec_out_14 dec_out_15 vdd gnd ++ sram_2_16_1_freepdk45_hierarchical_decoder +Xwordline_driver ++ dec_out_0 dec_out_1 dec_out_2 dec_out_3 dec_out_4 dec_out_5 dec_out_6 ++ dec_out_7 dec_out_8 dec_out_9 dec_out_10 dec_out_11 dec_out_12 ++ dec_out_13 dec_out_14 dec_out_15 wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 ++ wl_7 wl_8 wl_9 wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 wl_en vdd gnd ++ sram_2_16_1_freepdk45_wordline_driver_array +Xrbl_driver ++ wl_en vdd rbl_wl vdd gnd ++ sram_2_16_1_freepdk45_and2_dec_0 +.ENDS sram_2_16_1_freepdk45_port_address + +.SUBCKT write_driver din bl br en vdd gnd +*inverters for enable and data input +minP bl_bar din vdd vdd pmos_vtg w=360.000000n l=50.000000n +minN bl_bar din gnd gnd nmos_vtg w=180.000000n l=50.000000n +moutP en_bar en vdd vdd pmos_vtg w=360.000000n l=50.000000n +moutN en_bar en gnd gnd nmos_vtg w=180.000000n l=50.000000n + +*tristate for BL +mout0P int1 bl_bar vdd vdd pmos_vtg w=360.000000n l=50.000000n +mout0P2 bl en_bar int1 vdd pmos_vtg w=360.000000n l=50.000000n +mout0N bl en int2 gnd nmos_vtg w=180.000000n l=50.000000n +mout0N2 int2 bl_bar gnd gnd nmos_vtg w=180.000000n l=50.000000n + +*tristate for BR +mout1P int3 din vdd vdd pmos_vtg w=360.000000n l=50.000000n +mout1P2 br en_bar int3 vdd pmos_vtg w=360.000000n l=50.000000n +mout1N br en int4 gnd nmos_vtg w=180.000000n l=50.000000n +mout1N2 int4 din gnd gnd nmos_vtg w=180.000000n l=50.000000n +.ENDS write_driver + + +.SUBCKT sram_2_16_1_freepdk45_write_driver_array ++ data_0 data_1 bl_0 br_0 bl_1 br_1 en vdd gnd +* INPUT : data_0 +* INPUT : data_1 +* OUTPUT: bl_0 +* OUTPUT: br_0 +* OUTPUT: bl_1 +* OUTPUT: br_1 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* word_size 2 +Xwrite_driver0 ++ data_0 bl_0 br_0 en vdd gnd ++ write_driver +Xwrite_driver1 ++ data_1 bl_1 br_1 en vdd gnd ++ write_driver +.ENDS sram_2_16_1_freepdk45_write_driver_array + +.SUBCKT sense_amp bl br dout en vdd gnd +M_1 dint net_1 vdd vdd pmos_vtg w=540.0n l=50.0n +M_3 net_1 dint vdd vdd pmos_vtg w=540.0n l=50.0n +M_2 dint net_1 net_2 gnd nmos_vtg w=270.0n l=50.0n +M_8 net_1 dint net_2 gnd nmos_vtg w=270.0n l=50.0n +M_5 bl en dint vdd pmos_vtg w=720.0n l=50.0n +M_6 br en net_1 vdd pmos_vtg w=720.0n l=50.0n +M_7 net_2 en gnd gnd nmos_vtg w=270.0n l=50.0n + +M_9 dout_bar dint vdd vdd pmos_vtg w=180.0n l=50.0n +M_10 dout_bar dint gnd gnd nmos_vtg w=90.0n l=50.0n +M_11 dout dout_bar vdd vdd pmos_vtg w=540.0n l=50.0n +M_12 dout dout_bar gnd gnd nmos_vtg w=270.0n l=50.0n +.ENDS sense_amp + + +.SUBCKT sram_2_16_1_freepdk45_sense_amp_array ++ data_0 bl_0 br_0 data_1 bl_1 br_1 en vdd gnd +* OUTPUT: data_0 +* INPUT : bl_0 +* INPUT : br_0 +* OUTPUT: data_1 +* INPUT : bl_1 +* INPUT : br_1 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* words_per_row: 1 +Xsa_d0 ++ bl_0 br_0 data_0 en vdd gnd ++ sense_amp +Xsa_d1 ++ bl_1 br_1 data_1 en vdd gnd ++ sense_amp +.ENDS sram_2_16_1_freepdk45_sense_amp_array + +.SUBCKT sram_2_16_1_freepdk45_precharge_0 ++ bl br en_bar vdd +* OUTPUT: bl +* OUTPUT: br +* INPUT : en_bar +* POWER : vdd +Mlower_pmos bl en_bar br vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mupper_pmos1 bl en_bar vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +Mupper_pmos2 br en_bar vdd vdd pmos_vtg m=1 w=0.27u l=0.05u pd=0.64u ps=0.64u as=0.03p ad=0.03p +.ENDS sram_2_16_1_freepdk45_precharge_0 + +.SUBCKT sram_2_16_1_freepdk45_precharge_array ++ bl_0 br_0 bl_1 br_1 bl_2 br_2 en_bar vdd +* OUTPUT: bl_0 +* OUTPUT: br_0 +* OUTPUT: bl_1 +* OUTPUT: br_1 +* OUTPUT: bl_2 +* OUTPUT: br_2 +* INPUT : en_bar +* POWER : vdd +* cols: 3 size: 1 bl: bl br: br +Xpre_column_0 ++ bl_0 br_0 en_bar vdd ++ sram_2_16_1_freepdk45_precharge_0 +Xpre_column_1 ++ bl_1 br_1 en_bar vdd ++ sram_2_16_1_freepdk45_precharge_0 +Xpre_column_2 ++ bl_2 br_2 en_bar vdd ++ sram_2_16_1_freepdk45_precharge_0 +.ENDS sram_2_16_1_freepdk45_precharge_array + +.SUBCKT sram_2_16_1_freepdk45_port_data ++ rbl_bl rbl_br bl_0 br_0 bl_1 br_1 dout_0 dout_1 din_0 din_1 s_en ++ p_en_bar w_en vdd gnd +* INOUT : rbl_bl +* INOUT : rbl_br +* INOUT : bl_0 +* INOUT : br_0 +* INOUT : bl_1 +* INOUT : br_1 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* INPUT : din_0 +* INPUT : din_1 +* INPUT : s_en +* INPUT : p_en_bar +* INPUT : w_en +* POWER : vdd +* GROUND: gnd +Xprecharge_array0 ++ rbl_bl rbl_br bl_0 br_0 bl_1 br_1 p_en_bar vdd ++ sram_2_16_1_freepdk45_precharge_array +Xsense_amp_array0 ++ dout_0 bl_0 br_0 dout_1 bl_1 br_1 s_en vdd gnd ++ sram_2_16_1_freepdk45_sense_amp_array +Xwrite_driver_array0 ++ din_0 din_1 bl_0 br_0 bl_1 br_1 w_en vdd gnd ++ sram_2_16_1_freepdk45_write_driver_array +.ENDS sram_2_16_1_freepdk45_port_data + +.SUBCKT dummy_cell_1rw bl br wl vdd gnd +* Inverter 1 +MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n +MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n + +* Inverer 2 +MM1 Q Q_bar gnd gnd NMOS_VTG W=205.00n L=50n +MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n + +* Access transistors +MM3 bl_noconn wl Q gnd NMOS_VTG W=135.00n L=50n +MM2 br_noconn wl Q_bar gnd NMOS_VTG W=135.00n L=50n +.ENDS dummy_cell_1rw + + +.SUBCKT sram_2_16_1_freepdk45_dummy_array_3 ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ wl_0_17 wl_0_18 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* INPUT : wl_0_17 +* INPUT : wl_0_18 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ dummy_cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ dummy_cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ dummy_cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ dummy_cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ dummy_cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ dummy_cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ dummy_cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ dummy_cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ dummy_cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ dummy_cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ dummy_cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ dummy_cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ dummy_cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ dummy_cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ dummy_cell_1rw +Xbit_r16_c0 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ dummy_cell_1rw +Xbit_r17_c0 ++ bl_0_0 br_0_0 wl_0_17 vdd gnd ++ dummy_cell_1rw +Xbit_r18_c0 ++ bl_0_0 br_0_0 wl_0_18 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_freepdk45_dummy_array_3 + +.SUBCKT cell_1rw bl br wl vdd gnd +* Inverter 1 +MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n +MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n + +* Inverer 2 +MM1 Q Q_bar gnd gnd NMOS_VTG W=205.00n L=50n +MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n + +* Access transistors +MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n +MM2 br wl Q_bar gnd NMOS_VTG W=135.00n L=50n +.ENDS cell_1rw + + +.SUBCKT sram_2_16_1_freepdk45_bitcell_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 ++ wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 ++ wl_0_15 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rows: 16 cols: 2 +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ cell_1rw +Xbit_r1_c1 ++ bl_0_1 br_0_1 wl_0_1 vdd gnd ++ cell_1rw +Xbit_r2_c1 ++ bl_0_1 br_0_1 wl_0_2 vdd gnd ++ cell_1rw +Xbit_r3_c1 ++ bl_0_1 br_0_1 wl_0_3 vdd gnd ++ cell_1rw +Xbit_r4_c1 ++ bl_0_1 br_0_1 wl_0_4 vdd gnd ++ cell_1rw +Xbit_r5_c1 ++ bl_0_1 br_0_1 wl_0_5 vdd gnd ++ cell_1rw +Xbit_r6_c1 ++ bl_0_1 br_0_1 wl_0_6 vdd gnd ++ cell_1rw +Xbit_r7_c1 ++ bl_0_1 br_0_1 wl_0_7 vdd gnd ++ cell_1rw +Xbit_r8_c1 ++ bl_0_1 br_0_1 wl_0_8 vdd gnd ++ cell_1rw +Xbit_r9_c1 ++ bl_0_1 br_0_1 wl_0_9 vdd gnd ++ cell_1rw +Xbit_r10_c1 ++ bl_0_1 br_0_1 wl_0_10 vdd gnd ++ cell_1rw +Xbit_r11_c1 ++ bl_0_1 br_0_1 wl_0_11 vdd gnd ++ cell_1rw +Xbit_r12_c1 ++ bl_0_1 br_0_1 wl_0_12 vdd gnd ++ cell_1rw +Xbit_r13_c1 ++ bl_0_1 br_0_1 wl_0_13 vdd gnd ++ cell_1rw +Xbit_r14_c1 ++ bl_0_1 br_0_1 wl_0_14 vdd gnd ++ cell_1rw +Xbit_r15_c1 ++ bl_0_1 br_0_1 wl_0_15 vdd gnd ++ cell_1rw +.ENDS sram_2_16_1_freepdk45_bitcell_array + +.SUBCKT sram_2_16_1_freepdk45_dummy_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_freepdk45_dummy_array + +.SUBCKT replica_cell_1rw bl br wl vdd gnd +* Inverter 1 +MM0 vdd Q gnd gnd NMOS_VTG W=205.00n L=50n +MM4 vdd Q vdd vdd PMOS_VTG W=90n L=50n + +* Inverer 2 +MM1 Q vdd gnd gnd NMOS_VTG W=205.00n L=50n +MM5 Q vdd vdd vdd PMOS_VTG W=90n L=50n + +* Access transistors +MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n +MM2 br wl vdd gnd NMOS_VTG W=135.00n L=50n +.ENDS cell_1rw + + +.SUBCKT sram_2_16_1_freepdk45_replica_column ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ vdd gnd +* OUTPUT: bl_0_0 +* OUTPUT: br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* POWER : vdd +* GROUND: gnd +Xrbc_0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ replica_cell_1rw +Xrbc_1 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ replica_cell_1rw +Xrbc_2 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ replica_cell_1rw +Xrbc_3 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ replica_cell_1rw +Xrbc_4 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ replica_cell_1rw +Xrbc_5 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ replica_cell_1rw +Xrbc_6 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ replica_cell_1rw +Xrbc_7 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ replica_cell_1rw +Xrbc_8 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ replica_cell_1rw +Xrbc_9 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ replica_cell_1rw +Xrbc_10 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ replica_cell_1rw +Xrbc_11 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ replica_cell_1rw +Xrbc_12 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ replica_cell_1rw +Xrbc_13 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ replica_cell_1rw +Xrbc_14 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ replica_cell_1rw +Xrbc_15 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ replica_cell_1rw +Xrbc_16 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ replica_cell_1rw +.ENDS sram_2_16_1_freepdk45_replica_column + +.SUBCKT sram_2_16_1_freepdk45_replica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd +* INOUT : rbl_bl_0_0 +* INOUT : rbl_br_0_0 +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : rbl_wl_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rbl: [1, 0] left_rbl: [0] right_rbl: [] +Xbitcell_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 ++ wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 ++ wl_0_15 vdd gnd ++ sram_2_16_1_freepdk45_bitcell_array +Xreplica_col_0 ++ rbl_bl_0_0 rbl_br_0_0 rbl_wl_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 ++ wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 ++ wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_freepdk45_replica_column +Xdummy_row_0 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 vdd gnd ++ sram_2_16_1_freepdk45_dummy_array +.ENDS sram_2_16_1_freepdk45_replica_bitcell_array + +.SUBCKT sram_2_16_1_freepdk45_dummy_array_1 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 bl_0_2 br_0_2 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INOUT : bl_0_2 +* INOUT : br_0_2 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c2 ++ bl_0_2 br_0_2 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_freepdk45_dummy_array_1 + +.SUBCKT sram_2_16_1_freepdk45_dummy_array_0 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 bl_0_2 br_0_2 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INOUT : bl_0_2 +* INOUT : br_0_2 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c2 ++ bl_0_2 br_0_2 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_freepdk45_dummy_array_0 + +.SUBCKT sram_2_16_1_freepdk45_dummy_array_2 ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ wl_0_17 wl_0_18 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* INPUT : wl_0_17 +* INPUT : wl_0_18 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ dummy_cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ dummy_cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ dummy_cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ dummy_cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ dummy_cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ dummy_cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ dummy_cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ dummy_cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ dummy_cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ dummy_cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ dummy_cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ dummy_cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ dummy_cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ dummy_cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ dummy_cell_1rw +Xbit_r16_c0 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ dummy_cell_1rw +Xbit_r17_c0 ++ bl_0_0 br_0_0 wl_0_17 vdd gnd ++ dummy_cell_1rw +Xbit_r18_c0 ++ bl_0_0 br_0_0 wl_0_18 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_freepdk45_dummy_array_2 + +.SUBCKT sram_2_16_1_freepdk45_capped_replica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd +* INOUT : rbl_bl_0_0 +* INOUT : rbl_br_0_0 +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : rbl_wl_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rbl: [1, 0] left_rbl: [0] right_rbl: [] +Xreplica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_freepdk45_replica_bitcell_array +Xdummy_row_bot ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 gnd vdd gnd ++ sram_2_16_1_freepdk45_dummy_array_1 +Xdummy_row_top ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 gnd vdd gnd ++ sram_2_16_1_freepdk45_dummy_array_0 +Xdummy_col_left ++ dummy_left_bl_0_0 dummy_left_br_0_0 gnd rbl_wl_0_0 wl_0_0 wl_0_1 ++ wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 gnd vdd gnd ++ sram_2_16_1_freepdk45_dummy_array_2 +Xdummy_col_right ++ dummy_right_bl_0_0 dummy_right_br_0_0 gnd rbl_wl_0_0 wl_0_0 wl_0_1 ++ wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 gnd vdd gnd ++ sram_2_16_1_freepdk45_dummy_array_3 +.ENDS sram_2_16_1_freepdk45_capped_replica_bitcell_array + +.SUBCKT sram_2_16_1_freepdk45_bank ++ dout0_0 dout0_1 rbl_bl_0_0 din0_0 din0_1 addr0_0 addr0_1 addr0_2 ++ addr0_3 s_en0 p_en_bar0 w_en0 wl_en0 vdd gnd +* OUTPUT: dout0_0 +* OUTPUT: dout0_1 +* OUTPUT: rbl_bl_0_0 +* INPUT : din0_0 +* INPUT : din0_1 +* INPUT : addr0_0 +* INPUT : addr0_1 +* INPUT : addr0_2 +* INPUT : addr0_3 +* INPUT : s_en0 +* INPUT : p_en_bar0 +* INPUT : w_en0 +* INPUT : wl_en0 +* POWER : vdd +* GROUND: gnd +Xbitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_freepdk45_capped_replica_bitcell_array +Xport_data0 ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 dout0_0 dout0_1 ++ din0_0 din0_1 s_en0 p_en_bar0 w_en0 vdd gnd ++ sram_2_16_1_freepdk45_port_data +Xport_address0 ++ addr0_0 addr0_1 addr0_2 addr0_3 wl_en0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 ++ wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 ++ wl_0_13 wl_0_14 wl_0_15 rbl_wl0 vdd gnd ++ sram_2_16_1_freepdk45_port_address +.ENDS sram_2_16_1_freepdk45_bank + +.SUBCKT sram_2_16_1_freepdk45 ++ din0[0] din0[1] addr0[0] addr0[1] addr0[2] addr0[3] csb0 web0 clk0 ++ dout0[0] dout0[1] vdd gnd +* INPUT : din0[0] +* INPUT : din0[1] +* INPUT : addr0[0] +* INPUT : addr0[1] +* INPUT : addr0[2] +* INPUT : addr0[3] +* INPUT : csb0 +* INPUT : web0 +* INPUT : clk0 +* OUTPUT: dout0[0] +* OUTPUT: dout0[1] +* POWER : vdd +* GROUND: gnd +Xbank0 ++ dout0[0] dout0[1] rbl_bl0 bank_din0_0 bank_din0_1 a0_0 a0_1 a0_2 a0_3 ++ s_en0 p_en_bar0 w_en0 wl_en0 vdd gnd ++ sram_2_16_1_freepdk45_bank +Xcontrol0 ++ csb0 web0 clk0 rbl_bl0 s_en0 w_en0 p_en_bar0 wl_en0 clk_buf0 vdd gnd ++ sram_2_16_1_freepdk45_control_logic_rw +Xrow_address0 ++ addr0[0] addr0[1] addr0[2] addr0[3] a0_0 a0_1 a0_2 a0_3 clk_buf0 vdd ++ gnd ++ sram_2_16_1_freepdk45_row_addr_dff +Xdata_dff0 ++ din0[0] din0[1] bank_din0_0 bank_din0_1 clk_buf0 vdd gnd ++ sram_2_16_1_freepdk45_data_dff +.ENDS sram_2_16_1_freepdk45 diff --git a/compiler/tests/sp_files/sram_2_16_1_scn4m_subm.sp b/compiler/tests/sp_files/sram_2_16_1_scn4m_subm.sp new file mode 100644 index 00000000..c6836a9d --- /dev/null +++ b/compiler/tests/sp_files/sram_2_16_1_scn4m_subm.sp @@ -0,0 +1,1758 @@ +************************************************** +* OpenRAM generated memory. +* Words: 16 +* Data bits: 2 +* Banks: 1 +* Column mux: 1:1 +* Trimmed: False +* LVS: False +************************************************** + +*********************** "cell_1rw" ****************************** +.SUBCKT replica_cell_1rw bl br wl vdd gnd +* SPICE3 file created from cell_1rw.ext - technology: scmos + +* Inverter 1 +M1000 Q vdd vdd vdd p w=0.6u l=0.8u +M1002 Q vdd gnd gnd n w=1.6u l=0.4u + +* Inverter 2 +M1001 vdd Q vdd vdd p w=0.6u l=0.8u +M1003 gnd Q vdd gnd n w=1.6u l=0.4u + +* Access transistors +M1004 Q wl bl gnd n w=0.8u l=0.4u +M1005 vdd wl br gnd n w=0.8u l=0.4u + +.ENDS + +.SUBCKT sram_2_16_1_scn4m_subm_replica_column ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ vdd gnd +* OUTPUT: bl_0_0 +* OUTPUT: br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* POWER : vdd +* GROUND: gnd +Xrbc_0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ replica_cell_1rw +Xrbc_1 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ replica_cell_1rw +Xrbc_2 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ replica_cell_1rw +Xrbc_3 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ replica_cell_1rw +Xrbc_4 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ replica_cell_1rw +Xrbc_5 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ replica_cell_1rw +Xrbc_6 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ replica_cell_1rw +Xrbc_7 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ replica_cell_1rw +Xrbc_8 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ replica_cell_1rw +Xrbc_9 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ replica_cell_1rw +Xrbc_10 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ replica_cell_1rw +Xrbc_11 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ replica_cell_1rw +Xrbc_12 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ replica_cell_1rw +Xrbc_13 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ replica_cell_1rw +Xrbc_14 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ replica_cell_1rw +Xrbc_15 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ replica_cell_1rw +Xrbc_16 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ replica_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_replica_column + +*********************** "cell_1rw" ****************************** +.SUBCKT cell_1rw bl br wl vdd gnd +* SPICE3 file created from cell_1rw.ext - technology: scmos + +* Inverter 1 +M1000 Q Q_bar vdd vdd p w=0.6u l=0.8u +M1002 Q Q_bar gnd gnd n w=1.6u l=0.4u + +* Inverter 2 +M1001 vdd Q Q_bar vdd p w=0.6u l=0.8u +M1003 gnd Q Q_bar gnd n w=1.6u l=0.4u + +* Access transistors +M1004 Q wl bl gnd n w=0.8u l=0.4u +M1005 Q_bar wl br gnd n w=0.8u l=0.4u + +.ENDS + +.SUBCKT sram_2_16_1_scn4m_subm_bitcell_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 ++ wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 ++ wl_0_15 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rows: 16 cols: 2 +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ cell_1rw +Xbit_r1_c1 ++ bl_0_1 br_0_1 wl_0_1 vdd gnd ++ cell_1rw +Xbit_r2_c1 ++ bl_0_1 br_0_1 wl_0_2 vdd gnd ++ cell_1rw +Xbit_r3_c1 ++ bl_0_1 br_0_1 wl_0_3 vdd gnd ++ cell_1rw +Xbit_r4_c1 ++ bl_0_1 br_0_1 wl_0_4 vdd gnd ++ cell_1rw +Xbit_r5_c1 ++ bl_0_1 br_0_1 wl_0_5 vdd gnd ++ cell_1rw +Xbit_r6_c1 ++ bl_0_1 br_0_1 wl_0_6 vdd gnd ++ cell_1rw +Xbit_r7_c1 ++ bl_0_1 br_0_1 wl_0_7 vdd gnd ++ cell_1rw +Xbit_r8_c1 ++ bl_0_1 br_0_1 wl_0_8 vdd gnd ++ cell_1rw +Xbit_r9_c1 ++ bl_0_1 br_0_1 wl_0_9 vdd gnd ++ cell_1rw +Xbit_r10_c1 ++ bl_0_1 br_0_1 wl_0_10 vdd gnd ++ cell_1rw +Xbit_r11_c1 ++ bl_0_1 br_0_1 wl_0_11 vdd gnd ++ cell_1rw +Xbit_r12_c1 ++ bl_0_1 br_0_1 wl_0_12 vdd gnd ++ cell_1rw +Xbit_r13_c1 ++ bl_0_1 br_0_1 wl_0_13 vdd gnd ++ cell_1rw +Xbit_r14_c1 ++ bl_0_1 br_0_1 wl_0_14 vdd gnd ++ cell_1rw +Xbit_r15_c1 ++ bl_0_1 br_0_1 wl_0_15 vdd gnd ++ cell_1rw +.ENDS sram_2_16_1_scn4m_subm_bitcell_array + +*********************** "dummy_cell_1rw" ****************************** +.SUBCKT dummy_cell_1rw bl br wl vdd gnd + +* Inverter 1 +M1000 Q Q_bar vdd vdd p w=0.6u l=0.8u +M1002 Q Q_bar gnd gnd n w=1.6u l=0.4u + +* Inverter 2 +M1001 vdd Q Q_bar vdd p w=0.6u l=0.8u +M1003 gnd Q Q_bar gnd n w=1.6u l=0.4u + +* Access transistors +M1004 Q wl bl_noconn gnd n w=0.8u l=0.4u +M1005 Q_bar wl br_noconn gnd n w=0.8u l=0.4u + +.ENDS + +.SUBCKT sram_2_16_1_scn4m_subm_dummy_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_dummy_array + +.SUBCKT sram_2_16_1_scn4m_subm_replica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd +* INOUT : rbl_bl_0_0 +* INOUT : rbl_br_0_0 +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : rbl_wl_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rbl: [1, 0] left_rbl: [0] right_rbl: [] +Xbitcell_array ++ bl_0_0 br_0_0 bl_0_1 br_0_1 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 ++ wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 ++ wl_0_15 vdd gnd ++ sram_2_16_1_scn4m_subm_bitcell_array +Xreplica_col_0 ++ rbl_bl_0_0 rbl_br_0_0 rbl_wl_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 ++ wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 ++ wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_scn4m_subm_replica_column +Xdummy_row_0 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 vdd gnd ++ sram_2_16_1_scn4m_subm_dummy_array +.ENDS sram_2_16_1_scn4m_subm_replica_bitcell_array + +.SUBCKT sram_2_16_1_scn4m_subm_dummy_array_2 ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ wl_0_17 wl_0_18 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* INPUT : wl_0_17 +* INPUT : wl_0_18 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ dummy_cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ dummy_cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ dummy_cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ dummy_cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ dummy_cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ dummy_cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ dummy_cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ dummy_cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ dummy_cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ dummy_cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ dummy_cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ dummy_cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ dummy_cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ dummy_cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ dummy_cell_1rw +Xbit_r16_c0 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ dummy_cell_1rw +Xbit_r17_c0 ++ bl_0_0 br_0_0 wl_0_17 vdd gnd ++ dummy_cell_1rw +Xbit_r18_c0 ++ bl_0_0 br_0_0 wl_0_18 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_dummy_array_2 + +.SUBCKT sram_2_16_1_scn4m_subm_dummy_array_0 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 bl_0_2 br_0_2 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INOUT : bl_0_2 +* INOUT : br_0_2 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c2 ++ bl_0_2 br_0_2 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_dummy_array_0 + +.SUBCKT sram_2_16_1_scn4m_subm_dummy_array_1 ++ bl_0_0 br_0_0 bl_0_1 br_0_1 bl_0_2 br_0_2 wl_0_0 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INOUT : bl_0_2 +* INOUT : br_0_2 +* INPUT : wl_0_0 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c1 ++ bl_0_1 br_0_1 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r0_c2 ++ bl_0_2 br_0_2 wl_0_0 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_dummy_array_1 + +.SUBCKT sram_2_16_1_scn4m_subm_dummy_array_3 ++ bl_0_0 br_0_0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 ++ wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 wl_0_16 ++ wl_0_17 wl_0_18 vdd gnd +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* INPUT : wl_0_16 +* INPUT : wl_0_17 +* INPUT : wl_0_18 +* POWER : vdd +* GROUND: gnd +Xbit_r0_c0 ++ bl_0_0 br_0_0 wl_0_0 vdd gnd ++ dummy_cell_1rw +Xbit_r1_c0 ++ bl_0_0 br_0_0 wl_0_1 vdd gnd ++ dummy_cell_1rw +Xbit_r2_c0 ++ bl_0_0 br_0_0 wl_0_2 vdd gnd ++ dummy_cell_1rw +Xbit_r3_c0 ++ bl_0_0 br_0_0 wl_0_3 vdd gnd ++ dummy_cell_1rw +Xbit_r4_c0 ++ bl_0_0 br_0_0 wl_0_4 vdd gnd ++ dummy_cell_1rw +Xbit_r5_c0 ++ bl_0_0 br_0_0 wl_0_5 vdd gnd ++ dummy_cell_1rw +Xbit_r6_c0 ++ bl_0_0 br_0_0 wl_0_6 vdd gnd ++ dummy_cell_1rw +Xbit_r7_c0 ++ bl_0_0 br_0_0 wl_0_7 vdd gnd ++ dummy_cell_1rw +Xbit_r8_c0 ++ bl_0_0 br_0_0 wl_0_8 vdd gnd ++ dummy_cell_1rw +Xbit_r9_c0 ++ bl_0_0 br_0_0 wl_0_9 vdd gnd ++ dummy_cell_1rw +Xbit_r10_c0 ++ bl_0_0 br_0_0 wl_0_10 vdd gnd ++ dummy_cell_1rw +Xbit_r11_c0 ++ bl_0_0 br_0_0 wl_0_11 vdd gnd ++ dummy_cell_1rw +Xbit_r12_c0 ++ bl_0_0 br_0_0 wl_0_12 vdd gnd ++ dummy_cell_1rw +Xbit_r13_c0 ++ bl_0_0 br_0_0 wl_0_13 vdd gnd ++ dummy_cell_1rw +Xbit_r14_c0 ++ bl_0_0 br_0_0 wl_0_14 vdd gnd ++ dummy_cell_1rw +Xbit_r15_c0 ++ bl_0_0 br_0_0 wl_0_15 vdd gnd ++ dummy_cell_1rw +Xbit_r16_c0 ++ bl_0_0 br_0_0 wl_0_16 vdd gnd ++ dummy_cell_1rw +Xbit_r17_c0 ++ bl_0_0 br_0_0 wl_0_17 vdd gnd ++ dummy_cell_1rw +Xbit_r18_c0 ++ bl_0_0 br_0_0 wl_0_18 vdd gnd ++ dummy_cell_1rw +.ENDS sram_2_16_1_scn4m_subm_dummy_array_3 + +.SUBCKT sram_2_16_1_scn4m_subm_capped_replica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd +* INOUT : rbl_bl_0_0 +* INOUT : rbl_br_0_0 +* INOUT : bl_0_0 +* INOUT : br_0_0 +* INOUT : bl_0_1 +* INOUT : br_0_1 +* INPUT : rbl_wl_0_0 +* INPUT : wl_0_0 +* INPUT : wl_0_1 +* INPUT : wl_0_2 +* INPUT : wl_0_3 +* INPUT : wl_0_4 +* INPUT : wl_0_5 +* INPUT : wl_0_6 +* INPUT : wl_0_7 +* INPUT : wl_0_8 +* INPUT : wl_0_9 +* INPUT : wl_0_10 +* INPUT : wl_0_11 +* INPUT : wl_0_12 +* INPUT : wl_0_13 +* INPUT : wl_0_14 +* INPUT : wl_0_15 +* POWER : vdd +* GROUND: gnd +* rbl: [1, 0] left_rbl: [0] right_rbl: [] +Xreplica_bitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl_0_0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_scn4m_subm_replica_bitcell_array +Xdummy_row_bot ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 gnd vdd gnd ++ sram_2_16_1_scn4m_subm_dummy_array_1 +Xdummy_row_top ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 gnd vdd gnd ++ sram_2_16_1_scn4m_subm_dummy_array_0 +Xdummy_col_left ++ dummy_left_bl_0_0 dummy_left_br_0_0 gnd rbl_wl_0_0 wl_0_0 wl_0_1 ++ wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 gnd vdd gnd ++ sram_2_16_1_scn4m_subm_dummy_array_2 +Xdummy_col_right ++ dummy_right_bl_0_0 dummy_right_br_0_0 gnd rbl_wl_0_0 wl_0_0 wl_0_1 ++ wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 gnd vdd gnd ++ sram_2_16_1_scn4m_subm_dummy_array_3 +.ENDS sram_2_16_1_scn4m_subm_capped_replica_bitcell_array +*********************** "sense_amp" ****************************** + +.SUBCKT sense_amp bl br dout en vdd gnd + +* SPICE3 file created from sense_amp.ext - technology: scmos + +M1000 gnd en a_56_432# gnd n w=1.8u l=0.4u +M1001 a_56_432# a_48_304# dint gnd n w=1.8u l=0.4u +M1002 a_48_304# dint a_56_432# gnd n w=1.8u l=0.4u +M1003 vdd a_48_304# dint vdd p w=3.6u l=0.4u +M1004 a_48_304# dint vdd vdd p w=3.6u l=0.4u +M1005 bl en dint vdd p w=4.8u l=0.4u +M1006 a_48_304# en br vdd p w=4.8u l=0.4u + +M1007 dout_bar dint vdd vdd p w=1.6u l=0.4u +M1008 gnd dint dout_bar gnd n w=0.8u l=0.4u +M1009 dout dout_bar vdd vdd p w=4.8u l=0.4u +M1010 gnd dout_bar dout gnd n w=2.4u l=0.4u +.ENDS + +.SUBCKT sram_2_16_1_scn4m_subm_sense_amp_array ++ data_0 bl_0 br_0 data_1 bl_1 br_1 en vdd gnd +* OUTPUT: data_0 +* INPUT : bl_0 +* INPUT : br_0 +* OUTPUT: data_1 +* INPUT : bl_1 +* INPUT : br_1 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* words_per_row: 1 +Xsa_d0 ++ bl_0 br_0 data_0 en vdd gnd ++ sense_amp +Xsa_d1 ++ bl_1 br_1 data_1 en vdd gnd ++ sense_amp +.ENDS sram_2_16_1_scn4m_subm_sense_amp_array + +* spice ptx M{0} {1} p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +.SUBCKT sram_2_16_1_scn4m_subm_precharge_0 ++ bl br en_bar vdd +* OUTPUT: bl +* OUTPUT: br +* INPUT : en_bar +* POWER : vdd +Mlower_pmos bl en_bar br vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mupper_pmos1 bl en_bar vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mupper_pmos2 br en_bar vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_precharge_0 + +.SUBCKT sram_2_16_1_scn4m_subm_precharge_array ++ bl_0 br_0 bl_1 br_1 bl_2 br_2 en_bar vdd +* OUTPUT: bl_0 +* OUTPUT: br_0 +* OUTPUT: bl_1 +* OUTPUT: br_1 +* OUTPUT: bl_2 +* OUTPUT: br_2 +* INPUT : en_bar +* POWER : vdd +* cols: 3 size: 1 bl: bl br: br +Xpre_column_0 ++ bl_0 br_0 en_bar vdd ++ sram_2_16_1_scn4m_subm_precharge_0 +Xpre_column_1 ++ bl_1 br_1 en_bar vdd ++ sram_2_16_1_scn4m_subm_precharge_0 +Xpre_column_2 ++ bl_2 br_2 en_bar vdd ++ sram_2_16_1_scn4m_subm_precharge_0 +.ENDS sram_2_16_1_scn4m_subm_precharge_array +*********************** Write_Driver ****************************** +.SUBCKT write_driver din bl br en vdd gnd + +**** Inverter to conver Data_in to data_in_bar ****** +* din_bar = inv(din) +M_1 din_bar din gnd gnd n W=0.8u L=0.4u +M_2 din_bar din vdd vdd p W=1.4u L=0.4u + +**** 2input nand gate follwed by inverter to drive BL ****** +* din_bar_gated = nand(en, din) +M_3 din_bar_gated en net_7 gnd n W=1.4u L=0.4u +M_4 net_7 din gnd gnd n W=1.4u L=0.4u +M_5 din_bar_gated en vdd vdd p W=1.4u L=0.4u +M_6 din_bar_gated din vdd vdd p W=1.4u L=0.4u +* din_bar_gated_bar = inv(din_bar_gated) +M_7 din_bar_gated_bar din_bar_gated vdd vdd p W=1.4u L=0.4u +M_8 din_bar_gated_bar din_bar_gated gnd gnd n W=0.8u L=0.4u + +**** 2input nand gate follwed by inverter to drive BR****** +* din_gated = nand(en, din_bar) +M_9 din_gated en vdd vdd p W=1.4u L=0.4u +M_10 din_gated en net_8 gnd n W=1.4u L=0.4u +M_11 net_8 din_bar gnd gnd n W=1.4u L=0.4u +M_12 din_gated din_bar vdd vdd p W=1.4u L=0.4u +* din_gated_bar = inv(din_gated) +M_13 din_gated_bar din_gated vdd vdd p W=1.4u L=0.4u +M_14 din_gated_bar din_gated gnd gnd n W=0.8u L=0.4u + +************************************************ +* pull down with en enable +M_15 bl din_gated_bar gnd gnd n W=2.4u L=0.4u +M_16 br din_bar_gated_bar gnd gnd n W=2.4u L=0.4u + + + +.ENDS $ write_driver + +.SUBCKT sram_2_16_1_scn4m_subm_write_driver_array ++ data_0 data_1 bl_0 br_0 bl_1 br_1 en vdd gnd +* INPUT : data_0 +* INPUT : data_1 +* OUTPUT: bl_0 +* OUTPUT: br_0 +* OUTPUT: bl_1 +* OUTPUT: br_1 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* word_size 2 +Xwrite_driver0 ++ data_0 bl_0 br_0 en vdd gnd ++ write_driver +Xwrite_driver1 ++ data_1 bl_1 br_1 en vdd gnd ++ write_driver +.ENDS sram_2_16_1_scn4m_subm_write_driver_array + +.SUBCKT sram_2_16_1_scn4m_subm_port_data ++ rbl_bl rbl_br bl_0 br_0 bl_1 br_1 dout_0 dout_1 din_0 din_1 s_en ++ p_en_bar w_en vdd gnd +* INOUT : rbl_bl +* INOUT : rbl_br +* INOUT : bl_0 +* INOUT : br_0 +* INOUT : bl_1 +* INOUT : br_1 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* INPUT : din_0 +* INPUT : din_1 +* INPUT : s_en +* INPUT : p_en_bar +* INPUT : w_en +* POWER : vdd +* GROUND: gnd +Xprecharge_array0 ++ rbl_bl rbl_br bl_0 br_0 bl_1 br_1 p_en_bar vdd ++ sram_2_16_1_scn4m_subm_precharge_array +Xsense_amp_array0 ++ dout_0 bl_0 br_0 dout_1 bl_1 br_1 s_en vdd gnd ++ sram_2_16_1_scn4m_subm_sense_amp_array +Xwrite_driver_array0 ++ din_0 din_1 bl_0 br_0 bl_1 br_1 w_en vdd gnd ++ sram_2_16_1_scn4m_subm_write_driver_array +.ENDS sram_2_16_1_scn4m_subm_port_data + +* spice ptx M{0} {1} p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +* spice ptx M{0} {1} n m=1 w=0.8u l=0.4u pd=2.40u ps=2.40u as=0.80p ad=0.80p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.40u ps=2.40u as=0.80p ad=0.80p +.ENDS sram_2_16_1_scn4m_subm_pinv + +* spice ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +* spice ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +.SUBCKT sram_2_16_1_scn4m_subm_pnand2 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pnand2 + +.SUBCKT sram_2_16_1_scn4m_subm_and2_dec ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* size: 1 +Xpand2_dec_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand2 +Xpand2_dec_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv +.ENDS sram_2_16_1_scn4m_subm_and2_dec + +.SUBCKT sram_2_16_1_scn4m_subm_hierarchical_predecode2x4 ++ in_0 in_1 out_0 out_1 out_2 out_3 vdd gnd +* INPUT : in_0 +* INPUT : in_1 +* OUTPUT: out_0 +* OUTPUT: out_1 +* OUTPUT: out_2 +* OUTPUT: out_3 +* POWER : vdd +* GROUND: gnd +Xpre_inv_0 ++ in_0 inbar_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv +Xpre_inv_1 ++ in_1 inbar_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv +XXpre2x4_and_0 ++ inbar_0 inbar_1 out_0 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XXpre2x4_and_1 ++ in_0 inbar_1 out_1 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XXpre2x4_and_2 ++ inbar_0 in_1 out_2 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XXpre2x4_and_3 ++ in_0 in_1 out_3 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +.ENDS sram_2_16_1_scn4m_subm_hierarchical_predecode2x4 + +.SUBCKT sram_2_16_1_scn4m_subm_hierarchical_decoder ++ addr_0 addr_1 addr_2 addr_3 decode_0 decode_1 decode_2 decode_3 ++ decode_4 decode_5 decode_6 decode_7 decode_8 decode_9 decode_10 ++ decode_11 decode_12 decode_13 decode_14 decode_15 vdd gnd +* INPUT : addr_0 +* INPUT : addr_1 +* INPUT : addr_2 +* INPUT : addr_3 +* OUTPUT: decode_0 +* OUTPUT: decode_1 +* OUTPUT: decode_2 +* OUTPUT: decode_3 +* OUTPUT: decode_4 +* OUTPUT: decode_5 +* OUTPUT: decode_6 +* OUTPUT: decode_7 +* OUTPUT: decode_8 +* OUTPUT: decode_9 +* OUTPUT: decode_10 +* OUTPUT: decode_11 +* OUTPUT: decode_12 +* OUTPUT: decode_13 +* OUTPUT: decode_14 +* OUTPUT: decode_15 +* POWER : vdd +* GROUND: gnd +Xpre_0 ++ addr_0 addr_1 out_0 out_1 out_2 out_3 vdd gnd ++ sram_2_16_1_scn4m_subm_hierarchical_predecode2x4 +Xpre_1 ++ addr_2 addr_3 out_4 out_5 out_6 out_7 vdd gnd ++ sram_2_16_1_scn4m_subm_hierarchical_predecode2x4 +XDEC_AND_0 ++ out_0 out_4 decode_0 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_4 ++ out_0 out_5 decode_4 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_8 ++ out_0 out_6 decode_8 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_12 ++ out_0 out_7 decode_12 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_1 ++ out_1 out_4 decode_1 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_5 ++ out_1 out_5 decode_5 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_9 ++ out_1 out_6 decode_9 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_13 ++ out_1 out_7 decode_13 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_2 ++ out_2 out_4 decode_2 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_6 ++ out_2 out_5 decode_6 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_10 ++ out_2 out_6 decode_10 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_14 ++ out_2 out_7 decode_14 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_3 ++ out_3 out_4 decode_3 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_7 ++ out_3 out_5 decode_7 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_11 ++ out_3 out_6 decode_11 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +XDEC_AND_15 ++ out_3 out_7 decode_15 vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec +.ENDS sram_2_16_1_scn4m_subm_hierarchical_decoder + +.SUBCKT sram_2_16_1_scn4m_subm_wordline_driver ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xwld_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand2 +Xwl_driver ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv +.ENDS sram_2_16_1_scn4m_subm_wordline_driver + +.SUBCKT sram_2_16_1_scn4m_subm_wordline_driver_array ++ in_0 in_1 in_2 in_3 in_4 in_5 in_6 in_7 in_8 in_9 in_10 in_11 in_12 ++ in_13 in_14 in_15 wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 wl_7 wl_8 wl_9 ++ wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 en vdd gnd +* INPUT : in_0 +* INPUT : in_1 +* INPUT : in_2 +* INPUT : in_3 +* INPUT : in_4 +* INPUT : in_5 +* INPUT : in_6 +* INPUT : in_7 +* INPUT : in_8 +* INPUT : in_9 +* INPUT : in_10 +* INPUT : in_11 +* INPUT : in_12 +* INPUT : in_13 +* INPUT : in_14 +* INPUT : in_15 +* OUTPUT: wl_0 +* OUTPUT: wl_1 +* OUTPUT: wl_2 +* OUTPUT: wl_3 +* OUTPUT: wl_4 +* OUTPUT: wl_5 +* OUTPUT: wl_6 +* OUTPUT: wl_7 +* OUTPUT: wl_8 +* OUTPUT: wl_9 +* OUTPUT: wl_10 +* OUTPUT: wl_11 +* OUTPUT: wl_12 +* OUTPUT: wl_13 +* OUTPUT: wl_14 +* OUTPUT: wl_15 +* INPUT : en +* POWER : vdd +* GROUND: gnd +* rows: 16 cols: 2 +Xwl_driver_and0 ++ in_0 en wl_0 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and1 ++ in_1 en wl_1 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and2 ++ in_2 en wl_2 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and3 ++ in_3 en wl_3 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and4 ++ in_4 en wl_4 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and5 ++ in_5 en wl_5 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and6 ++ in_6 en wl_6 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and7 ++ in_7 en wl_7 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and8 ++ in_8 en wl_8 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and9 ++ in_9 en wl_9 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and10 ++ in_10 en wl_10 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and11 ++ in_11 en wl_11 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and12 ++ in_12 en wl_12 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and13 ++ in_13 en wl_13 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and14 ++ in_14 en wl_14 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +Xwl_driver_and15 ++ in_15 en wl_15 vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver +.ENDS sram_2_16_1_scn4m_subm_wordline_driver_array + +.SUBCKT sram_2_16_1_scn4m_subm_and2_dec_0 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* size: 1 +Xpand2_dec_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand2 +Xpand2_dec_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv +.ENDS sram_2_16_1_scn4m_subm_and2_dec_0 + +.SUBCKT sram_2_16_1_scn4m_subm_port_address ++ addr_0 addr_1 addr_2 addr_3 wl_en wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 ++ wl_7 wl_8 wl_9 wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 rbl_wl vdd gnd +* INPUT : addr_0 +* INPUT : addr_1 +* INPUT : addr_2 +* INPUT : addr_3 +* INPUT : wl_en +* OUTPUT: wl_0 +* OUTPUT: wl_1 +* OUTPUT: wl_2 +* OUTPUT: wl_3 +* OUTPUT: wl_4 +* OUTPUT: wl_5 +* OUTPUT: wl_6 +* OUTPUT: wl_7 +* OUTPUT: wl_8 +* OUTPUT: wl_9 +* OUTPUT: wl_10 +* OUTPUT: wl_11 +* OUTPUT: wl_12 +* OUTPUT: wl_13 +* OUTPUT: wl_14 +* OUTPUT: wl_15 +* OUTPUT: rbl_wl +* POWER : vdd +* GROUND: gnd +Xrow_decoder ++ addr_0 addr_1 addr_2 addr_3 dec_out_0 dec_out_1 dec_out_2 dec_out_3 ++ dec_out_4 dec_out_5 dec_out_6 dec_out_7 dec_out_8 dec_out_9 dec_out_10 ++ dec_out_11 dec_out_12 dec_out_13 dec_out_14 dec_out_15 vdd gnd ++ sram_2_16_1_scn4m_subm_hierarchical_decoder +Xwordline_driver ++ dec_out_0 dec_out_1 dec_out_2 dec_out_3 dec_out_4 dec_out_5 dec_out_6 ++ dec_out_7 dec_out_8 dec_out_9 dec_out_10 dec_out_11 dec_out_12 ++ dec_out_13 dec_out_14 dec_out_15 wl_0 wl_1 wl_2 wl_3 wl_4 wl_5 wl_6 ++ wl_7 wl_8 wl_9 wl_10 wl_11 wl_12 wl_13 wl_14 wl_15 wl_en vdd gnd ++ sram_2_16_1_scn4m_subm_wordline_driver_array +Xrbl_driver ++ wl_en vdd rbl_wl vdd gnd ++ sram_2_16_1_scn4m_subm_and2_dec_0 +.ENDS sram_2_16_1_scn4m_subm_port_address + +.SUBCKT sram_2_16_1_scn4m_subm_bank ++ dout0_0 dout0_1 rbl_bl_0_0 din0_0 din0_1 addr0_0 addr0_1 addr0_2 ++ addr0_3 s_en0 p_en_bar0 w_en0 wl_en0 vdd gnd +* OUTPUT: dout0_0 +* OUTPUT: dout0_1 +* OUTPUT: rbl_bl_0_0 +* INPUT : din0_0 +* INPUT : din0_1 +* INPUT : addr0_0 +* INPUT : addr0_1 +* INPUT : addr0_2 +* INPUT : addr0_3 +* INPUT : s_en0 +* INPUT : p_en_bar0 +* INPUT : w_en0 +* INPUT : wl_en0 +* POWER : vdd +* GROUND: gnd +Xbitcell_array ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 rbl_wl0 wl_0_0 ++ wl_0_1 wl_0_2 wl_0_3 wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 ++ wl_0_11 wl_0_12 wl_0_13 wl_0_14 wl_0_15 vdd gnd ++ sram_2_16_1_scn4m_subm_capped_replica_bitcell_array +Xport_data0 ++ rbl_bl_0_0 rbl_br_0_0 bl_0_0 br_0_0 bl_0_1 br_0_1 dout0_0 dout0_1 ++ din0_0 din0_1 s_en0 p_en_bar0 w_en0 vdd gnd ++ sram_2_16_1_scn4m_subm_port_data +Xport_address0 ++ addr0_0 addr0_1 addr0_2 addr0_3 wl_en0 wl_0_0 wl_0_1 wl_0_2 wl_0_3 ++ wl_0_4 wl_0_5 wl_0_6 wl_0_7 wl_0_8 wl_0_9 wl_0_10 wl_0_11 wl_0_12 ++ wl_0_13 wl_0_14 wl_0_15 rbl_wl0 vdd gnd ++ sram_2_16_1_scn4m_subm_port_address +.ENDS sram_2_16_1_scn4m_subm_bank +*********************** "dff" ****************************** +* Positive edge-triggered FF +.SUBCKT dff D Q clk vdd gnd + +* SPICE3 file created from dff.ext - technology: scmos + +M1000 vdd clk a_24_24# vdd p w=8u l=0.4u +M1001 a_84_296# D vdd vdd p w=4u l=0.4u +M1002 a_104_24# clk a_84_296# vdd p w=4u l=0.4u +M1003 a_140_296# a_24_24# a_104_24# vdd p w=4u l=0.4u +M1004 vdd a_152_16# a_140_296# vdd p w=4u l=0.4u +M1005 a_152_16# a_104_24# vdd vdd p w=4u l=0.4u +M1006 a_260_296# a_152_16# vdd vdd p w=4u l=0.4u +M1007 a_280_24# a_24_24# a_260_296# vdd p w=4u l=0.4u +M1008 a_320_336# clk a_280_24# vdd p w=2u l=0.4u +M1009 vdd Q a_320_336# vdd p w=2u l=0.4u +M1010 gnd clk a_24_24# gnd n w=4u l=0.4u +M1011 Q a_280_24# vdd vdd p w=8u l=0.4u +M1012 a_84_24# D gnd gnd n w=2u l=0.4u +M1013 a_104_24# a_24_24# a_84_24# gnd n w=2u l=0.4u +M1014 a_140_24# clk a_104_24# gnd n w=2u l=0.4u +M1015 gnd a_152_16# a_140_24# gnd n w=2u l=0.4u +M1016 a_152_16# a_104_24# gnd gnd n w=2u l=0.4u +M1017 a_260_24# a_152_16# gnd gnd n w=2u l=0.4u +M1018 a_280_24# clk a_260_24# gnd n w=2u l=0.4u +M1019 a_320_24# a_24_24# a_280_24# gnd n w=2u l=0.4u +M1020 gnd Q a_320_24# gnd n w=2u l=0.4u +M1021 Q a_280_24# gnd gnd n w=4u l=0.4u + +.ENDS + +.SUBCKT sram_2_16_1_scn4m_subm_data_dff ++ din_0 din_1 dout_0 dout_1 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* rows: 1 cols: 2 +Xdff_r0_c0 ++ din_0 dout_0 clk vdd gnd ++ dff +Xdff_r0_c1 ++ din_1 dout_1 clk vdd gnd ++ dff +.ENDS sram_2_16_1_scn4m_subm_data_dff + +.SUBCKT sram_2_16_1_scn4m_subm_row_addr_dff ++ din_0 din_1 din_2 din_3 dout_0 dout_1 dout_2 dout_3 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* INPUT : din_2 +* INPUT : din_3 +* OUTPUT: dout_0 +* OUTPUT: dout_1 +* OUTPUT: dout_2 +* OUTPUT: dout_3 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* rows: 4 cols: 1 +Xdff_r0_c0 ++ din_0 dout_0 clk vdd gnd ++ dff +Xdff_r1_c0 ++ din_1 dout_1 clk vdd gnd ++ dff +Xdff_r2_c0 ++ din_2 dout_2 clk vdd gnd ++ dff +Xdff_r3_c0 ++ din_3 dout_3 clk vdd gnd ++ dff +.ENDS sram_2_16_1_scn4m_subm_row_addr_dff + +* spice ptx M{0} {1} n m=1 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p + +* spice ptx M{0} {1} p m=1 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_7 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p +Mpinv_nmos Z A gnd gnd n m=1 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p +.ENDS sram_2_16_1_scn4m_subm_pinv_7 + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_5 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.40u ps=2.40u as=0.80p ad=0.80p +.ENDS sram_2_16_1_scn4m_subm_pinv_5 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver_1 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 5] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_5 +Xbuf_inv2 ++ Zb1_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_7 +.ENDS sram_2_16_1_scn4m_subm_pdriver_1 + +* spice ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +.SUBCKT sram_2_16_1_scn4m_subm_pnand3_0 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand3_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand3_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand3_pmos3 Z C vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand3_nmos1 Z C net1 gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand3_nmos2 net1 B net2 gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand3_nmos3 net2 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pnand3_0 + +* spice ptx M{0} {1} n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p + +* spice ptx M{0} {1} p m=1 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_6 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p +Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pinv_6 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver_3 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [2] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_6 +.ENDS sram_2_16_1_scn4m_subm_pdriver_3 + +.SUBCKT sram_2_16_1_scn4m_subm_pand3_0 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand3_nand ++ A B C zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand3_0 +Xpand3_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver_3 +.ENDS sram_2_16_1_scn4m_subm_pand3_0 + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_10 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.40u ps=2.40u as=0.80p ad=0.80p +.ENDS sram_2_16_1_scn4m_subm_pinv_10 + +.SUBCKT sram_2_16_1_scn4m_subm_delay_chain ++ in out vdd gnd +* INPUT : in +* OUTPUT: out +* POWER : vdd +* GROUND: gnd +* fanouts: [4, 4, 4, 4, 4, 4, 4, 4, 4] +Xdinv0 ++ in dout_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_0_0 ++ dout_1 n_0_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_0_1 ++ dout_1 n_0_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_0_2 ++ dout_1 n_0_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_0_3 ++ dout_1 n_0_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv1 ++ dout_1 dout_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_1_0 ++ dout_2 n_1_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_1_1 ++ dout_2 n_1_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_1_2 ++ dout_2 n_1_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_1_3 ++ dout_2 n_1_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv2 ++ dout_2 dout_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_2_0 ++ dout_3 n_2_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_2_1 ++ dout_3 n_2_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_2_2 ++ dout_3 n_2_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_2_3 ++ dout_3 n_2_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv3 ++ dout_3 dout_4 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_3_0 ++ dout_4 n_3_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_3_1 ++ dout_4 n_3_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_3_2 ++ dout_4 n_3_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_3_3 ++ dout_4 n_3_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv4 ++ dout_4 dout_5 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_4_0 ++ dout_5 n_4_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_4_1 ++ dout_5 n_4_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_4_2 ++ dout_5 n_4_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_4_3 ++ dout_5 n_4_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv5 ++ dout_5 dout_6 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_5_0 ++ dout_6 n_5_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_5_1 ++ dout_6 n_5_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_5_2 ++ dout_6 n_5_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_5_3 ++ dout_6 n_5_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv6 ++ dout_6 dout_7 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_6_0 ++ dout_7 n_6_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_6_1 ++ dout_7 n_6_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_6_2 ++ dout_7 n_6_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_6_3 ++ dout_7 n_6_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv7 ++ dout_7 dout_8 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_7_0 ++ dout_8 n_7_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_7_1 ++ dout_8 n_7_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_7_2 ++ dout_8 n_7_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_7_3 ++ dout_8 n_7_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdinv8 ++ dout_8 out vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_8_0 ++ out n_8_0 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_8_1 ++ out n_8_1 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_8_2 ++ out n_8_2 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +Xdload_8_3 ++ out n_8_3 vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_10 +.ENDS sram_2_16_1_scn4m_subm_delay_chain + +.SUBCKT sram_2_16_1_scn4m_subm_pnand2_0 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pnand2_0 + +* spice ptx M{0} {1} p m=3 w=6.4u l=0.4u pd=13.60u ps=13.60u as=6.40p ad=6.40p + +* spice ptx M{0} {1} n m=3 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_2 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=3 w=6.4u l=0.4u pd=13.60u ps=13.60u as=6.40p ad=6.40p +Mpinv_nmos Z A gnd gnd n m=3 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p +.ENDS sram_2_16_1_scn4m_subm_pinv_2 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [12] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_2 +.ENDS sram_2_16_1_scn4m_subm_pdriver + +.SUBCKT sram_2_16_1_scn4m_subm_pand2 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand2_nand ++ A B zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand2_0 +Xpand2_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver +.ENDS sram_2_16_1_scn4m_subm_pand2 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver_4 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 1] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_5 +Xbuf_inv2 ++ Zb1_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_5 +.ENDS sram_2_16_1_scn4m_subm_pdriver_4 + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_3 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpinv_nmos Z A gnd gnd n m=1 w=0.8u l=0.4u pd=2.40u ps=2.40u as=0.80p ad=0.80p +.ENDS sram_2_16_1_scn4m_subm_pinv_3 + +* spice ptx M{0} {1} n m=2 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p + +* spice ptx M{0} {1} p m=2 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_9 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=2 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p +Mpinv_nmos Z A gnd gnd n m=2 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p +.ENDS sram_2_16_1_scn4m_subm_pinv_9 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver_2 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [10] +Xbuf_inv1 ++ A Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_9 +.ENDS sram_2_16_1_scn4m_subm_pdriver_2 + +.SUBCKT sram_2_16_1_scn4m_subm_pand3 ++ A B C Z vdd gnd +* INPUT : A +* INPUT : B +* INPUT : C +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Xpand3_nand ++ A B C zb_int vdd gnd ++ sram_2_16_1_scn4m_subm_pnand3_0 +Xpand3_inv ++ zb_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver_2 +.ENDS sram_2_16_1_scn4m_subm_pand3 + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_0 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p +Mpinv_nmos Z A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pinv_0 + +* spice ptx M{0} {1} n m=1 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p + +* spice ptx M{0} {1} p m=1 w=6.4u l=0.4u pd=13.60u ps=13.60u as=6.40p ad=6.40p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_1 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=1 w=6.4u l=0.4u pd=13.60u ps=13.60u as=6.40p ad=6.40p +Mpinv_nmos Z A gnd gnd n m=1 w=3.2u l=0.4u pd=7.20u ps=7.20u as=3.20p ad=3.20p +.ENDS sram_2_16_1_scn4m_subm_pinv_1 + +.SUBCKT sram_2_16_1_scn4m_subm_dff_buf_0 ++ D Q Qb clk vdd gnd +* INPUT : D +* OUTPUT: Q +* OUTPUT: Qb +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* inv1: 2 inv2: 4 +Xdff_buf_dff ++ D qint clk vdd gnd ++ dff +Xdff_buf_inv1 ++ qint Qb vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_0 +Xdff_buf_inv2 ++ Qb Q vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_1 +.ENDS sram_2_16_1_scn4m_subm_dff_buf_0 + +.SUBCKT sram_2_16_1_scn4m_subm_dff_buf_array ++ din_0 din_1 dout_0 dout_bar_0 dout_1 dout_bar_1 clk vdd gnd +* INPUT : din_0 +* INPUT : din_1 +* OUTPUT: dout_0 +* OUTPUT: dout_bar_0 +* OUTPUT: dout_1 +* OUTPUT: dout_bar_1 +* INPUT : clk +* POWER : vdd +* GROUND: gnd +* inv1: 2 inv2: 4 +Xdff_r0_c0 ++ din_0 dout_0 dout_bar_0 clk vdd gnd ++ sram_2_16_1_scn4m_subm_dff_buf_0 +Xdff_r1_c0 ++ din_1 dout_1 dout_bar_1 clk vdd gnd ++ sram_2_16_1_scn4m_subm_dff_buf_0 +.ENDS sram_2_16_1_scn4m_subm_dff_buf_array + +* spice ptx M{0} {1} n m=3 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p + +* spice ptx M{0} {1} p m=3 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p + +.SUBCKT sram_2_16_1_scn4m_subm_pinv_8 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpinv_pmos Z A vdd vdd p m=3 w=8.0u l=0.4u pd=16.80u ps=16.80u as=8.00p ad=8.00p +Mpinv_nmos Z A gnd gnd n m=3 w=4.0u l=0.4u pd=8.80u ps=8.80u as=4.00p ad=4.00p +.ENDS sram_2_16_1_scn4m_subm_pinv_8 + +.SUBCKT sram_2_16_1_scn4m_subm_pdriver_0 ++ A Z vdd gnd +* INPUT : A +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +* sizes: [1, 2, 5, 15] +Xbuf_inv1 ++ A Zb1_int vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_5 +Xbuf_inv2 ++ Zb1_int Zb2_int vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_6 +Xbuf_inv3 ++ Zb2_int Zb3_int vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_7 +Xbuf_inv4 ++ Zb3_int Z vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_8 +.ENDS sram_2_16_1_scn4m_subm_pdriver_0 + +.SUBCKT sram_2_16_1_scn4m_subm_pnand2_1 ++ A B Z vdd gnd +* INPUT : A +* INPUT : B +* OUTPUT: Z +* POWER : vdd +* GROUND: gnd +Mpnand2_pmos1 vdd A Z vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_pmos2 Z B vdd vdd p m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos1 Z B net1 gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +Mpnand2_nmos2 net1 A gnd gnd n m=1 w=1.6u l=0.4u pd=4.00u ps=4.00u as=1.60p ad=1.60p +.ENDS sram_2_16_1_scn4m_subm_pnand2_1 + +.SUBCKT sram_2_16_1_scn4m_subm_control_logic_rw ++ csb web clk rbl_bl s_en w_en p_en_bar wl_en clk_buf vdd gnd +* INPUT : csb +* INPUT : web +* INPUT : clk +* INPUT : rbl_bl +* OUTPUT: s_en +* OUTPUT: w_en +* OUTPUT: p_en_bar +* OUTPUT: wl_en +* OUTPUT: clk_buf +* POWER : vdd +* GROUND: gnd +* word_size 2 +Xctrl_dffs ++ csb web cs_bar cs we_bar we clk_buf vdd gnd ++ sram_2_16_1_scn4m_subm_dff_buf_array +Xclkbuf ++ clk clk_buf vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver_0 +Xinv_clk_bar ++ clk_buf clk_bar vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_3 +Xand2_gated_clk_bar ++ clk_bar cs gated_clk_bar vdd gnd ++ sram_2_16_1_scn4m_subm_pand2 +Xand2_gated_clk_buf ++ clk_buf cs gated_clk_buf vdd gnd ++ sram_2_16_1_scn4m_subm_pand2 +Xbuf_wl_en ++ gated_clk_bar wl_en vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver_1 +Xrbl_bl_delay_inv ++ rbl_bl_delay rbl_bl_delay_bar vdd gnd ++ sram_2_16_1_scn4m_subm_pinv_3 +Xw_en_and ++ we rbl_bl_delay_bar gated_clk_bar w_en vdd gnd ++ sram_2_16_1_scn4m_subm_pand3 +Xbuf_s_en_and ++ rbl_bl_delay gated_clk_bar we_bar s_en vdd gnd ++ sram_2_16_1_scn4m_subm_pand3_0 +Xdelay_chain ++ rbl_bl rbl_bl_delay vdd gnd ++ sram_2_16_1_scn4m_subm_delay_chain +Xnand_p_en_bar ++ gated_clk_buf rbl_bl_delay p_en_bar_unbuf vdd gnd ++ sram_2_16_1_scn4m_subm_pnand2_1 +Xbuf_p_en_bar ++ p_en_bar_unbuf p_en_bar vdd gnd ++ sram_2_16_1_scn4m_subm_pdriver_4 +.ENDS sram_2_16_1_scn4m_subm_control_logic_rw + +.SUBCKT sram_2_16_1_scn4m_subm ++ din0[0] din0[1] addr0[0] addr0[1] addr0[2] addr0[3] csb0 web0 clk0 ++ dout0[0] dout0[1] vdd gnd +* INPUT : din0[0] +* INPUT : din0[1] +* INPUT : addr0[0] +* INPUT : addr0[1] +* INPUT : addr0[2] +* INPUT : addr0[3] +* INPUT : csb0 +* INPUT : web0 +* INPUT : clk0 +* OUTPUT: dout0[0] +* OUTPUT: dout0[1] +* POWER : vdd +* GROUND: gnd +Xbank0 ++ dout0[0] dout0[1] rbl_bl0 bank_din0_0 bank_din0_1 a0_0 a0_1 a0_2 a0_3 ++ s_en0 p_en_bar0 w_en0 wl_en0 vdd gnd ++ sram_2_16_1_scn4m_subm_bank +Xcontrol0 ++ csb0 web0 clk0 rbl_bl0 s_en0 w_en0 p_en_bar0 wl_en0 clk_buf0 vdd gnd ++ sram_2_16_1_scn4m_subm_control_logic_rw +Xrow_address0 ++ addr0[0] addr0[1] addr0[2] addr0[3] a0_0 a0_1 a0_2 a0_3 clk_buf0 vdd ++ gnd ++ sram_2_16_1_scn4m_subm_row_addr_dff +Xdata_dff0 ++ din0[0] din0[1] bank_din0_0 bank_din0_1 clk_buf0 vdd gnd ++ sram_2_16_1_scn4m_subm_data_dff +.ENDS sram_2_16_1_scn4m_subm diff --git a/compiler/tests/sram_1b_16_1rw_scn4m_subm.log b/compiler/tests/sram_1b_16_1rw_scn4m_subm.log new file mode 100644 index 00000000..0164bbb4 --- /dev/null +++ b/compiler/tests/sram_1b_16_1rw_scn4m_subm.log @@ -0,0 +1,2 @@ +ERROR: file magic.py: line 358: sram LVS mismatch (results in /tmp/openram_bugra_14157_temp/sram.lvs.report) + diff --git a/docs/source/characterization.md b/docs/source/characterization.md index 60adc74a..5fdde81b 100644 --- a/docs/source/characterization.md +++ b/docs/source/characterization.md @@ -46,7 +46,8 @@ Measures the timing/power through SPICE simulation: * Testing Support Modules * Other modules are derivatives of the simulation module used in the unit tests - +## Stand-alone Charaterizer +The stand-alone characterizer is a script ([sram_char.py]()sram_char.py) that can be run without generating an SRAM. ## Characterization Options * Characterization by Configuration File diff --git a/sram_char.py b/sram_char.py new file mode 100755 index 00000000..52a085cb --- /dev/null +++ b/sram_char.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +""" +This script will characterize an SRAM previously generated by OpenRAM given a +configuration file. Configuration option "use_pex" determines whether extracted +or generated spice is used and option "analytical_delay" determines whether +an analytical model or spice simulation is used for characterization. +""" + +import sys +import datetime + +# You don't need the next two lines if you're sure that openram package is installed +from common import * +make_openram_package() +import openram + +(OPTS, args) = openram.parse_args() + +# Override the usage +USAGE = "Usage: {} [options] \nUse -h for help.\n".format(__file__) + +# Check that we are left with a single configuration file as argument. +if len(args) != 2: + print(USAGE) + sys.exit(2) + +OPTS.top_process = 'memchar' + +# These depend on arguments, so don't load them until now. +from openram import debug + +# Parse config file and set up all the options +openram.init_openram(config_file=args[0], is_unit_test=False) + +openram.print_banner() + +# Configure the SRAM organization (duplicated from openram.py) +from openram.characterizer import fake_sram +s = fake_sram(name=OPTS.output_name, + 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) + +debug.check(os.path.exists(args[1]), "Spice netlist file {} not found.".format(args[1])) +sp_file = args[1] +s.generate_pins() +s.setup_multiport_constants() + +OPTS.netlist_only = True +OPTS.check_lvsdrc = False +OPTS.nomimal_corner_only = True + +# TODO: remove this after adding trimmed netlist gen to sram run +OPTS.trim_netlist = False + +# Characterize the design +start_time = datetime.datetime.now() +from openram.characterizer import lib +debug.print_raw("LIB: Characterizing... ") +lib(out_dir=OPTS.output_path, sram=s, sp_file=sp_file, use_model=False) +print_time("Characterization", datetime.datetime.now(), start_time) + +# Output info about this run +print("Output files are:\n{0}*.lib".format(OPTS.output_path)) +#report_status() #could modify this function to provide relevant info + +# Delete temp files, remove the dir, etc. +openram.end_openram() diff --git a/sram_compiler.py b/sram_compiler.py index 389418b0..10f32393 100755 --- a/sram_compiler.py +++ b/sram_compiler.py @@ -32,6 +32,8 @@ if len(args) != 1: print(openram.USAGE) sys.exit(2) +# Set top process to openram +OPTS.top_process = 'openram' # These depend on arguments, so don't load them until now. from openram import debug @@ -76,4 +78,3 @@ s.save() # Delete temp files etc. openram.end_openram() openram.print_time("End", datetime.datetime.now(), start_time) - diff --git a/sram_func.py b/sram_func.py new file mode 100755 index 00000000..5b7b1569 --- /dev/null +++ b/sram_func.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +""" +This script will functionally simulate an SRAM previously generated by OpenRAM +given a configuration file. Configuration option "use_pex" determines whether +extracted or generated spice is used. Command line arguments dictate the +number of cycles and period to be simulated. +""" + +import sys +import datetime + +# You don't need the next two lines if you're sure that openram package is installed +from common import * +make_openram_package() +import openram + +(OPTS, args) = openram.parse_args() + +# Override the usage +USAGE = "Usage: {} [options] \nUse -h for help.\n".format(__file__) + +# Check that we are left with a single configuration file as argument. +if len(args) != 4: + print(USAGE) + sys.exit(2) + +OPTS.top_process = 'memfunc' + +# Parse argument +config_file = args[0] +sp_file = args[1] +cycles = int(args[2]) +period = float(args[3]) + +# These depend on arguments, so don't load them until now. +from openram import debug + +# Parse config file and set up all the options +openram.init_openram(config_file=config_file, is_unit_test=False) + +openram.print_banner() + +# Configure the SRAM organization (duplicated from openram.py) +from openram.characterizer.fake_sram import fake_sram +s = fake_sram(name=OPTS.output_name, + 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) + +s.generate_pins() +s.setup_multiport_constants() + +OPTS.netlist_only = True +OPTS.check_lvsdrc = False + +# Generate stimulus and run functional simulation on the design +start_time = datetime.datetime.now() +from openram.characterizer import functional +debug.print_raw("Functional simulation... ") +f = functional(s, cycles=cycles, spfile=sp_file, period=period, output_path=OPTS.openram_temp) +(fail, error) = f.run() +debug.print_raw(error) +openram.print_time("Functional simulation", datetime.datetime.now(), start_time) + +# Delete temp files, remove the dir, etc. after success +if fail: + openram.end_openram() diff --git a/technology/freepdk45/gds_lib/sense_amp.gds b/technology/freepdk45/gds_lib/sense_amp.gds index f0bfebfd..51513e13 100644 Binary files a/technology/freepdk45/gds_lib/sense_amp.gds and b/technology/freepdk45/gds_lib/sense_amp.gds differ diff --git a/technology/freepdk45/sp_lib/sense_amp.sp b/technology/freepdk45/sp_lib/sense_amp.sp index b5778306..8daf8a00 100644 --- a/technology/freepdk45/sp_lib/sense_amp.sp +++ b/technology/freepdk45/sp_lib/sense_amp.sp @@ -1,11 +1,16 @@ .SUBCKT sense_amp bl br dout en vdd gnd -M_1 dout net_1 vdd vdd pmos_vtg w=540.0n l=50.0n -M_3 net_1 dout vdd vdd pmos_vtg w=540.0n l=50.0n -M_2 dout net_1 net_2 gnd nmos_vtg w=270.0n l=50.0n -M_8 net_1 dout net_2 gnd nmos_vtg w=270.0n l=50.0n -M_5 bl en dout vdd pmos_vtg w=720.0n l=50.0n +M_1 dint net_1 vdd vdd pmos_vtg w=540.0n l=50.0n +M_3 net_1 dint vdd vdd pmos_vtg w=540.0n l=50.0n +M_2 dint net_1 net_2 gnd nmos_vtg w=270.0n l=50.0n +M_8 net_1 dint net_2 gnd nmos_vtg w=270.0n l=50.0n +M_5 bl en dint vdd pmos_vtg w=720.0n l=50.0n M_6 br en net_1 vdd pmos_vtg w=720.0n l=50.0n M_7 net_2 en gnd gnd nmos_vtg w=270.0n l=50.0n + +M_9 dout_bar dint vdd vdd pmos_vtg w=180.0n l=50.0n +M_10 dout_bar dint gnd gnd nmos_vtg w=90.0n l=50.0n +M_11 dout dout_bar vdd vdd pmos_vtg w=540.0n l=50.0n +M_12 dout dout_bar gnd gnd nmos_vtg w=270.0n l=50.0n .ENDS sense_amp diff --git a/technology/scn4m_subm/gds_lib/sense_amp.gds b/technology/scn4m_subm/gds_lib/sense_amp.gds index 5ffbb0d5..5790e4bc 100644 Binary files a/technology/scn4m_subm/gds_lib/sense_amp.gds and b/technology/scn4m_subm/gds_lib/sense_amp.gds differ diff --git a/technology/scn4m_subm/mag_lib/sense_amp.mag b/technology/scn4m_subm/mag_lib/sense_amp.mag index e5fa4373..08e20f6d 100644 --- a/technology/scn4m_subm/mag_lib/sense_amp.mag +++ b/technology/scn4m_subm/mag_lib/sense_amp.mag @@ -1,136 +1,183 @@ magic tech scmos -timestamp 1536089670 +timestamp 1681333912 << nwell >> -rect 0 0 40 102 +rect 0 28 40 153 << pwell >> -rect 0 102 40 163 +rect 0 153 40 214 +rect 0 0 40 28 << ntransistor >> -rect 21 130 23 139 -rect 12 108 14 117 -rect 20 108 22 117 +rect 21 181 23 190 +rect 12 159 14 168 +rect 20 159 22 168 +rect 13 10 15 22 +rect 21 18 23 22 << ptransistor >> -rect 12 78 14 96 -rect 20 78 22 96 -rect 11 20 13 44 -rect 27 20 29 44 +rect 12 129 14 147 +rect 20 129 22 147 +rect 11 71 13 95 +rect 27 71 29 95 +rect 13 34 15 58 +rect 21 34 23 42 << ndiffusion >> -rect 20 130 21 139 -rect 23 130 24 139 -rect 11 108 12 117 -rect 14 108 15 117 -rect 19 108 20 117 -rect 22 108 23 117 +rect 20 181 21 190 +rect 23 181 24 190 +rect 11 159 12 168 +rect 14 159 15 168 +rect 19 159 20 168 +rect 22 159 23 168 +rect 12 10 13 22 +rect 15 10 16 22 +rect 20 18 21 22 +rect 23 18 24 22 << pdiffusion >> -rect 7 94 12 96 -rect 11 80 12 94 -rect 7 78 12 80 -rect 14 94 20 96 -rect 14 80 15 94 -rect 19 80 20 94 -rect 14 78 20 80 -rect 22 94 27 96 -rect 22 80 23 94 -rect 22 78 27 80 -rect 10 20 11 44 -rect 13 20 14 44 -rect 26 20 27 44 -rect 29 20 30 44 +rect 7 145 12 147 +rect 11 131 12 145 +rect 7 129 12 131 +rect 14 145 20 147 +rect 14 131 15 145 +rect 19 131 20 145 +rect 14 129 20 131 +rect 22 145 27 147 +rect 22 131 23 145 +rect 22 129 27 131 +rect 10 71 11 95 +rect 13 71 14 95 +rect 26 71 27 95 +rect 29 71 30 95 +rect 12 34 13 58 +rect 15 34 16 58 +rect 20 34 21 42 +rect 23 34 24 42 << ndcontact >> -rect 16 130 20 139 -rect 24 130 28 139 -rect 7 108 11 117 -rect 15 108 19 117 -rect 23 108 27 117 +rect 16 181 20 190 +rect 24 181 28 190 +rect 7 159 11 168 +rect 15 159 19 168 +rect 23 159 27 168 +rect 8 10 12 22 +rect 16 10 20 22 +rect 24 18 28 22 << pdcontact >> -rect 7 80 11 94 -rect 15 80 19 94 -rect 23 80 27 94 -rect 6 20 10 44 -rect 14 20 18 44 -rect 22 20 26 44 -rect 30 20 34 44 +rect 7 131 11 145 +rect 15 131 19 145 +rect 23 131 27 145 +rect 6 71 10 95 +rect 14 71 18 95 +rect 22 71 26 95 +rect 30 71 34 95 +rect 8 34 12 58 +rect 16 34 20 58 +rect 24 34 28 42 << psubstratepcontact >> -rect 32 137 36 141 +rect 32 188 36 192 +rect 32 13 36 17 << nsubstratencontact >> -rect 27 70 31 74 +rect 27 121 31 125 +rect 27 55 31 59 << polysilicon >> -rect 21 139 23 149 -rect 21 129 23 130 -rect 3 127 23 129 -rect 3 47 5 127 -rect 12 122 34 124 -rect 12 117 14 122 -rect 20 117 22 119 -rect 12 96 14 108 -rect 20 96 22 108 -rect 32 105 34 122 -rect 30 101 34 105 -rect 12 76 14 78 -rect 20 69 22 78 -rect 13 67 22 69 -rect 9 55 11 65 -rect 32 55 34 101 -rect 33 51 34 55 -rect 3 45 13 47 -rect 11 44 13 45 -rect 27 44 29 46 -rect 11 19 13 20 -rect 27 19 29 20 -rect 11 17 29 19 +rect 21 190 23 200 +rect 21 180 23 181 +rect 3 178 23 180 +rect 3 98 5 178 +rect 12 173 34 175 +rect 12 168 14 173 +rect 20 168 22 170 +rect 12 147 14 159 +rect 20 147 22 159 +rect 32 156 34 173 +rect 30 152 34 156 +rect 12 127 14 129 +rect 20 120 22 129 +rect 13 118 22 120 +rect 9 106 11 116 +rect 32 106 34 152 +rect 33 102 34 106 +rect 3 96 13 98 +rect 11 95 13 96 +rect 27 95 29 97 +rect 11 70 13 71 +rect 27 70 29 71 +rect 11 68 29 70 +rect 7 63 23 65 +rect 13 58 15 60 +rect 21 42 23 63 +rect 13 31 15 34 +rect 13 27 14 31 +rect 13 22 15 27 +rect 21 22 23 34 +rect 21 16 23 18 +rect 13 8 15 10 << polycontact >> -rect 20 149 24 153 -rect 26 101 30 105 -rect 9 65 13 69 -rect 9 51 13 55 -rect 29 51 33 55 +rect 20 200 24 204 +rect 26 152 30 156 +rect 9 116 13 120 +rect 9 102 13 106 +rect 29 102 33 106 +rect 3 63 7 67 +rect 14 27 18 31 << metal1 >> -rect -2 149 20 153 -rect 24 149 36 153 -rect 28 133 32 137 -rect 16 117 19 130 -rect 7 94 11 108 -rect 23 105 27 108 -rect 23 101 26 105 -rect 7 69 11 80 -rect 15 94 19 96 -rect 15 78 19 80 -rect 23 94 27 101 -rect 23 78 27 80 -rect 15 75 18 78 -rect 15 74 31 75 -rect 15 72 27 74 -rect 7 65 9 69 -rect 6 44 9 54 -rect 33 51 34 55 -rect 31 44 34 51 -rect 3 20 6 23 -rect 3 15 7 20 +rect -2 200 20 204 +rect 24 200 36 204 +rect 28 184 32 188 +rect 16 168 19 181 +rect 7 145 11 159 +rect 23 156 27 159 +rect 23 152 26 156 +rect 7 120 11 131 +rect 15 145 19 147 +rect 15 129 19 131 +rect 23 145 27 152 +rect 23 129 27 131 +rect 15 126 18 129 +rect 15 125 31 126 +rect 15 123 27 125 +rect 7 116 9 120 +rect 6 95 9 105 +rect 33 102 34 106 +rect 31 95 34 102 +rect 3 71 6 74 +rect 3 67 7 71 +rect 20 55 27 58 +rect 8 22 11 34 +rect 24 30 28 34 +rect 18 27 28 30 +rect 24 22 28 27 +rect 20 13 32 15 +rect 20 12 36 13 +rect 8 8 11 10 +rect 7 5 11 8 << m2contact >> -rect 32 133 36 137 -rect 27 66 31 70 -rect 13 44 17 48 -rect 22 44 26 48 -rect 3 11 7 15 +rect 32 184 36 188 +rect 27 117 31 121 +rect 13 95 17 99 +rect 22 95 26 99 +rect 27 51 31 55 +rect 32 17 36 21 +rect 3 4 7 8 << metal2 >> -rect 10 48 14 163 -rect 20 48 24 163 -rect 32 129 36 133 -rect 27 62 31 66 -rect 10 44 13 48 -rect 20 44 22 48 -rect 3 0 7 11 -rect 10 0 14 44 -rect 20 0 24 44 +rect 10 99 14 214 +rect 20 99 24 214 +rect 32 180 36 184 +rect 27 113 31 117 +rect 10 95 13 99 +rect 20 95 22 99 +rect 3 0 7 4 +rect 10 0 14 95 +rect 20 0 24 95 +rect 27 47 31 51 +rect 32 21 36 25 << bb >> -rect 0 0 34 163 +rect 0 0 34 214 << labels >> -flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en -rlabel metal2 34 131 34 131 1 gnd -rlabel metal2 29 64 29 64 1 vdd -rlabel metal2 12 161 12 161 5 bl -rlabel metal2 22 161 22 161 5 br -rlabel metal2 5 3 5 3 1 dout +rlabel metal2 5 2 5 2 1 dout +rlabel metal2 29 49 29 49 1 vdd +rlabel metal2 22 212 22 212 5 br +rlabel metal2 12 212 12 212 5 bl +rlabel metal2 29 115 29 115 1 vdd +rlabel metal2 34 182 34 182 1 gnd +flabel metal1 0 200 0 200 4 FreeSans 26 0 0 0 en +rlabel metal2 34 23 34 23 1 gnd << properties >> string path 270.000 468.000 270.000 486.000 288.000 486.000 288.000 468.000 270.000 468.000 << end >> diff --git a/technology/scn4m_subm/sp_lib/sense_amp.sp b/technology/scn4m_subm/sp_lib/sense_amp.sp index 70622413..2b72262e 100644 --- a/technology/scn4m_subm/sp_lib/sense_amp.sp +++ b/technology/scn4m_subm/sp_lib/sense_amp.sp @@ -5,11 +5,15 @@ * SPICE3 file created from sense_amp.ext - technology: scmos M1000 gnd en a_56_432# gnd n w=1.8u l=0.4u -M1001 a_56_432# a_48_304# dout gnd n w=1.8u l=0.4u -M1002 a_48_304# dout a_56_432# gnd n w=1.8u l=0.4u -M1003 vdd a_48_304# dout vdd p w=3.6u l=0.4u -M1004 a_48_304# dout vdd vdd p w=3.6u l=0.4u -M1005 bl en dout vdd p w=4.8u l=0.4u +M1001 a_56_432# a_48_304# dint gnd n w=1.8u l=0.4u +M1002 a_48_304# dint a_56_432# gnd n w=1.8u l=0.4u +M1003 vdd a_48_304# dint vdd p w=3.6u l=0.4u +M1004 a_48_304# dint vdd vdd p w=3.6u l=0.4u +M1005 bl en dint vdd p w=4.8u l=0.4u M1006 a_48_304# en br vdd p w=4.8u l=0.4u +M1007 dout_bar dint vdd vdd p w=1.6u l=0.4u +M1008 gnd dint dout_bar gnd n w=0.8u l=0.4u +M1009 dout dout_bar vdd vdd p w=4.8u l=0.4u +M1010 gnd dout_bar dout gnd n w=2.4u l=0.4u .ENDS