diff --git a/compiler/base/utils.py b/compiler/base/utils.py index b13f2f7e..28c5f997 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -3,6 +3,7 @@ import gdsMill import tech import math import globals +import debug from vector import vector from pin_layout import pin_layout @@ -65,6 +66,7 @@ def get_gds_size(name, gds_filename, units, layer): Open a GDS file and return the size from either the bounding box or a border layer. """ + debug.info(2,"Creating VLSI layout for {}".format(name)) cell_vlsi = gdsMill.VlsiLayout(units=units) reader = gdsMill.Gds2reader(cell_vlsi) reader.loadFromFile(gds_filename) @@ -72,6 +74,7 @@ def get_gds_size(name, gds_filename, units, layer): cell = {} measure_result = cell_vlsi.getLayoutBorder(layer) if measure_result == None: + debug.info(2,"Layout border failed. Trying to measure size for {}".format(name)) measure_result = cell_vlsi.measureSize(name) # returns width,height return measure_result diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py new file mode 100644 index 00000000..9cec7d8d --- /dev/null +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -0,0 +1,98 @@ +import design +import debug +import utils +from tech import GDS,layer + +class bitcell_1rw_1r(design.design): + """ + A single bit cell (6T, 8T, etc.) This module implements the + single memory cell used in the design. It is a hand-made cell, so + the layout and netlist should be available in the technology + library. + """ + + pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"] + (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) + pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"], layer["boundary"]) + + def __init__(self): + design.design.__init__(self, "cell_1rw_1r") + debug.info(2, "Create bitcell with 1RW and 1R Port") + + self.width = bitcell.width + self.height = bitcell.height + self.pin_map = bitcell.pin_map + + def analytical_delay(self, slew, load=0, swing = 0.5): + # delay of bit cell is not like a driver(from WL) + # so the slew used should be 0 + # it should not be slew dependent? + # because the value is there + # the delay is only over half transsmission gate + from tech import spice + r = spice["min_tx_r"]*3 + c_para = spice["min_tx_drain_c"] + result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing) + return result + + + def list_bitcell_pins(self, col, row): + """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ + bitcell_pins = ["bl0[{0}]".format(col), + "br0[{0}]".format(col), + "bl1[{0}]".format(col), + "br1[{0}]".format(col), + "wl0[{0}]".format(row), + "wl1[{0}]".format(row), + "vdd", + "gnd"] + return bitcell_pins + + def list_all_wl_names(self): + """ Creates a list of all wordline pin names """ + row_pins = ["wl0", "wl1"] + return row_pins + + def list_all_bitline_names(self): + """ Creates a list of all bitline pin names (both bl and br) """ + column_pins = ["bl0", "br0", "bl1", "br1"] + return column_pins + + def list_all_bl_names(self): + """ Creates a list of all bl pins names """ + column_pins = ["bl0", "bl1"] + return column_pins + + def list_all_br_names(self): + """ Creates a list of all br pins names """ + column_pins = ["br0", "br1"] + return column_pins + + def list_read_bl_names(self): + """ Creates a list of bl pin names associated with read ports """ + column_pins = ["bl0", "bl1"] + return column_pins + + def list_read_br_names(self): + """ Creates a list of br pin names associated with read ports """ + column_pins = ["br0", "br1"] + return column_pins + + def list_write_bl_names(self): + """ Creates a list of bl pin names associated with write ports """ + column_pins = ["bl0"] + return column_pins + + def list_write_br_names(self): + """ Creates a list of br pin names asscociated with write ports""" + column_pins = ["br0"] + return column_pins + + def analytical_power(self, proc, vdd, temp, load): + """Bitcell power in nW. Only characterizes leakage.""" + from tech import spice + leakage = spice["bitcell_leakage"] + dynamic = 0 #temporary + total_power = self.return_power(dynamic, leakage) + return total_power + diff --git a/compiler/modules/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py similarity index 100% rename from compiler/modules/replica_bitcell.py rename to compiler/bitcells/replica_bitcell.py diff --git a/compiler/modules/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py similarity index 100% rename from compiler/modules/replica_pbitcell.py rename to compiler/bitcells/replica_pbitcell.py diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index ea99c51c..53155e09 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -6,6 +6,7 @@ from .lib import * from .delay import * from .setup_hold import * from .functional import * +from .worst_case import * from .simulation import * diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 0d5b347b..d699dc06 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -7,8 +7,9 @@ from .trim_spice import * from .charutils import * import utils from globals import OPTS +from .simulation import simulation -class delay(): +class delay(simulation): """Functions to measure the delay and power of an SRAM at a given address and data bit. @@ -26,27 +27,14 @@ class delay(): """ def __init__(self, sram, spfile, corner): - self.sram = sram - self.name = sram.name - self.word_size = self.sram.word_size - self.addr_size = self.sram.addr_size - self.num_cols = self.sram.num_cols - self.num_rows = self.sram.num_rows - self.num_banks = self.sram.num_banks - self.sp_file = spfile - - self.total_ports = self.sram.total_ports - self.total_write = self.sram.total_write - self.total_read = self.sram.total_read - self.read_index = self.sram.read_index - self.write_index = self.sram.write_index - self.port_id = self.sram.port_id + simulation.__init__(self, sram, spfile, corner) # These are the member variables for a simulation + self.targ_read_ports = [] + self.targ_write_ports = [] self.period = 0 self.set_load_slew(0,0) self.set_corner(corner) - self.create_port_names() self.create_signal_names() #Create global measure names. Should maybe be an input at some point. @@ -66,34 +54,6 @@ class delay(): #This is TODO once multiport control has been finalized. #self.control_name = "CSB" - def create_port_names(self): - """Generates the port names to be used in characterization and sets default simulation target ports""" - self.write_ports = [] - self.read_ports = [] - self.total_port_num = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports - - #save a member variable to avoid accessing global. readwrite ports have different control signals. - self.readwrite_port_num = OPTS.num_rw_ports - - #Generate the port names. readwrite ports are required to be added first for this to work. - for readwrite_port_num in range(OPTS.num_rw_ports): - self.read_ports.append(readwrite_port_num) - self.write_ports.append(readwrite_port_num) - #This placement is intentional. It makes indexing input data easier. See self.data_values - for write_port_num in range(OPTS.num_rw_ports, OPTS.num_rw_ports+OPTS.num_w_ports): - self.write_ports.append(write_port_num) - for read_port_num in range(OPTS.num_rw_ports+OPTS.num_w_ports, OPTS.num_rw_ports+OPTS.num_w_ports+OPTS.num_r_ports): - self.read_ports.append(read_port_num) - - #Set the default target ports for simulation. Default is all the ports. - self.targ_read_ports = self.read_ports - self.targ_write_ports = self.write_ports - - def set_corner(self,corner): - """ Set the corner values """ - self.corner = corner - (self.process, self.vdd_voltage, self.temperature) = corner - def set_load_slew(self,load,slew): """ Set the load and slew """ self.load = load @@ -113,9 +73,9 @@ class delay(): debug.error("Given probe_data is not an integer to specify a data bit",1) #Adding port options here which the characterizer cannot handle. Some may be added later like ROM - if len(self.read_ports) == 0: + if len(self.read_index) == 0: debug.error("Characterizer does not currently support SRAMs without read ports.",1) - if len(self.write_ports) == 0: + if len(self.write_index) == 0: debug.error("Characterizer does not currently support SRAMs without write ports.",1) def write_generic_stimulus(self): @@ -129,12 +89,12 @@ class delay(): self.sf.write("\n* Instantiation of the SRAM\n") self.stim.inst_sram(sram=self.sram, port_signal_names=(self.addr_name,self.din_name,self.dout_name), - port_info=(self.total_port_num,self.write_ports,self.read_ports), + port_info=(self.total_ports,self.write_index,self.read_index), abits=self.addr_size, dbits=self.word_size, sram_name=self.name) self.sf.write("\n* SRAM output loads\n") - for port in self.read_ports: + for port in self.read_index: for i in range(self.word_size): self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load)) @@ -172,7 +132,7 @@ class delay(): self.gen_control() self.sf.write("\n* Generation of Port clock signal\n") - for port in range(self.total_port_num): + for port in range(self.total_ports): self.stim.gen_pulse(sig_name="CLK{0}".format(port), v1=0, v2=self.vdd_voltage, @@ -195,9 +155,6 @@ class delay(): """ self.check_arguments() - # obtains list of time-points for each rising clk edge - #self.create_test_cycles() - # creates and opens stimulus file for writing temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.sf = open(temp_stim, "w") @@ -214,24 +171,24 @@ class delay(): # generate data and addr signals self.sf.write("\n* Generation of data and address signals\n") - for write_port in self.write_ports: + for write_port in self.write_index: for i in range(self.word_size): self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i), v_val=0) - for port in range(self.total_port_num): + for port in range(self.total_ports): for i in range(self.addr_size): self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i), v_val=0) # generate control signals self.sf.write("\n* Generation of control signals\n") - for port in range(self.total_port_num): + for port in range(self.total_ports): self.stim.gen_constant(sig_name="CSB{0}".format(port), v_val=self.vdd_voltage) - if port in self.write_ports and port in self.read_ports: + if port in self.write_index and port in self.read_index: self.stim.gen_constant(sig_name="WEB{0}".format(port), v_val=self.vdd_voltage) self.sf.write("\n* Generation of global clock signal\n") - for port in range(self.total_port_num): + for port in range(self.total_ports): self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) self.write_power_measures() @@ -257,10 +214,10 @@ class delay(): trig_name = trig_clk_name if 'lh' in delay_name: targ_dir="RISE" - trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]] + trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read1"]] else: targ_dir="FALL" - trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]] + trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]] elif 'slew' in delay_name: trig_name = targ_name @@ -268,12 +225,12 @@ class delay(): trig_val = trig_slew_low targ_val = targ_slew_high targ_dir = trig_dir = "RISE" - trig_td = targ_td = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]] + trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read1"]] else: trig_val = targ_slew_high targ_val = trig_slew_low targ_dir = trig_dir = "FALL" - trig_td = targ_td = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]] + trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]] else: debug.error(1, "Measure command {0} not recognized".format(delay_name)) return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td) @@ -294,11 +251,11 @@ class delay(): #Different naming schemes are used for the measure cycle dict and measurement names. #TODO: make them the same so they can be indexed the same. if '1' in pname: - t_initial = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]] - t_final = self.cycle_times[self.measure_cycles["read1_{0}".format(port)]+1] + t_initial = self.cycle_times[self.measure_cycles[port]["read1"]] + t_final = self.cycle_times[self.measure_cycles[port]["read1"]+1] elif '0' in pname: - t_initial = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]] - t_final = self.cycle_times[self.measure_cycles["read0_{0}".format(port)]+1] + t_initial = self.cycle_times[self.measure_cycles[port]["read0"]] + t_final = self.cycle_times[self.measure_cycles[port]["read0"]+1] self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port), t_initial=t_initial, t_final=t_final) @@ -311,11 +268,11 @@ class delay(): for pname in self.power_meas_names: if "write" not in pname: continue - t_initial = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]] - t_final = self.cycle_times[self.measure_cycles["write0_{0}".format(port)]+1] + t_initial = self.cycle_times[self.measure_cycles[port]["write0"]] + t_final = self.cycle_times[self.measure_cycles[port]["write0"]+1] if '1' in pname: - t_initial = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]] - t_final = self.cycle_times[self.measure_cycles["write1_{0}".format(port)]+1] + t_initial = self.cycle_times[self.measure_cycles[port]["write1"]] + t_final = self.cycle_times[self.measure_cycles[port]["write1"]+1] self.stim.gen_meas_power(meas_name="{0}{1}".format(pname, port), t_initial=t_initial, @@ -360,10 +317,9 @@ class delay(): double the period until we find a valid period to use as a starting point. """ - debug.check(port in self.read_ports, "Characterizer requires a read port to determine a period.") + debug.check(port in self.read_index, "Characterizer requires a read port to determine a period.") feasible_period = float(tech.spice["feasible_period"]) - #feasible_period = float(2.5)#What happens if feasible starting point is wrong? time_out = 9 while True: time_out -= 1 @@ -406,19 +362,18 @@ class delay(): Loops through all read ports determining the feasible period and collecting delay information from each port. """ - feasible_delays = [{} for i in range(self.total_port_num)] - self.period = float(tech.spice["feasible_period"]) + feasible_delays = [{} for i in range(self.total_ports)] #Get initial feasible delays from first port - feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0]) + feasible_delays[self.read_index[0]] = self.find_feasible_period_one_port(self.read_index[0]) previous_period = self.period #Loops through all the ports checks if the feasible period works. Everything restarts it if does not. #Write ports do not produce delays which is why they are not included here. i = 1 - while i < len(self.read_ports): - port = self.read_ports[i] + while i < len(self.read_index): + port = self.read_index[i] #Only extract port values from the specified port, not the entire results. feasible_delays[port].update(self.find_feasible_period_one_port(port)) #Function sets the period. Restart the entire process if period changes to collect accurate delays @@ -461,7 +416,7 @@ class delay(): #Sanity Check debug.check(self.period > 0, "Target simulation period non-positive") - result = [{} for i in range(self.total_port_num)] + result = [{} for i in range(self.total_ports)] # Checking from not data_value to data_value self.write_delay_stimulus() @@ -563,7 +518,7 @@ class delay(): #Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position. #For testing purposes, only checks read ports. - for port in self.read_ports: + for port in self.read_index: target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period) #The min period of one port becomes the new lower bound. Reset the upper_bound. lb_period = target_period @@ -728,8 +683,8 @@ class delay(): """Simulate all specified output loads and input slews pairs of all ports""" measure_data = self.get_empty_measure_data_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 + self.targ_read_ports = self.read_index + self.targ_write_ports = self.write_index for slew in slews: for load in loads: self.set_load_slew(load,slew) @@ -738,7 +693,7 @@ class delay(): debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load)) #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). - for port in range(self.total_port_num): + for port in range(self.total_ports): for mname,value in delay_results[port].items(): if "power" in mname: # Subtract partial array leakage and add full array leakage for the power measures @@ -746,119 +701,8 @@ class delay(): else: measure_data[port][mname].append(value) return measure_data - - def add_data(self, data, port): - """ Add the array of data values """ - debug.check(len(data)==self.word_size, "Invalid data word size.") - debug.check(port < len(self.data_values), "Port number cannot index data values.") - index = 0 - for c in data: - if c=="0": - self.data_values[port][index].append(0) - elif c=="1": - self.data_values[port][index].append(1) - else: - debug.error("Non-binary data string",1) - index += 1 - - def add_address(self, address, port): - """ Add the array of address values """ - debug.check(len(address)==self.addr_size, "Invalid address size.") - index = 0 - for c in address: - if c=="0": - self.addr_values[port][index].append(0) - elif c=="1": - self.addr_values[port][index].append(1) - else: - debug.error("Non-binary address string",1) - index += 1 - def add_noop_one_port(self, address, data, port): - """ Add the control values for a noop to a single port. """ - #This is to be used as a helper function for the other add functions. Cycle and comments are omitted. - self.add_control_one_port(port, "noop") - if port in self.write_ports: - self.add_data(data,port) - self.add_address(address, port) - - def add_noop_all_ports(self, comment, address, data): - """ Add the control values for a noop to all ports. """ - self.add_comment("All", comment) - self.cycle_times.append(self.t_current) - self.t_current += self.period - - for port in range(self.total_port_num): - self.add_noop_one_port(address, data, port) - - - def add_read(self, comment, address, data, port): - """ Add the control values for a read cycle. """ - debug.check(port in self.read_ports, "Cannot add read cycle to a write port.") - self.add_comment(port, comment) - self.cycle_times.append(self.t_current) - self.t_current += self.period - self.add_control_one_port(port, "read") - - #If the port is also a readwrite then add data. - if port in self.write_ports: - self.add_data(data,port) - self.add_address(address, port) - - #This value is hard coded here. Possibly change to member variable or set in add_noop_one_port - noop_data = "0"*self.word_size - #Add noops to all other ports. - for unselected_port in range(self.total_port_num): - if unselected_port != port: - self.add_noop_one_port(address, noop_data, unselected_port) - def add_write(self, comment, address, data, port): - """ Add the control values for a write cycle. """ - debug.check(port in self.write_ports, "Cannot add read cycle to a read port.") - self.add_comment(port, comment) - self.cycle_times.append(self.t_current) - self.t_current += self.period - - self.add_control_one_port(port, "write") - self.add_data(data,port) - self.add_address(address,port) - - #This value is hard coded here. Possibly change to member variable or set in add_noop_one_port - noop_data = "0"*self.word_size - #Add noops to all other ports. - for unselected_port in range(self.total_port_num): - if unselected_port != port: - self.add_noop_one_port(address, noop_data, unselected_port) - - def add_control_one_port(self, port, op): - """Appends control signals for operation to a given port""" - #Determine values to write to port - web_val = 1 - csb_val = 1 - if op == "read": - csb_val = 0 - elif op == "write": - csb_val = 0 - web_val = 0 - elif op != "noop": - debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port,op),1) - - #Append the values depending on the type of port - self.csb_values[port].append(csb_val) - #If port is in both lists, add rw control signal. Condition indicates its a RW port. - if port in self.write_ports and port in self.read_ports: - self.web_values[port].append(web_val) - - def add_comment(self, port, comment): - """Add comment to list to be printed in stimulus file""" - #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), - port, - time, - time_spacing, - comment)) def gen_test_cycles_one_port(self, read_port, write_port): """Intended but not implemented: Returns a list of key time-points [ns] of the waveform (each rising edge) of the cycles to do a timing evaluation of a single port. Current: Values overwritten for multiple calls""" @@ -886,8 +730,7 @@ class delay(): self.add_write("W data 0 address 11..11 to write value", self.probe_address,data_zeros,write_port) - self.measure_cycles["write0_{0}".format(write_port)] = len(self.cycle_times)-1 - #self.write0_cycle=len(self.cycle_times)-1 # Remember for power measure + self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1 # This also ensures we will have a H->L transition on the next read self.add_read("R data 1 address 00..00 to set DOUT caps", @@ -895,18 +738,14 @@ class delay(): self.add_read("R data 0 address 11..11 to check W0 worked", self.probe_address,data_zeros,read_port) - self.measure_cycles["read0_{0}".format(read_port)] = len(self.cycle_times)-1 - #self.read0_cycle=len(self.cycle_times)-1 # Remember for power measure + self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1 self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)", inverse_address,data_zeros) - #Does not seem like is is used anywhere commenting out for now. - #self.idle_cycle=len(self.cycle_times)-1 # Remember for power measure self.add_write("W data 1 address 11..11 to write value", self.probe_address,data_ones,write_port) - self.measure_cycles["write1_{0}".format(write_port)] = len(self.cycle_times)-1 - #self.write1_cycle=len(self.cycle_times)-1 # Remember for power measure + self.measure_cycles[write_port]["write1"] = len(self.cycle_times)-1 self.add_write("W data 0 address 00..00 to clear DIN caps", inverse_address,data_zeros,write_port) @@ -917,19 +756,22 @@ class delay(): self.add_read("R data 1 address 11..11 to check W1 worked", self.probe_address,data_zeros,read_port) - self.measure_cycles["read1_{0}".format(read_port)] = len(self.cycle_times)-1 - #self.read1_cycle=len(self.cycle_times)-1 # Remember for power measure + self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1 self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))", self.probe_address,data_zeros) def get_available_port(self,get_read_port): """Returns the first accessible read or write port. """ - if get_read_port and len(self.read_ports) > 0: - return self.read_ports[0] - elif not get_read_port and len(self.write_ports) > 0: - return self.write_ports[0] + if get_read_port and len(self.read_index) > 0: + return self.read_index[0] + elif not get_read_port and len(self.write_index) > 0: + return self.write_index[0] return None + + def set_stimulus_variables(self): + simulation.set_stimulus_variables(self) + self.measure_cycles = [{} for port in range(self.total_ports)] def create_test_cycles(self): """Returns a list of key time-points [ns] of the waveform (each rising edge) @@ -937,35 +779,16 @@ class delay(): and does not need a rising edge.""" #Using this requires setting at least one port to target for simulation. if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: - debug.error("No ports selected for characterization.",1) - - # Start at time 0 - self.t_current = 0 - - # Cycle times (positive edge) with comment - self.cycle_comments = [] - self.cycle_times = [] - self.measure_cycles = {} - - # Control signals for ports. These are not the final signals and will likely be changed later. - #web is the enable for write ports. Dicts used for simplicity as ports are not necessarily incremental. - self.web_values = {port:[] for port in self.write_ports} - #csb acts as an enable for the read ports. - self.csb_values = {port:[] for port in range(self.total_port_num)} - - # Address and data values for each address/data bit. A 3d list of size #ports x bits x cycles. - self.data_values=[[[] for bit in range(self.word_size)] for port in range(len(self.write_ports))] - self.addr_values=[[[] for bit in range(self.addr_size)] for port in range(self.total_port_num)] - + debug.error("No port selected for characterization.",1) + self.set_stimulus_variables() + #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) - - #These checks should be superceded by check_arguments which should have been called earlier, so this is a double check. debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") - #Characterizing the remaining target ports. Not the final design. + #Create test cycles for specified target ports. write_pos = 0 read_pos = 0 while True: @@ -997,7 +820,7 @@ class delay(): for slew in slews: for load in loads: self.set_load_slew(load,slew) - bank_delay = sram.analytical_delay(self.slew,self.load) + bank_delay = sram.analytical_delay(self.vdd_voltage, self.slew,self.load) # Convert from ps to ns delay_lh.append(bank_delay.delay/1e3) delay_hl.append(bank_delay.delay/1e3) @@ -1026,7 +849,7 @@ class delay(): def gen_data(self): """ Generates the PWL data inputs for a simulation timing test. """ - for write_port in self.write_ports: + for write_port in self.write_index: for i in range(self.word_size): sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i) self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05) @@ -1036,16 +859,16 @@ class delay(): Generates the address inputs for a simulation timing test. This alternates between all 1's and all 0's for the address. """ - for port in range(self.total_port_num): + for port in range(self.total_ports): for i in range(self.addr_size): sig_name = "{0}{1}_{2}".format(self.addr_name,port,i) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05) def gen_control(self): """ Generates the control signals """ - for port in range(self.total_port_num): + for port in range(self.total_ports): 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.read_ports and port in self.write_ports: + if port in self.read_index and port in self.write_index: self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05) @@ -1053,5 +876,5 @@ class delay(): """Make a dict of lists for each type of delay and power measurement to append results to""" measure_names = self.delay_meas_names + self.power_meas_names #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. - measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_port_num)] + measure_data = [{mname:[] for mname in measure_names} for i in range(self.total_ports)] return measure_data diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index b2c88d08..ab232843 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -266,7 +266,7 @@ class functional(simulation): t_intital=t_intital, t_final=t_final) - self.stim.write_control(self.cycle_times[-1] + self.period) + self.stim.write_control(self.cycle_times[-1] + self.period, runlvl=1) self.sf.close() diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 436ee301..7ae25b73 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -17,7 +17,8 @@ class lib: self.sram = sram self.sp_file = sp_file self.use_model = use_model - self.gen_port_names() #copy and paste from delay.py, names are not final will likely be changed later. + #self.gen_port_names() #copy and paste from delay.py, names are not final will likely be changed later. + self.set_port_indices() self.prepare_tables() @@ -25,7 +26,10 @@ class lib: self.characterize_corners() - + def set_port_indices(self): + self.total_port_num = self.sram.total_ports + self.read_ports = self.sram.read_index + self.write_ports = self.sram.write_index def gen_port_names(self): """Generates the port names to be written to the lib file""" @@ -108,21 +112,21 @@ class lib: self.write_header() - #Loop over all readwrite ports. This is debugging. Will change later. + #Loop over all ports. for port in range(self.total_port_num): #set the read and write port as inputs. self.write_data_bus(port) self.write_addr_bus(port) self.write_control_pins(port) #need to split this into sram and port control signals - - self.write_clk_timing_power() + self.write_clk_timing_power(port) self.write_footer() def write_footer(self): """ Write the footer """ - self.lib.write("}\n") + self.lib.write(" }\n") #Closing brace for the cell + self.lib.write("}\n") #Closing brace for the library def write_header(self): """ Write the header information """ @@ -151,7 +155,7 @@ class lib: self.lib.write(" dont_touch : true;\n") self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height)) - #Build string of all control signals. This is subject to change once control signals finalized. + #Build string of all control signals. control_str = 'CSb0' #assume at least 1 port for i in range(1, self.total_port_num): control_str += ' & CSb{0}'.format(i) @@ -296,12 +300,12 @@ class lib: self.lib.write(" }\n\n") - def write_FF_setuphold(self): + def write_FF_setuphold(self, port): """ Adds Setup and Hold timing results""" self.lib.write(" timing(){ \n") self.lib.write(" timing_type : setup_rising; \n") - self.lib.write(" related_pin : \"clk\"; \n") + self.lib.write(" related_pin : \"clk{0}\"; \n".format(port)) self.lib.write(" rise_constraint(CONSTRAINT_TABLE) {\n") rounded_values = list(map(round_time,self.times["setup_times_LH"])) self.write_values(rounded_values,len(self.slews)," ") @@ -313,7 +317,7 @@ class lib: self.lib.write(" }\n") self.lib.write(" timing(){ \n") self.lib.write(" timing_type : hold_rising; \n") - self.lib.write(" related_pin : \"clk\"; \n") + self.lib.write(" related_pin : \"clk{0}\"; \n".format(port)) self.lib.write(" rise_constraint(CONSTRAINT_TABLE) {\n") rounded_values = list(map(round_time,self.times["hold_times_LH"])) self.write_values(rounded_values,len(self.slews)," ") @@ -339,10 +343,9 @@ class lib: self.lib.write(" pin(DOUT{1}[{0}:0]){{\n".format(self.sram.word_size - 1, read_port)) - self.write_FF_setuphold() self.lib.write(" timing(){ \n") self.lib.write(" timing_sense : non_unate; \n") - self.lib.write(" related_pin : \"clk\"; \n") + self.lib.write(" related_pin : \"clk{0}\"; \n".format(read_port)) self.lib.write(" timing_type : rising_edge; \n") self.lib.write(" cell_rise(CELL_TABLE) {\n") self.write_values(self.char_port_results[read_port]["delay_lh"],len(self.loads)," ") @@ -361,7 +364,7 @@ class lib: self.lib.write(" }\n\n") # bus def write_data_bus_input(self, write_port): - """ Adds data bus timing results.""" + """ Adds DIN data bus timing results.""" self.lib.write(" bus(DIN{0}){{\n".format(write_port)) self.lib.write(" bus_type : DATA; \n") @@ -370,9 +373,12 @@ class lib: self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) self.lib.write(" memory_write(){ \n") self.lib.write(" address : ADDR{0}; \n".format(write_port)) - self.lib.write(" clocked_on : clk; \n") - self.lib.write(" }\n") - self.lib.write(" }\n") + self.lib.write(" clocked_on : clk{0}; \n".format(write_port)) + self.lib.write(" }\n") + self.lib.write(" pin(DIN{1}[{0}:0]){{\n".format(self.sram.word_size - 1, write_port)) + self.write_FF_setuphold(write_port) + self.lib.write(" }\n") # pin + self.lib.write(" }\n") #bus def write_data_bus(self, port): """ Adds data bus timing results.""" @@ -392,7 +398,7 @@ class lib: self.lib.write(" pin(ADDR{1}[{0}:0])".format(self.sram.addr_size - 1, port)) self.lib.write("{\n") - self.write_FF_setuphold() + self.write_FF_setuphold(port) self.lib.write(" }\n") self.lib.write(" }\n\n") @@ -409,28 +415,25 @@ class lib: self.lib.write("{\n") self.lib.write(" direction : input; \n") self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) - self.write_FF_setuphold() + self.write_FF_setuphold(port) self.lib.write(" }\n\n") - def write_clk_timing_power(self): + def write_clk_timing_power(self, port): """ Adds clk pin timing results.""" - self.lib.write(" pin(clk){\n") + self.lib.write(" pin(clk{0}){{\n".format(port)) self.lib.write(" clock : true;\n") self.lib.write(" direction : input; \n") # FIXME: This depends on the clock buffer size in the control logic self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"])) - #Add power values for the ports. lib generated with this is not syntactically correct. TODO once - #top level is done. - for port in range(self.total_port_num): - self.add_clk_control_power(port) + self.add_clk_control_power(port) min_pulse_width = round_time(self.char_sram_results["min_period"])/2.0 min_period = round_time(self.char_sram_results["min_period"]) self.lib.write(" timing(){ \n") self.lib.write(" timing_type :\"min_pulse_width\"; \n") - self.lib.write(" related_pin : clk; \n") + self.lib.write(" related_pin : clk{0}; \n".format(port)) self.lib.write(" rise_constraint(scalar) {\n") self.lib.write(" values(\"{0}\"); \n".format(min_pulse_width)) self.lib.write(" }\n") @@ -440,7 +443,7 @@ class lib: self.lib.write(" }\n") self.lib.write(" timing(){ \n") self.lib.write(" timing_type :\"minimum_period\"; \n") - self.lib.write(" related_pin : clk; \n") + self.lib.write(" related_pin : clk{0}; \n".format(port)) self.lib.write(" rise_constraint(scalar) {\n") self.lib.write(" values(\"{0}\"); \n".format(min_period)) self.lib.write(" }\n") @@ -448,8 +451,7 @@ class lib: self.lib.write(" values(\"{0}\"); \n".format(min_period)) self.lib.write(" }\n") self.lib.write(" }\n") - self.lib.write(" }\n") - self.lib.write(" }\n") + self.lib.write(" }\n\n") def add_clk_control_power(self, port): """Writes powers under the clock pin group for a specified port""" @@ -461,7 +463,7 @@ class lib: web_name = " & !WEb{0}".format(port) avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!CSb{0} & clk{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!CSb{0} & clk{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0)) self.lib.write(" }\n") @@ -475,7 +477,7 @@ class lib: web_name = " & WEb{0}".format(port) avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!CSb{0} & !clk{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!CSb{0} & !clk{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0)) self.lib.write(" }\n") diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index d568e112..43ce75a5 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -58,6 +58,7 @@ class simulation(): # For generating comments in SPICE stimulus self.cycle_comments = [] + self.fn_cycle_comments = [] def add_control_one_port(self, port, op): """Appends control signals for operation to a given port""" @@ -81,7 +82,6 @@ class simulation(): def add_data(self, data, port): """ Add the array of data values """ debug.check(len(data)==self.word_size, "Invalid data word size.") - #debug.check(port < len(self.data_values), "Port number cannot index data values.") bit = self.word_size - 1 for c in data: @@ -111,8 +111,10 @@ class simulation(): """ Add the control values for a write cycle. """ debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index)) comment = self.gen_cycle_comment("write", data, address, port, self.t_current) - debug.info(1, comment) - self.cycle_comments.append(comment) + debug.info(2, comment) + self.fn_cycle_comments.append(comment) + + self.append_cycle_comment(port, comment) self.cycle_times.append(self.t_current) self.t_current += self.period @@ -132,9 +134,11 @@ class simulation(): """ Add the control values for a read cycle. """ debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index)) comment = self.gen_cycle_comment("read", dout_data, address, port, self.t_current) - debug.info(1, comment) - self.cycle_comments.append(comment) + debug.info(2, comment) + self.fn_cycle_comments.append(comment) + self.append_cycle_comment(port, comment) + self.cycle_times.append(self.t_current) self.t_current += self.period self.add_control_one_port(port, "read") @@ -154,9 +158,11 @@ class simulation(): def add_noop_all_ports(self, address, data): """ Add the control values for a noop to all ports. """ comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current) - debug.info(1, comment) - self.cycle_comments.append(comment) + debug.info(2, comment) + self.fn_cycle_comments.append(comment) + self.append_cycle_comment("All", comment) + self.cycle_times.append(self.t_current) self.t_current += self.period @@ -167,8 +173,8 @@ class simulation(): """ Add the control values for a write cycle. Does not increment the period. """ debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index)) comment = self.gen_cycle_comment("write", data, address, port, self.t_current) - debug.info(1, comment) - self.cycle_comments.append(comment) + debug.info(2, comment) + self.fn_cycle_comments.append(comment) self.add_control_one_port(port, "write") self.add_data(data,port) @@ -178,8 +184,8 @@ class simulation(): """ Add the control values for a read cycle. Does not increment the period. """ debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index)) comment = self.gen_cycle_comment("read", dout_data, address, port, self.t_current) - debug.info(1, comment) - self.cycle_comments.append(comment) + debug.info(2, comment) + self.fn_cycle_comments.append(comment) self.add_control_one_port(port, "read") #If the port is also a readwrite then add data. @@ -193,6 +199,17 @@ class simulation(): if port in self.write_index: self.add_data(data,port) self.add_address(address, 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. + 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), + port, + time, + time_spacing, + comment)) def gen_cycle_comment(self, op, word, addr, port, t_current): if op == "noop": diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 14f780c2..6fa7a481 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -232,8 +232,19 @@ class stimuli(): measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name, dout, t_intital, t_final) self.sf.write(measure_string) - def write_control(self, end_time): + def write_control(self, end_time, runlvl=4): """ Write the control cards to run and end the simulation """ + + # These are guesses... + if runlvl==1: + reltol = 0.02 # 2% + elif runlvl==2: + reltol = 0.01 # 1% + elif runlvl==3: + reltol = 0.005 # 0.5% + else: + reltol = 0.001 # 0.1% + # UIC is needed for ngspice to converge self.sf.write(".TRAN 5p {0}n UIC\n".format(end_time)) if OPTS.spice_name == "ngspice": @@ -241,9 +252,9 @@ class stimuli(): # which is more accurate, but slower than the default trapezoid method # Do not remove this or it may not converge due to some "pa_00" nodes # unless you figure out what these are. - self.sf.write(".OPTIONS POST=1 RUNLVL=4 PROBE method=gear TEMP={}\n".format(self.temperature)) + self.sf.write(".OPTIONS POST=1 RELTOL={0} PROBE method=gear TEMP={1}\n".format(reltol,self.temperature)) else: - self.sf.write(".OPTIONS POST=1 RUNLVL=4 PROBE TEMP={}\n".format(self.temperature)) + self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE TEMP={1}\n".format(runlvl,self.temperature)) # create plots for all signals self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index 3518fac0..a33df26c 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -111,6 +111,7 @@ class trim_spice(): match of the line with a term so you can search for a single net connection, the instance name, anything.. """ + removed_insts = 0 #Expects keep_inst_list are regex patterns. Compile them here. compiled_patterns = [re.compile(pattern) for pattern in keep_inst_list] @@ -127,11 +128,14 @@ class trim_spice(): new_buffer.append(line) in_subckt=False elif in_subckt: + removed_insts += 1 for pattern in compiled_patterns: if pattern.search(line) != None: new_buffer.append(line) + removed_insts -= 1 break else: new_buffer.append(line) self.sp_buffer = new_buffer + debug.info(2, "Removed {} instances from {} subcircuit.".format(removed_insts, subckt_name)) diff --git a/compiler/characterizer/worst_case.py b/compiler/characterizer/worst_case.py new file mode 100644 index 00000000..6dad95d9 --- /dev/null +++ b/compiler/characterizer/worst_case.py @@ -0,0 +1,77 @@ +import sys,re,shutil +import debug +import tech +import math +from .stimuli import * +from .trim_spice import * +from .charutils import * +import utils +from globals import OPTS +from .delay import delay + +class worst_case(delay): + """Functions to test for the worst case delay in a target SRAM + + The current worst case determines a feasible period for the SRAM then tests + several bits and record the delay and differences between the bits. + + """ + + def __init__(self, sram, spfile, corner): + delay.__init__(self,sram,spfile,corner) + + + def analyze(self,probe_address, probe_data, slews, loads): + """ + Main function to test the delays of different bits. + """ + debug.check(OPTS.num_rw_ports < 2 and OPTS.num_w_ports < 1 and OPTS.num_r_ports < 1 , + "Bit testing does not currently support multiport.") + #Dict to hold all characterization values + char_sram_data = {} + + self.set_probe(probe_address, probe_data) + #self.prepare_netlist() + + self.load=max(loads) + self.slew=max(slews) + + # 1) Find a feasible period and it's corresponding delays using the trimmed array. + feasible_delays = self.find_feasible_period() + + # 2) Find the delays of several bits + test_bits = self.get_test_bits() + bit_delays = self.simulate_for_bit_delays(test_bits) + + for i in range(len(test_bits)): + debug.info(1, "Bit tested: addr {0[0]} data_pos {0[1]}\n Values {1}".format(test_bits[i], bit_delays[i])) + + def simulate_for_bit_delays(self, test_bits): + """Simulates the delay of the sram of over several bits.""" + bit_delays = [{} for i in range(len(test_bits))] + + #Assumes a bitcell with only 1 rw port. (6t, port 0) + port = 0 + self.targ_read_ports = [self.read_ports[port]] + self.targ_write_ports = [self.write_ports[port]] + + for i in range(len(test_bits)): + (bit_addr, bit_data) = test_bits[i] + self.set_probe(bit_addr, bit_data) + debug.info(1,"Delay bit test: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data)) + (success, results)=self.run_delay_simulation() + debug.check(success, "Bit Test Failed: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data)) + bit_delays[i] = results[port] + + return bit_delays + + + def get_test_bits(self): + """Statically determines address and bit values to test""" + #First and last address, first middle, and last bit. Last bit is repeated twice with different data position. + bit_addrs = ["0"*self.addr_size, "0"+"1"*(self.addr_size-1), "1"*self.addr_size, "1"*self.addr_size] + data_positions = [0, (self.word_size-1)//2, 0, self.word_size-1] + #Return them in a tuple form + return [(bit_addrs[i], data_positions[i]) for i in range(len(bit_addrs))] + + diff --git a/compiler/example_config_freepdk45.py b/compiler/example_config_freepdk45.py index e9e753b9..5e7a689f 100644 --- a/compiler/example_config_freepdk45.py +++ b/compiler/example_config_freepdk45.py @@ -1,6 +1,5 @@ word_size = 2 num_words = 16 -num_banks = 1 tech_name = "freepdk45" process_corners = ["TT"] diff --git a/compiler/example_config_scn4m_subm.py b/compiler/example_config_scn4m_subm.py index 9aa8e498..436d0ffd 100644 --- a/compiler/example_config_scn4m_subm.py +++ b/compiler/example_config_scn4m_subm.py @@ -1,6 +1,5 @@ word_size = 2 num_words = 16 -num_banks = 1 tech_name = "scn4m_subm" process_corners = ["TT"] @@ -9,3 +8,11 @@ temperatures = [ 25 ] output_path = "temp" output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name) + +#Setting for multiport +netlist_only = True +bitcell = "pbitcell" +replica_bitcell="replica_pbitcell" +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 1 \ No newline at end of file diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index ea20a276..f6d301a1 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -155,10 +155,10 @@ class VlsiLayout: def traverseTheHierarchy(self, startingStructureName=None, delegateFunction = None, transformPath = [], rotateAngle = 0, transFlags = [0,0,0], coordinates = (0,0)): #since this is a recursive function, must deal with the default - #parameters explicitly + #parameters explicitly if startingStructureName == None: startingStructureName = self.rootStructureName - + #set up the rotation matrix if(rotateAngle == None or rotateAngle == ""): angle = 0 diff --git a/compiler/globals.py b/compiler/globals.py index 5b2ab2b3..0b04079b 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -24,7 +24,7 @@ def parse_args(): global OPTS option_list = { - optparse.make_option("-b", "--backannotated", action="store_true", dest="run_pex", + optparse.make_option("-b", "--backannotated", action="store_true", dest="use_pex", help="Back annotate simulation"), optparse.make_option("-o", "--output", dest="output_name", help="Base output file name(s) prefix", metavar="FILE"), diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 9ef7a2c1..0fb6be60 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -925,7 +925,7 @@ class bank(design.design): rotate=90) - def analytical_delay(self, slew, load): + def analytical_delay(self, vdd, slew, load): """ return analytical delay of the bank""" decoder_delay = self.row_decoder.analytical_delay(slew, self.wordline_driver.input_load()) @@ -933,10 +933,17 @@ class bank(design.design): bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew) - bl_t_data_out_delay = self.sense_amp_array.analytical_delay(bitcell_array_delay.slew, + if self.words_per_row > 1: + port = 0 #Analytical delay only supports single port + column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew, + self.sense_amp_array.input_load()) + else: + column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew) + + bl_t_data_out_delay = self.sense_amp_array.analytical_delay(column_mux_delay.slew, self.bitcell_array.output_load()) # output load of bitcell_array is set to be only small part of bl for sense amp. - result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + result = decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay return result diff --git a/compiler/modules/sense_amp.py b/compiler/modules/sense_amp.py index 45a195fc..6187b37a 100644 --- a/compiler/modules/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -23,6 +23,11 @@ class sense_amp(design.design): self.height = sense_amp.height self.pin_map = sense_amp.pin_map + def input_load(self): + #Input load for the bitlines which are connected to the source/drain of a TX. Not the selects. + bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file. + return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff + def analytical_delay(self, slew, load=0.0): from tech import spice r = spice["min_tx_r"]/(10) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 32efaeb5..1bbbf02e 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -134,6 +134,9 @@ class sense_amp_array(design.design): width=self.width, height=drc("minwidth_metal1")) + def input_load(self): + return self.amp.input_load() + def analytical_delay(self, slew, load=0.0): return self.amp.analytical_delay(slew=slew, load=load) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 120a9c1d..a74f8514 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -217,5 +217,13 @@ class single_level_column_mux_array(design.design): offset= br_out_offset, rotate=90) - + def analytical_delay(self, vdd, slew, load=0.0): + from tech import spice + r = spice["min_tx_r"]/(self.mux.ptx_width/parameter["min_tx_size"]) + #Drains of mux transistors make up capacitance. + c_para = spice["min_tx_drain_c"]*(self.mux.ptx_width/parameter["min_tx_size"])*self.words_per_row#ff + volt_swing = spice["v_threshold_typical"]/vdd + + result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = volt_swing) + return self.return_delay(result.delay, result.slew) diff --git a/compiler/sram.py b/compiler/sram.py index 59b7d7e8..1b6b104f 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -61,6 +61,21 @@ class sram(): def save(self): """ Save all the output files while reporting time to do it as well. """ + if not OPTS.netlist_only: + # Write the layout + start_time = datetime.datetime.now() + gdsname = OPTS.output_path + self.s.name + ".gds" + print("GDS: Writing to {0}".format(gdsname)) + self.s.gds_write(gdsname) + print_time("GDS", datetime.datetime.now(), start_time) + + # Create a LEF physical model + start_time = datetime.datetime.now() + lefname = OPTS.output_path + self.s.name + ".lef" + print("LEF: Writing to {0}".format(lefname)) + self.s.lef_write(lefname) + print_time("LEF", datetime.datetime.now(), start_time) + # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" @@ -70,6 +85,7 @@ class sram(): # Save the extracted spice file if OPTS.use_pex: + import verify start_time = datetime.datetime.now() # Output the extracted design if requested sp_file = OPTS.output_path + "temp_pex.sp" @@ -92,21 +108,6 @@ class sram(): print("Trimming netlist to speed up characterization.") lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file) print_time("Characterization", datetime.datetime.now(), start_time) - - if not OPTS.netlist_only: - # Write the layout - start_time = datetime.datetime.now() - gdsname = OPTS.output_path + self.s.name + ".gds" - print("GDS: Writing to {0}".format(gdsname)) - self.s.gds_write(gdsname) - print_time("GDS", datetime.datetime.now(), start_time) - - # Create a LEF physical model - start_time = datetime.datetime.now() - lefname = OPTS.output_path + self.s.name + ".lef" - print("LEF: Writing to {0}".format(lefname)) - self.s.lef_write(lefname) - print_time("LEF", datetime.datetime.now(), start_time) # Write the datasheet start_time = datetime.datetime.now() diff --git a/compiler/sram_base.py b/compiler/sram_base.py index 32838bda..cc8247ed 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -451,8 +451,8 @@ class sram_base(design): sp.close() - def analytical_delay(self,slew,load): + def analytical_delay(self, vdd, slew,load): """ LH and HL are the same in analytical model. """ - return self.bank.analytical_delay(slew,load) + return self.bank.analytical_delay(vdd,slew,load) diff --git a/compiler/sram_config.py b/compiler/sram_config.py index e7c80fd8..3c3892a5 100644 --- a/compiler/sram_config.py +++ b/compiler/sram_config.py @@ -53,7 +53,7 @@ class sram_config: # Estimate the number of rows given the tentative words per row self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) - + # Fix the number of columns and rows self.num_cols = int(self.words_per_row*self.word_size) self.num_rows = int(self.num_words_per_bank/self.words_per_row) diff --git a/compiler/tests/04_bitcell_1rw_1r_test.py b/compiler/tests/04_bitcell_1rw_1r_test.py new file mode 100755 index 00000000..67db3710 --- /dev/null +++ b/compiler/tests/04_bitcell_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +""" +Run regresion tests on a parameterized bitcell +""" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + +OPTS = globals.OPTS + +@unittest.skip("SKIPPING 04_bitcell_1rw_1r_test") +class bitcell_1rw_1r_test(openram_test): + + def runTest(self): + OPTS.bitcell = "bitcell_1rw_1r" + globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + from bitcell import bitcell + from bitcell_1rw_1r import bitcell_1rw_1r + import tech + OPTS.num_rw_ports=1 + OPTS.num_w_ports=0 + OPTS.num_r_ports=1 + debug.info(2, "Bitcell with 1 read/write and 1 read port") + #tx = bitcell_1rw_1r() + tx = bitcell() + self.local_check(tx) + + globals.end_openram() + + + +# instantiate a copy of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/20_psram_1bank_test.py b/compiler/tests/20_psram_1bank_nomux_test.py similarity index 100% rename from compiler/tests/20_psram_1bank_test.py rename to compiler/tests/20_psram_1bank_nomux_test.py diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py index 7755a2c7..edb344f9 100755 --- a/compiler/tests/26_pex_test.py +++ b/compiler/tests/26_pex_test.py @@ -11,7 +11,7 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 22_sram_pex_test") +@unittest.skip("SKIPPING 26_pex_test") class sram_func_test(openram_test): def runTest(self): diff --git a/compiler/tests/27_worst_case_delay_test.py b/compiler/tests/27_worst_case_delay_test.py new file mode 100755 index 00000000..cf999e45 --- /dev/null +++ b/compiler/tests/27_worst_case_delay_test.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +""" +Run a regression test on various srams +""" + +import unittest +from testutils import header,openram_test +import sys,os +sys.path.append(os.path.join(sys.path[0],"..")) +import globals +from globals import OPTS +import debug + +@unittest.skip("SKIPPING 27_worst_case_delay_test") +class worst_case_timing_sram_test(openram_test): + + def runTest(self): + OPTS.tech_name = "freepdk45" + globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + OPTS.spice_name="hspice" + OPTS.analytical_delay = False + OPTS.trim_netlist = False + OPTS.check_lvsdrc = True + + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import worst_case + if not OPTS.spice_exe: + debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) + + word_size, num_words, num_banks = 2, 16, 1 + from sram import sram + from sram_config import sram_config + c = sram_config(word_size=word_size, + num_words=num_words, + num_banks=num_banks) + c.words_per_row=1 + #c.compute_sizes() + debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format( + word_size, num_words, num_banks)) + s = sram(c, name="sram1") + + sp_netlist_file = OPTS.openram_temp + "temp.sp" + s.sp_write(sp_netlist_file) + + if OPTS.use_pex: + gdsname = OPTS.output_path + s.name + ".gds" + s.gds_write(gdsname) + + import verify + reload(verify) + # Output the extracted design if requested + sp_pex_file = OPTS.output_path + s.name + "_pex.sp" + verify.run_pex(s.name, gdsname, sp_netlist_file, output=sp_pex_file) + sp_sim_file = sp_pex_file + debug.info(1, "Performing spice simulations with backannotated spice file.") + else: + sp_sim_file = sp_netlist_file + debug.info(1, "Performing spice simulations with spice netlist.") + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + wc = worst_case(s.s, sp_sim_file, corner) + import tech + loads = [tech.spice["msflop_in_cap"]*4] + slews = [tech.spice["rise_time"]*2] + probe_address = "1" * s.s.addr_size + probe_data = s.s.word_size - 1 + wc.analyze(probe_address, probe_data, slews, loads) + + globals.end_openram() + +# instantiate a copdsay of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib index 84f301f8..45813c16 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib @@ -78,214 +78,216 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 948.52275; + area : 977.4951374999999; leakage_power () { - when : "CSb"; - value : 0.0021292; + when : "CSb0"; + value : 0.0011164579999999999; } cell_leakage_power : 0; - bus(DIN){ + bus(DIN0){ bus_type : DATA; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR; - clocked_on : clk; + address : ADDR0; + clocked_on : clk0; + } + pin(DIN0[1:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); + } + } } } - bus(DOUT){ + bus(DOUT0){ bus_type : DATA; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR; - } - pin(DOUT[1:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); - } + address : ADDR0; } + pin(DOUT0[1:0]){ timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { - values("0.229, 0.23, 0.234",\ - "0.23, 0.23, 0.234",\ - "0.236, 0.236, 0.24"); + values("0.235, 0.235, 0.239",\ + "0.235, 0.236, 0.24",\ + "0.241, 0.242, 0.246"); } cell_fall(CELL_TABLE) { - values("2.555, 2.556, 2.568",\ - "2.555, 2.557, 2.569",\ - "2.562, 2.563, 2.575"); + values("2.583, 2.585, 2.612",\ + "2.584, 2.585, 2.613",\ + "2.59, 2.592, 2.62"); } rise_transition(CELL_TABLE) { - values("0.02, 0.021, 0.028",\ - "0.02, 0.021, 0.028",\ - "0.02, 0.021, 0.028"); + values("0.022, 0.022, 0.03",\ + "0.022, 0.023, 0.03",\ + "0.022, 0.022, 0.03"); } fall_transition(CELL_TABLE) { - values("0.111, 0.112, 0.115",\ - "0.111, 0.111, 0.115",\ - "0.111, 0.111, 0.116"); + values("0.078, 0.079, 0.083",\ + "0.078, 0.079, 0.083",\ + "0.079, 0.079, 0.083"); } } } } - bus(ADDR){ + bus(ADDR0){ bus_type : ADDR; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR[3:0]){ + pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } } - pin(CSb){ + pin(CSb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } - pin(WEb){ + pin(WEb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb & clk & !WEb"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("0.027431397222222223"); + values("0.03599689694444445"); } fall_power(scalar){ - values("0.027431397222222223"); + values("0.03599689694444445"); } } internal_power(){ - when : "!CSb & !clk & WEb"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("0.026240397222222222"); + values("0.029906643888888886"); } fall_power(scalar){ - values("0.026240397222222222"); + values("0.029906643888888886"); } } internal_power(){ - when : "CSb"; + when : "CSb0"; rise_power(scalar){ values("0"); } @@ -295,7 +297,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("2.422"); } @@ -305,7 +307,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("4.844"); } @@ -314,5 +316,6 @@ cell (sram_2_16_1_freepdk45){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib index 2fbbd8b8..13c6d975 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib @@ -78,96 +78,98 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 948.52275; + area : 977.4951374999999; leakage_power () { - when : "CSb"; - value : 0.000168; + when : "CSb0"; + value : 0.000179; } cell_leakage_power : 0; - bus(DIN){ + bus(DIN0){ bus_type : DATA; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR; - clocked_on : clk; + address : ADDR0; + clocked_on : clk0; + } + pin(DIN0[1:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); + } + } } } - bus(DOUT){ + bus(DOUT0){ bus_type : DATA; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR; - } - pin(DOUT[1:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } + address : ADDR0; } + pin(DOUT0[1:0]){ timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { - values("0.103, 0.104, 0.113",\ - "0.103, 0.104, 0.113",\ - "0.103, 0.104, 0.113"); + values("0.098, 0.098, 0.098",\ + "0.098, 0.098, 0.098",\ + "0.098, 0.098, 0.098"); } cell_fall(CELL_TABLE) { - values("0.103, 0.104, 0.113",\ - "0.103, 0.104, 0.113",\ - "0.103, 0.104, 0.113"); + values("0.098, 0.098, 0.098",\ + "0.098, 0.098, 0.098",\ + "0.098, 0.098, 0.098"); } rise_transition(CELL_TABLE) { - values("0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } fall_transition(CELL_TABLE) { - values("0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } } } } - bus(ADDR){ + bus(ADDR0){ bus_type : ADDR; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR[3:0]){ + pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -181,7 +183,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -196,12 +198,12 @@ cell (sram_2_16_1_freepdk45){ } } - pin(CSb){ + pin(CSb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -215,7 +217,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -229,12 +231,12 @@ cell (sram_2_16_1_freepdk45){ } } - pin(WEb){ + pin(WEb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -248,7 +250,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -262,30 +264,30 @@ cell (sram_2_16_1_freepdk45){ } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb & clk & !WEb"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("0.0739870044551111"); + values("0.0747594982142222"); } fall_power(scalar){ - values("0.0739870044551111"); + values("0.0747594982142222"); } } internal_power(){ - when : "!CSb & !clk & WEb"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("0.0739870044551111"); + values("0.0747594982142222"); } fall_power(scalar){ - values("0.0739870044551111"); + values("0.0747594982142222"); } } internal_power(){ - when : "CSb"; + when : "CSb0"; rise_power(scalar){ values("0"); } @@ -295,7 +297,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("0.0"); } @@ -305,7 +307,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("0"); } @@ -314,5 +316,6 @@ cell (sram_2_16_1_freepdk45){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib index a3ec121c..4d0defaf 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib @@ -78,214 +78,216 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 948.52275; + area : 977.4951374999999; leakage_power () { - when : "CSb"; - value : 0.0021292; + when : "CSb0"; + value : 0.0011164579999999999; } cell_leakage_power : 0; - bus(DIN){ + bus(DIN0){ bus_type : DATA; direction : input; capacitance : 0.2091; memory_write(){ - address : ADDR; - clocked_on : clk; + address : ADDR0; + clocked_on : clk0; + } + pin(DIN0[1:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); + } + } } } - bus(DOUT){ + bus(DOUT0){ bus_type : DATA; direction : output; max_capacitance : 1.6728; min_capacitance : 0.052275; memory_read(){ - address : ADDR; - } - pin(DOUT[1:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); - } + address : ADDR0; } + pin(DOUT0[1:0]){ timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { - values("0.227, 0.227, 0.231",\ - "0.227, 0.228, 0.232",\ - "0.233, 0.234, 0.238"); + values("0.233, 0.233, 0.237",\ + "0.233, 0.234, 0.237",\ + "0.239, 0.24, 0.244"); } cell_fall(CELL_TABLE) { - values("2.555, 2.557, 2.569",\ - "2.556, 2.557, 2.569",\ - "2.562, 2.563, 2.576"); + values("2.584, 2.585, 2.611",\ + "2.584, 2.585, 2.612",\ + "2.591, 2.592, 2.618"); } rise_transition(CELL_TABLE) { - values("0.02, 0.021, 0.028",\ - "0.02, 0.021, 0.028",\ - "0.02, 0.021, 0.028"); + values("0.022, 0.022, 0.03",\ + "0.022, 0.023, 0.03",\ + "0.022, 0.023, 0.03"); } fall_transition(CELL_TABLE) { - values("0.11, 0.11, 0.114",\ - "0.109, 0.11, 0.113",\ - "0.11, 0.11, 0.114"); + values("0.076, 0.077, 0.082",\ + "0.077, 0.077, 0.082",\ + "0.077, 0.077, 0.082"); } } } } - bus(ADDR){ + bus(ADDR0){ bus_type : ADDR; direction : input; capacitance : 0.2091; max_transition : 0.04; - pin(ADDR[3:0]){ + pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } } - pin(CSb){ + pin(CSb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } - pin(WEb){ + pin(WEb0){ direction : input; capacitance : 0.2091; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039",\ + "0.033, 0.033, 0.039"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015",\ - "0.009, 0.009, 0.015"); + values("0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033",\ + "0.027, 0.027, 0.033"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004",\ - "0.002, 0.002, -0.004"); + values("-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022",\ + "-0.01, -0.016, -0.022"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016",\ - "-0.004, -0.004, -0.016"); + values("-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016",\ + "-0.016, -0.016, -0.016"); } } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 0.2091; internal_power(){ - when : "!CSb & clk & !WEb"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("0.025181683333333333"); + values("0.03334771594444444"); } fall_power(scalar){ - values("0.025181683333333333"); + values("0.03334771594444444"); } } internal_power(){ - when : "!CSb & !clk & WEb"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("0.024945991666666667"); + values("0.028457026222222223"); } fall_power(scalar){ - values("0.024945991666666667"); + values("0.028457026222222223"); } } internal_power(){ - when : "CSb"; + when : "CSb0"; rise_power(scalar){ values("0"); } @@ -295,7 +297,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("2.422"); } @@ -305,7 +307,7 @@ cell (sram_2_16_1_freepdk45){ } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("4.844"); } @@ -314,5 +316,6 @@ cell (sram_2_16_1_freepdk45){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C.lib index e6aa54f9..57d36974 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C.lib @@ -314,5 +314,6 @@ cell (sram_2_16_1_scn3me_subm){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_analytical.lib index 8d774ce5..c79394e3 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_analytical.lib @@ -314,5 +314,6 @@ cell (sram_2_16_1_scn3me_subm){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_pruned.lib index b514a858..ff297ad2 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_5p0V_25C_pruned.lib @@ -314,5 +314,6 @@ cell (sram_2_16_1_scn3me_subm){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib index 89f40320..affdf7a9 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib @@ -78,11 +78,11 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 60176.520000000004; + area : 60774.3; leakage_power () { when : "CSb0"; - value : 0.000175; + value : 0.0009813788999999999; } cell_leakage_power : 0; bus(DIN0){ @@ -91,7 +91,37 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; memory_write(){ address : ADDR0; - clocked_on : clk; + clocked_on : clk0; + } + pin(DIN0[1:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); + } + } } } bus(DOUT0){ @@ -103,57 +133,29 @@ cell (sram_2_16_1_scn4m_subm){ address : ADDR0; } pin(DOUT0[1:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { - values("0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268"); + values("1.556, 1.576, 1.751",\ + "1.559, 1.579, 1.754",\ + "1.624, 1.643, 1.819"); } cell_fall(CELL_TABLE) { - values("0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268"); + values("3.445, 3.504, 3.926",\ + "3.448, 3.507, 3.93",\ + "3.49, 3.549, 3.972"); } rise_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.13, 0.169, 0.574",\ + "0.13, 0.169, 0.574",\ + "0.13, 0.169, 0.574"); } fall_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.467, 0.49, 0.959",\ + "0.467, 0.49, 0.959",\ + "0.47, 0.493, 0.96"); } } } @@ -167,30 +169,30 @@ cell (sram_2_16_1_scn4m_subm){ pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } @@ -201,30 +203,30 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } @@ -234,54 +236,54 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk & !WEb0"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("11.3007276371"); + values("9.972790277777777"); } fall_power(scalar){ - values("11.3007276371"); + values("9.972790277777777"); } } internal_power(){ - when : "!CSb0 & !clk & WEb0"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("11.3007276371"); + values("8.899322499999998"); } fall_power(scalar){ - values("11.3007276371"); + values("8.899322499999998"); } } internal_power(){ @@ -295,24 +297,25 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { - values("0.0"); + values("2.344"); } fall_constraint(scalar) { - values("0.0"); + values("2.344"); } } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { - values("0"); + values("4.688"); } fall_constraint(scalar) { - values("0"); + values("4.688"); } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib index 89f40320..bb254713 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib @@ -78,11 +78,11 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 60176.520000000004; + area : 60774.3; leakage_power () { when : "CSb0"; - value : 0.000175; + value : 0.000179; } cell_leakage_power : 0; bus(DIN0){ @@ -91,21 +91,12 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; memory_write(){ address : ADDR0; - clocked_on : clk; + clocked_on : clk0; } - } - bus(DOUT0){ - bus_type : DATA; - direction : output; - max_capacitance : 78.5936; - min_capacitance : 2.45605; - memory_read(){ - address : ADDR0; - } - pin(DOUT0[1:0]){ + pin(DIN0[1:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -119,7 +110,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -131,9 +122,20 @@ cell (sram_2_16_1_scn4m_subm){ "0.001, 0.001, 0.001"); } } + } + } + bus(DOUT0){ + bus_type : DATA; + direction : output; + max_capacitance : 78.5936; + min_capacitance : 2.45605; + memory_read(){ + address : ADDR0; + } + pin(DOUT0[1:0]){ timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { values("0.268, 0.268, 0.268",\ @@ -167,7 +169,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -181,7 +183,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -201,7 +203,7 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -215,7 +217,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -234,7 +236,7 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.009",\ "0.009, 0.009, 0.009",\ @@ -248,7 +250,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("0.001, 0.001, 0.001",\ "0.001, 0.001, 0.001",\ @@ -262,26 +264,26 @@ cell (sram_2_16_1_scn4m_subm){ } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk & !WEb0"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("11.3007276371"); + values("11.3049604371"); } fall_power(scalar){ - values("11.3007276371"); + values("11.3049604371"); } } internal_power(){ - when : "!CSb0 & !clk & WEb0"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("11.3007276371"); + values("11.3049604371"); } fall_power(scalar){ - values("11.3007276371"); + values("11.3049604371"); } } internal_power(){ @@ -295,7 +297,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("0.0"); } @@ -305,7 +307,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("0"); } @@ -314,5 +316,6 @@ cell (sram_2_16_1_scn4m_subm){ } } } + } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib index 8509fc30..2ce6b2e9 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib @@ -78,11 +78,11 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 60176.520000000004; + area : 60774.3; leakage_power () { when : "CSb0"; - value : 0.025716199999999998; + value : 0.0009813788999999999; } cell_leakage_power : 0; bus(DIN0){ @@ -91,7 +91,37 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; memory_write(){ address : ADDR0; - clocked_on : clk; + clocked_on : clk0; + } + pin(DIN0[1:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk0"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114",\ + "-0.065, -0.071, -0.114"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); + } + } } } bus(DOUT0){ @@ -103,57 +133,29 @@ cell (sram_2_16_1_scn4m_subm){ address : ADDR0; } pin(DOUT0[1:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095"); - } - } timing(){ timing_sense : non_unate; - related_pin : "clk"; + related_pin : "clk0"; timing_type : rising_edge; cell_rise(CELL_TABLE) { - values("1.277, 1.297, 1.475",\ - "1.28, 1.3, 1.479",\ - "1.347, 1.367, 1.545"); + values("1.542, 1.562, 1.738",\ + "1.545, 1.565, 1.741",\ + "1.609, 1.629, 1.805"); } cell_fall(CELL_TABLE) { - values("3.217, 3.281, 3.71",\ - "3.22, 3.285, 3.714",\ - "3.261, 3.325, 3.75"); + values("3.446, 3.505, 3.924",\ + "3.45, 3.508, 3.927",\ + "3.491, 3.55, 3.97"); } rise_transition(CELL_TABLE) { - values("0.122, 0.164, 0.579",\ - "0.122, 0.164, 0.578",\ - "0.122, 0.164, 0.58"); + values("0.129, 0.169, 0.573",\ + "0.129, 0.169, 0.573",\ + "0.129, 0.169, 0.573"); } fall_transition(CELL_TABLE) { - values("0.363, 0.396, 0.958",\ - "0.363, 0.396, 0.957",\ - "0.366, 0.399, 0.951"); + values("0.457, 0.481, 0.956",\ + "0.457, 0.481, 0.956",\ + "0.459, 0.483, 0.957"); } } } @@ -167,30 +169,30 @@ cell (sram_2_16_1_scn4m_subm){ pin(ADDR0[3:0]){ timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } @@ -201,30 +203,30 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } @@ -234,54 +236,54 @@ cell (sram_2_16_1_scn4m_subm){ capacitance : 9.8242; timing(){ timing_type : setup_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228",\ - "0.179, 0.173, 0.228"); + values("0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228",\ + "0.167, 0.167, 0.228"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143",\ - "0.125, 0.125, 0.143"); + values("0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137",\ + "0.131, 0.125, 0.137"); } } timing(){ timing_type : hold_rising; - related_pin : "clk"; + related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { values("-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114",\ "-0.065, -0.071, -0.114"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095",\ - "-0.089, -0.089, -0.095"); + values("-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089",\ + "-0.089, -0.089, -0.089"); } } } - pin(clk){ + pin(clk0){ clock : true; direction : input; capacitance : 9.8242; internal_power(){ - when : "!CSb0 & clk & !WEb0"; + when : "!CSb0 & clk0 & !WEb0"; rise_power(scalar){ - values("9.141838916666668"); + values("9.602821763527778"); } fall_power(scalar){ - values("9.141838916666668"); + values("9.602821763527778"); } } internal_power(){ - when : "!CSb0 & !clk & WEb0"; + when : "!CSb0 & !clk0 & WEb0"; rise_power(scalar){ - values("8.304491694444444"); + values("8.647938152416664"); } fall_power(scalar){ - values("8.304491694444444"); + values("8.647938152416664"); } } internal_power(){ @@ -295,7 +297,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type :"min_pulse_width"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("2.344"); } @@ -305,7 +307,7 @@ cell (sram_2_16_1_scn4m_subm){ } timing(){ timing_type :"minimum_period"; - related_pin : clk; + related_pin : clk0; rise_constraint(scalar) { values("4.688"); } @@ -314,5 +316,6 @@ cell (sram_2_16_1_scn4m_subm){ } } } + } } diff --git a/technology/freepdk45/gds_lib/cell_1rw_1r.gds b/technology/freepdk45/gds_lib/cell_1rw_1r.gds new file mode 100644 index 00000000..9f4e0650 Binary files /dev/null and b/technology/freepdk45/gds_lib/cell_1rw_1r.gds differ diff --git a/technology/freepdk45/sp_lib/cell_1rw_1r.sp b/technology/freepdk45/sp_lib/cell_1rw_1r.sp new file mode 100644 index 00000000..483a0b4b --- /dev/null +++ b/technology/freepdk45/sp_lib/cell_1rw_1r.sp @@ -0,0 +1,14 @@ + +.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd +MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1 +MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1 +MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1 +MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1 +MM4 Q_bar wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1 +MM1 Q Q_bar gnd gnd NMOS_VTG W=270.0n L=50n m=1 +MM0 Q_bar Q gnd gnd NMOS_VTG W=270.0n L=50n m=1 +MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1 +MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1 +.ENDS + diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 7d8ee900..6cbeabdd 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -295,6 +295,7 @@ spice["channel"] = drc["minlength_channel"] spice["clk"] = "clk" # analytical delay parameters +spice["v_threshold_typical"] = 0.4 # Typical Threshold voltage in Volts spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2 spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index 149ccc82..d448b5dc 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -240,6 +240,7 @@ spice["clk"] = "clk" # analytical delay parameters # FIXME: These need to be updated for SCMOS, they are copied from FreePDK45. +spice["v_threshold_typical"] = 1.3 # Typical Threshold voltage in Volts spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2 spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms diff --git a/technology/scn4m_subm/mag_lib/cell_1rw_1r.mag b/technology/scn4m_subm/mag_lib/cell_1rw_1r.mag new file mode 100644 index 00000000..7d3823b8 --- /dev/null +++ b/technology/scn4m_subm/mag_lib/cell_1rw_1r.mag @@ -0,0 +1,146 @@ +magic +tech scmos +timestamp 1539900829 +<< nwell >> +rect -18 -1 32 26 +<< pwell >> +rect -18 -51 32 -6 +<< ntransistor >> +rect -6 -18 -4 -12 +rect 2 -24 4 -12 +rect 10 -24 12 -12 +rect 18 -18 20 -12 +rect -6 -36 -4 -28 +rect 2 -36 4 -28 +rect 10 -36 12 -28 +rect 18 -36 20 -28 +<< ptransistor >> +rect 2 5 4 9 +rect 10 5 12 9 +<< ndiffusion >> +rect -11 -14 -6 -12 +rect -7 -18 -6 -14 +rect -4 -18 -3 -12 +rect 1 -20 2 -12 +rect -3 -24 2 -20 +rect 4 -24 5 -12 +rect 9 -24 10 -12 +rect 12 -20 13 -12 +rect 17 -18 18 -12 +rect 20 -14 25 -12 +rect 20 -18 21 -14 +rect 12 -24 17 -20 +rect -11 -30 -6 -28 +rect -7 -34 -6 -30 +rect -11 -36 -6 -34 +rect -4 -36 2 -28 +rect 4 -36 5 -28 +rect 9 -36 10 -28 +rect 12 -36 18 -28 +rect 20 -30 25 -28 +rect 20 -34 21 -30 +rect 20 -36 25 -34 +<< pdiffusion >> +rect 1 5 2 9 +rect 4 5 5 9 +rect 9 5 10 9 +rect 12 5 13 9 +<< ndcontact >> +rect -11 -18 -7 -14 +rect -3 -20 1 -12 +rect 5 -24 9 -12 +rect 13 -20 17 -12 +rect 21 -18 25 -14 +rect -11 -34 -7 -30 +rect 5 -36 9 -28 +rect 21 -34 25 -30 +<< pdcontact >> +rect -3 5 1 9 +rect 5 5 9 9 +rect 13 5 17 9 +<< psubstratepcontact >> +rect 5 -44 9 -40 +<< nsubstratencontact >> +rect 5 19 9 23 +<< polysilicon >> +rect 2 9 4 11 +rect 10 9 12 11 +rect 2 -5 4 5 +rect 10 2 12 5 +rect 11 -2 12 2 +rect -6 -12 -4 -7 +rect 2 -9 3 -5 +rect 2 -12 4 -9 +rect 10 -12 12 -2 +rect 18 -12 20 -7 +rect -6 -20 -4 -18 +rect 18 -20 20 -18 +rect -6 -28 -4 -27 +rect 2 -28 4 -24 +rect 10 -28 12 -24 +rect 18 -28 20 -27 +rect -6 -38 -4 -36 +rect 2 -38 4 -36 +rect 10 -38 12 -36 +rect 18 -38 20 -36 +<< polycontact >> +rect 7 -2 11 2 +rect -10 -11 -6 -7 +rect 3 -9 7 -5 +rect 20 -11 24 -7 +rect -8 -27 -4 -23 +rect 18 -27 22 -23 +<< metal1 >> +rect -18 19 5 23 +rect 9 19 32 23 +rect -18 12 32 16 +rect -10 -7 -6 12 +rect -3 2 0 5 +rect -3 -2 7 2 +rect -3 -12 0 -2 +rect 14 -5 17 5 +rect 7 -9 17 -5 +rect 14 -12 17 -9 +rect 20 -7 24 12 +rect -14 -18 -11 -14 +rect 25 -18 28 -14 +rect 5 -28 9 -24 +rect 5 -40 9 -36 +rect -17 -44 5 -40 +rect 9 -44 31 -40 +rect -17 -51 -4 -47 +rect 0 -51 14 -47 +rect 18 -51 31 -47 +<< m2contact >> +rect 5 19 9 23 +rect 5 5 9 9 +rect -18 -18 -14 -14 +rect -4 -27 0 -23 +rect 28 -18 32 -14 +rect 14 -27 18 -23 +rect -11 -34 -7 -30 +rect 21 -34 25 -30 +rect -4 -51 0 -47 +rect 14 -51 18 -47 +<< metal2 >> +rect -18 -14 -14 23 +rect -18 -51 -14 -18 +rect -11 -30 -7 23 +rect 5 9 9 19 +rect -11 -51 -7 -34 +rect -4 -47 0 -27 +rect 14 -47 18 -27 +rect 21 -30 25 23 +rect 21 -51 25 -34 +rect 28 -14 32 23 +rect 28 -51 32 -18 +<< labels >> +rlabel metal1 7 -49 7 -49 1 wl1 +rlabel psubstratepcontact 7 -42 7 -42 1 gnd +rlabel m2contact 7 21 7 21 5 vdd +rlabel metal1 -1 14 -1 14 1 wl0 +rlabel metal2 -16 -46 -16 -46 2 bl0 +rlabel metal2 -9 -46 -9 -46 1 bl1 +rlabel metal2 23 -46 23 -46 1 br1 +rlabel metal2 30 -46 30 -46 8 br0 +<< end >> diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index b35c3943..0e81953a 100755 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -261,6 +261,7 @@ spice["clk"] = "clk" # analytical delay parameters # FIXME: These need to be updated for SCMOS, they are copied from FreePDK45. +spice["v_threshold_typical"] = 1.3 # Typical Threshold voltage in Volts spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2 spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms