Merge branch 'dev'

This commit is contained in:
Matt Guthaus 2019-09-27 09:50:50 -07:00
commit 062156fbd3
43 changed files with 4730 additions and 334 deletions

View File

@ -164,18 +164,8 @@ If you want to support a enw technology, you will need to create:
+ a setup script for each technology you want to use
+ a technology directory for each technology with the base cells
All setup scripts should be in the setup\_scripts directory under the
$OPENRAM\_TECH directory. We provide two technology examples for
[SCMOS] and [FreePDK45]. Please look at the following file for an
example of what is needed for OpenRAM:
```
$OPENRAM_TECH/setup_scripts/setup_openram_freepdk45.py
```
Each setup script should be named as: setup\_openram\_{tech name}.py.
Each specific technology (e.g., [FreePDK45]) should be a subdirectory
We provide two technology examples for [SCMOS] and [FreePDK45]. Each
specific technology (e.g., [FreePDK45]) should be a subdirectory
(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files:
* gds_lib folder with all the .gds (premade) library cells:
* dff.gds
@ -183,6 +173,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
* write_driver.gds
* cell_6t.gds
* replica\_cell\_6t.gds
* dummy\_cell\_6t.gds
* sp_lib folder with all the .sp (premade) library netlists for the above cells.
* layers.map
* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with:

View File

@ -64,8 +64,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_write(tempspice)
self.gds_write(tempgds)
num_drc_errors = verify.run_drc(self.name, tempgds, final_verification)
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors))
total_drc_errors += num_drc_errors
@ -83,7 +83,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
global total_drc_errors
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
self.gds_write(tempgds)
num_errors = verify.run_drc(self.name, tempgds, final_verification)
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
total_drc_errors += num_errors
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
@ -100,7 +100,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
self.sp_write(tempspice)
self.gds_write(tempgds)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
total_lvs_errors += num_errors
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
os.remove(tempspice)

View File

@ -6,6 +6,7 @@
# All rights reserved.
#
import itertools
import collections
import geometry
import gdsMill
import debug
@ -839,10 +840,10 @@ class layout():
#hcg = {}
# Initialize the vertical conflict graph (vcg) and make a list of all pins
vcg = {}
vcg = collections.OrderedDict()
# Create names for the nets for the graphs
nets = {}
nets = collections.OrderedDict()
index = 0
#print(netlist)
for pin_list in netlist:

View File

@ -319,13 +319,13 @@ class spice():
corner_slew = SLEW_APPROXIMATION*corner_delay
return delay_data(corner_delay, corner_slew)
def get_stage_effort(self, corner, slew, load=0.0):
def get_stage_effort(self, cout, inp_is_rise=True):
"""Inform users undefined delay module while building new modules"""
debug.warning("Design Class {0} logical effort function needs to be defined"
.format(self.__class__.__name__))
debug.warning("Class {0} name {1}"
.format(self.__class__.__name__,
self.name))
.format(self.__class__.__name__,
self.name))
return None
def get_cin(self):
@ -392,7 +392,7 @@ class spice():
"""Returns delay increase due to voltage.
Implemented as linear factor based off nominal voltage.
"""
return tech.spice['vdd_nominal']/voltage
return tech.spice["nom_supply_voltage"]/voltage
def get_temp_delay_factor(self, temp):
"""Returns delay increase due to temperature (in C).
@ -400,11 +400,11 @@ class spice():
"""
#Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
#(k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
thermal_voltage_nom = .008625*tech.spice["temp_nominal"]
thermal_voltage = .008625*temp
vthresh = (tech.spice["v_threshold_typical"]+2*(thermal_voltage-thermal_voltage_nom))
thermal_voltage_nom = 0.008625*tech.spice["nom_temperature"]
thermal_voltage = 0.008625*temp
vthresh = (tech.spice["nom_threshold"]+2*(thermal_voltage-thermal_voltage_nom))
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated.
return (tech.spice['vdd_nominal'] - tech.spice["v_threshold_typical"])/(tech.spice['vdd_nominal']-vthresh)
return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"])/(tech.spice["nom_supply_voltage"]-vthresh)
def return_delay(self, delay, slew):
return delay_data(delay, slew)

View File

@ -259,7 +259,7 @@ class delay(simulation):
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port),
self.graph.get_all_paths('{}{}'.format("clk", port),
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
self.sen_name = self.get_sen_name(self.graph.all_paths)
@ -1050,7 +1050,7 @@ class delay(simulation):
def get_address_row_number(self, probe_address):
"""Calculates wordline row number of data bit under test using address and column mux size"""
return int(probe_address[self.sram.col_addr_size:],2)
def prepare_netlist(self):
@ -1285,13 +1285,13 @@ class delay(simulation):
debug.warning("Analytical characterization results are not supported for multiport.")
# Probe set to 0th bit, does not matter for analytical delay.
self.set_probe('0', 0)
self.set_probe('0'*self.addr_size, 0)
self.create_graph()
self.set_internal_spice_names()
self.create_measurement_names()
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port),
self.graph.get_all_paths('{}{}'.format("clk", port),
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
# Select the path with the bitline (bl)

View File

@ -349,7 +349,7 @@ class functional(simulation):
# Generate CLK signals
for port in self.all_ports:
self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),
self.stim.gen_pulse(sig_name="{0}{1}".format("clk", port),
v1=self.gnd_voltage,
v2=self.vdd_voltage,
offset=self.period,
@ -402,7 +402,7 @@ class functional(simulation):
# For now, only testing these using first read port.
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port),
self.graph.get_all_paths('{}{}'.format("clk", port),
'{}{}_{}'.format(self.dout_name, port, 0).lower())
self.sen_name = self.get_sen_name(self.graph.all_paths)

View File

@ -109,6 +109,8 @@ class lib:
#set the read and write port as inputs.
self.write_data_bus(port)
self.write_addr_bus(port)
if self.sram.write_size:
self.write_wmask_bus(port)
self.write_control_pins(port) #need to split this into sram and port control signals
self.write_clk_timing_power(port)
@ -297,6 +299,15 @@ class lib:
self.lib.write(" bit_to : {0};\n".format(self.sram.addr_size - 1))
self.lib.write(" }\n\n")
if self.sram.write_size:
self.lib.write(" type (wmask){\n")
self.lib.write(" base_type : array;\n")
self.lib.write(" data_type : bit;\n")
self.lib.write(" bit_width : {0};\n".format(self.sram.num_wmasks))
self.lib.write(" bit_from : 0;\n")
self.lib.write(" bit_to : {0};\n".format(self.sram.num_wmasks - 1))
self.lib.write(" }\n\n")
def write_FF_setuphold(self, port):
""" Adds Setup and Hold timing results"""
@ -400,6 +411,20 @@ class lib:
self.lib.write(" }\n")
self.lib.write(" }\n\n")
def write_wmask_bus(self, port):
""" Adds addr bus timing results."""
self.lib.write(" bus(wmask{0}){{\n".format(port))
self.lib.write(" bus_type : wmask; \n")
self.lib.write(" direction : input; \n")
self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"] / 1000))
self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
self.lib.write(" pin(wmask{0}[{1}:0])".format(port, self.sram.num_wmasks - 1))
self.lib.write("{\n")
self.write_FF_setuphold(port)
self.lib.write(" }\n")
self.lib.write(" }\n\n")
def write_control_pins(self, port):
""" Adds control pins timing results."""

View File

@ -336,10 +336,10 @@ class setup_hold():
for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews:
# convert from ps to ns
LH_setup.append(tech.spice["msflop_setup"]/1e3)
HL_setup.append(tech.spice["msflop_setup"]/1e3)
LH_hold.append(tech.spice["msflop_hold"]/1e3)
HL_hold.append(tech.spice["msflop_hold"]/1e3)
LH_setup.append(tech.spice["dff_setup"]/1e3)
HL_setup.append(tech.spice["dff_setup"]/1e3)
LH_hold.append(tech.spice["dff_hold"]/1e3)
HL_hold.append(tech.spice["dff_hold"]/1e3)
times = {"setup_times_LH": LH_setup,
"setup_times_HL": HL_setup,

View File

@ -46,10 +46,10 @@ class simulation():
""" sets feasible timing parameters """
self.period = tech.spice["feasible_period"]
self.slew = tech.spice["rise_time"]*2
self.load = tech.spice["msflop_in_cap"]*4
self.load = tech.spice["dff_in_cap"]*4
self.v_high = self.vdd_voltage - tech.spice["v_threshold_typical"]
self.v_low = tech.spice["v_threshold_typical"]
self.v_high = self.vdd_voltage - tech.spice["nom_threshold"]
self.v_low = tech.spice["nom_threshold"]
self.gnd_voltage = 0
def create_signal_names(self):
@ -301,7 +301,7 @@ class simulation():
pin_names.append("WEB{0}".format(port))
for port in range(total_ports):
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
pin_names.append("{0}{1}".format("clk", port))
if self.write_size:
for port in write_index:
@ -312,7 +312,7 @@ class simulation():
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
pin_names.append("{0}".format(tech.spice["vdd_name"]))
pin_names.append("{0}".format(tech.spice["gnd_name"]))
pin_names.append("{0}".format("vdd"))
pin_names.append("{0}".format("gnd"))
return pin_names

View File

@ -24,12 +24,12 @@ class stimuli():
""" Class for providing stimuli functions """
def __init__(self, stim_file, corner):
self.vdd_name = tech.spice["vdd_name"]
self.gnd_name = tech.spice["gnd_name"]
self.vdd_name = "vdd"
self.gnd_name = "gnd"
self.pmos_name = tech.spice["pmos"]
self.nmos_name = tech.spice["nmos"]
self.tx_width = tech.spice["minwidth_tx"]
self.tx_length = tech.spice["channel"]
self.tx_width = tech.drc["minwidth_tx"]
self.tx_length = tech.drc["minlength_channel"]
self.sf = stim_file

View File

@ -507,16 +507,16 @@ def report_status():
debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).")
if not OPTS.route_supplies:
debug.print_raw("Design supply routing skipped for run-time (incomplete GDS will not be saved) (route_supplies=True to enable).")
debug.print_raw("Design supply routing skipped. Supplies will have multiple must-connect pins. (route_supplies=True to enable supply routing).")
if not OPTS.inline_lvsdrc:
debug.print_raw("DRC/LVS/PEX is only run on the top-level design to save run-time (inline_lvsdrc=True to enable).")
debug.print_raw("DRC/LVS/PEX is only run on the top-level design to save run-time (inline_lvsdrc=True to do inline checking).")
if not OPTS.check_lvsdrc:
debug.print_raw("DRC/LVS/PEX is disabled (check_lvsdrc=True to enable).")
if OPTS.analytical_delay:
debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to enable).")
debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).")
else:
if OPTS.spice_name!="":
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))

View File

@ -74,7 +74,9 @@ class bank(design.design):
# Remember the bank center for further placement
self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1)
self.bank_array_ur = self.bitcell_array_inst.ur()
self.bank_array_ul = self.bitcell_array_inst.ul()
self.DRC_LVS()
def add_pins(self):
@ -928,7 +930,10 @@ class bank(design.design):
connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
if port in self.write_ports:
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
if port % 2:
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").rc()))
else:
connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
if port in self.read_ports:
connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))

View File

@ -157,7 +157,7 @@ class bitcell_array(design.design):
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = OPTS.rbl_delay_percentage
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
#Calculate the bitcell power which currently only includes leakage

View File

@ -33,9 +33,9 @@ class dff(design.design):
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["msflop_leakage"]
power_leak = spice["dff_leakage"]
total_power = self.return_power(power_dyn, power_leak)
return total_power
@ -44,8 +44,8 @@ class dff(design.design):
"""Computes effective capacitance. Results in fF"""
from tech import parameter
c_load = load
c_para = spice["flop_para_cap"]#ff
transition_prob = spice["flop_transition_prob"]
c_para = spice["dff_out_cap"]#ff
transition_prob = 0.5
return transition_prob*(c_load + c_para)
def get_clk_cin(self):
@ -57,4 +57,4 @@ class dff(design.design):
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)

View File

@ -22,11 +22,11 @@ class port_data(design.design):
sram_config.set_local_config(self)
self.port = port
if self.write_size:
if self.write_size is not None:
self.num_wmasks = int(self.word_size/self.write_size)
else:
self.num_wmasks = 0
if name == "":
name = "port_data_{0}".format(self.port)
design.design.__init__(self, name)
@ -58,7 +58,7 @@ class port_data(design.design):
if self.write_driver_array:
self.create_write_driver_array()
if self.write_size:
if self.write_size is not None:
self.create_write_mask_and_array()
else:
self.write_mask_and_array_inst = None
@ -70,9 +70,9 @@ class port_data(design.design):
self.create_column_mux_array()
else:
self.column_mux_array_inst = None
def create_layout(self):
self.compute_instance_offsets()
self.place_instances()
@ -81,7 +81,7 @@ class port_data(design.design):
def add_pins(self):
""" Adding pins for port address module"""
self.add_pin("rbl_bl","INOUT")
self.add_pin("rbl_br","INOUT")
for bit in range(self.num_cols):
@ -107,7 +107,7 @@ class port_data(design.design):
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
def route_layout(self):
""" Create routing among the modules """
self.route_data_lines()
@ -118,15 +118,15 @@ class port_data(design.design):
""" Add the pins """
self.route_bitline_pins()
self.route_control_pins()
def route_data_lines(self):
""" Route the bitlines depending on the port type rw, w, or r. """
if self.port in self.readwrite_ports:
# (write_mask_and ->) write_driver -> sense_amp -> (column_mux ->) precharge -> bitcell_array
self.route_write_mask_and_array_in(self.port)
self.route_write_mask_and_array_to_write_driver(self.port)
self.route_write_driver_in(self.port)
self.route_write_driver_in(self.port)
self.route_sense_amp_out(self.port)
self.route_write_driver_to_sense_amp(self.port)
self.route_sense_amp_to_column_mux_or_precharge_array(self.port)
@ -142,15 +142,15 @@ class port_data(design.design):
self.route_write_mask_and_array_to_write_driver(self.port)
self.route_write_driver_in(self.port)
self.route_write_driver_to_column_mux_or_precharge_array(self.port)
self.route_column_mux_to_precharge_array(self.port)
self.route_column_mux_to_precharge_array(self.port)
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
for inst in self.insts:
self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd")
def add_modules(self):
# Extra column +1 is for RBL
@ -163,23 +163,23 @@ class port_data(design.design):
if self.port in self.read_ports:
self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size,
word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
else:
self.sense_amp_array = None
if self.col_addr_size > 0:
self.column_mux_array = factory.create(module_type="column_mux_array",
columns=self.num_cols,
columns=self.num_cols,
word_size=self.word_size,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
self.add_mod(self.column_mux_array)
else:
self.column_mux_array = None
if self.port in self.write_ports:
self.write_driver_array = factory.create(module_type="write_driver_array",
@ -187,11 +187,12 @@ class port_data(design.design):
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_driver_array)
if self.write_size:
if self.write_size is not None:
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
write_size=self.write_size,
port = self.port)
self.add_mod(self.write_mask_and_array)
else:
self.write_mask_and_array = None
@ -207,8 +208,8 @@ class port_data(design.design):
if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size
else:
self.num_col_addr_lines = 0
self.num_col_addr_lines = 0
# A space for wells or jogging m2 between modules
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
@ -216,7 +217,7 @@ class port_data(design.design):
# create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell")
self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.get_all_wl_names()
@ -226,7 +227,7 @@ class port_data(design.design):
if not self.precharge_array:
self.precharge_array_inst = None
return
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array)
@ -245,16 +246,16 @@ class port_data(design.design):
temp.extend(["p_en_bar", "vdd"])
self.connect_inst(temp)
def place_precharge_array(self, offset):
""" Placing Precharge """
self.precharge_array_inst.place(offset=offset, mirror="MX")
def create_column_mux_array(self):
""" Creating Column Mux when words_per_row > 1 . """
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array)
@ -270,15 +271,15 @@ class port_data(design.design):
temp.append("gnd")
self.connect_inst(temp)
def place_column_mux_array(self, offset):
""" Placing Column Mux when words_per_row > 1 . """
if self.col_addr_size == 0:
return
self.column_mux_array_inst.place(offset=offset, mirror="MX")
def create_sense_amp_array(self):
""" Creating Sense amp """
self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
@ -293,11 +294,11 @@ class port_data(design.design):
else:
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
temp.extend(["s_en", "vdd", "gnd"])
self.connect_inst(temp)
def place_sense_amp_array(self, offset):
""" Placing Sense amp """
self.sense_amp_array_inst.place(offset=offset, mirror="MX")
@ -320,7 +321,7 @@ class port_data(design.design):
temp.append(self.bl_names[self.port] + "_out_{0}".format(bit))
temp.append(self.br_names[self.port] + "_out_{0}".format(bit))
if self.write_size:
if self.write_size is not None:
for i in range(self.num_wmasks):
temp.append("wdriver_sel_{}".format(i))
else:

View File

@ -382,7 +382,7 @@ class replica_bitcell_array(design.design):
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = OPTS.rbl_delay_percentage
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
#Calculate the bitcell power which currently only includes leakage

View File

@ -20,7 +20,7 @@ class write_mask_and_array(design.design):
The write mask AND array goes between the write driver array and the sense amp array.
"""
def __init__(self, name, columns, word_size, write_size):
def __init__(self, name, columns, word_size, write_size, port=0):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -30,6 +30,7 @@ class write_mask_and_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.port = port
self.words_per_row = int(columns / word_size)
self.num_wmasks = int(word_size / write_size)
@ -105,57 +106,48 @@ class write_mask_and_array(design.design):
def add_layout_pins(self):
self.nand2 = factory.create(module_type="pnand2")
supply_pin=self.nand2.get_pin("vdd")
for i in range(self.num_wmasks):
wmask_in_pin = self.and2_insts[i].get_pin("A")
self.add_layout_pin(text="wmask_in_{0}".format(i),
layer=wmask_in_pin.layer,
offset=wmask_in_pin.ll(),
width=wmask_in_pin.width(),
height=wmask_in_pin.height())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=wmask_in_pin.center())
# Create the enable pin that connects all write mask AND array's B pins
beg_en_pin = self.and2_insts[0].get_pin("B")
end_en_pin = self.and2_insts[self.num_wmasks-1].get_pin("B")
if self.port % 2:
# Extend metal3 to edge of AND array in multiport
en_to_edge = self.and2.width - beg_en_pin.cx()
self.add_layout_pin(text="en",
layer="metal3",
offset=beg_en_pin.bc(),
width=end_en_pin.cx() - beg_en_pin.cx() + en_to_edge)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=vector(end_en_pin.cx() + en_to_edge, end_en_pin.cy()))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vector(end_en_pin.cx() + en_to_edge, end_en_pin.cy()))
else:
self.add_layout_pin(text="en",
layer="metal3",
offset=beg_en_pin.bc(),
width=end_en_pin.cx() - beg_en_pin.cx())
for i in range(self.num_wmasks):
# Copy remaining layout pins
self.copy_layout_pin(self.and2_insts[i],"A","wmask_in_{0}".format(i))
self.copy_layout_pin(self.and2_insts[i],"Z","wmask_out_{0}".format(i))
# Add via connections to metal3 for AND array's B pin
en_pin = self.and2_insts[i].get_pin("B")
# Add the M1->M2 stack
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=en_pin.center())
# Add the M2->M3 stack
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=en_pin.center())
# Route en pin between AND gates
if i < self.num_wmasks-1:
self.add_layout_pin(text="en",
layer="metal3",
offset=en_pin.bc(),
width = self.en_width(i),
height = drc('minwidth_metal3'))
wmask_out_pin = self.and2_insts[i].get_pin("Z")
self.add_layout_pin(text="wmask_out_{0}".format(i),
layer=wmask_out_pin.layer,
offset=wmask_out_pin.ll(),
width=wmask_out_pin.width(),
height=wmask_out_pin.height())
self.add_power_pin("gnd", vector(supply_pin.width() + i * self.wmask_en_len, 0))
self.add_power_pin("vdd", vector(supply_pin.width() + i * self.wmask_en_len, self.height))
# Route power and ground rails together
if i < self.num_wmasks-1:
for n in ["gnd","vdd"]:
pin = self.and2_insts[i].get_pin(n)
next_pin = self.and2_insts[i+1].get_pin(n)
self.add_path("metal1",[pin.center(),next_pin.center()])
def en_width(self, pin):
en_pin = self.and2_insts[pin].get_pin("B")
next_en_pin = self.and2_insts[pin+1].get_pin("B")
width = next_en_pin.center() - en_pin.center()
# Return x coordinates only
return width[0]
def get_cin(self):
"""Get the relative capacitance of all the input connections in the bank"""
# The enable is connected to an and2 for every row.

View File

@ -58,10 +58,7 @@ debug.print_raw("Words per row: {}".format(c.words_per_row))
output_extensions = ["sp","v","lib","py","html","log"]
# Only output lef/gds if back-end
if not OPTS.netlist_only:
output_extensions.extend(["lef"])
# Only output gds if final routing
if OPTS.route_supplies:
output_extensions.extend(["gds"])
output_extensions.extend(["lef","gds"])
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
debug.print_raw("Output files are: ")

View File

@ -258,7 +258,7 @@ class pinv(pgate.pgate):
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["inv_leakage"]
@ -269,7 +269,7 @@ class pinv(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transition_prob = spice["inv_transition_prob"]
transition_prob = 0.5
return transition_prob*(c_load + c_para)
def input_load(self):

View File

@ -233,7 +233,7 @@ class pnand2(pgate.pgate):
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nand2_leakage"]
@ -244,7 +244,7 @@ class pnand2(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transition_prob = spice["nand2_transition_prob"]
transition_prob = 0.1875
return transition_prob*(c_load + c_para)
def input_load(self):

View File

@ -246,7 +246,7 @@ class pnand3(pgate.pgate):
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nand3_leakage"]
@ -257,7 +257,7 @@ class pnand3(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transition_prob = spice["nand3_transition_prob"]
transition_prob = 0.1094
return transition_prob*(c_load + c_para)
def input_load(self):

View File

@ -230,7 +230,7 @@ class pnor2(pgate.pgate):
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
freq = spice["default_event_rate"]
freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nor2_leakage"]
@ -241,7 +241,7 @@ class pnor2(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transition_prob = spice["nor2_transition_prob"]
transition_prob = 0.1875
return transition_prob*(c_load + c_para)
def build_graph(self, graph, inst_name, port_nets):

View File

@ -75,13 +75,12 @@ class sram():
self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time)
if OPTS.route_supplies:
# Write the layout
start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds"
debug.print_raw("GDS: Writing to {0}".format(gdsname))
self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time)
# Write the layout
start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds"
debug.print_raw("GDS: Writing to {0}".format(gdsname))
self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time)
# Save the spice file
start_time = datetime.datetime.now()
@ -130,4 +129,4 @@ class sram():
vname = OPTS.output_path + self.s.name + ".v"
debug.print_raw("Verilog: Writing to {0}".format(vname))
self.verilog_write(vname)
print_time("Verilog", datetime.datetime.now(), start_time)
print_time("Verilog", datetime.datetime.now(), start_time)

View File

@ -70,46 +70,51 @@ class sram_1bank(sram_base):
wmask_pos = [None]*len(self.all_ports)
data_pos = [None]*len(self.all_ports)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
# The M1 pitch is for supply rail spacings
max_gap_size = self.m2_pitch*max(self.word_size+1,self.col_addr_size+1) + 2*self.m1_pitch
if self.write_size:
max_gap_size = self.m3_pitch*self.word_size + 2*self.m1_pitch
max_gap_size_wmask = self.m2_pitch*max(self.num_wmasks+1,self.col_addr_size+1) + 2*self.m1_pitch
else:
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
# The M1 pitch is for supply rail spacings
max_gap_size = self.m2_pitch*max(self.word_size+1,self.col_addr_size+1) + 2*self.m1_pitch
# Port 0
port = 0
if self.write_size:
if port in self.write_ports:
if port in self.write_ports:
if self.write_size:
# Add the write mask flops below the write mask AND array.
wmask_pos[port] = vector(self.bank.bank_array_ll.x,
-0.5*max_gap_size - self.dff.height)
-max_gap_size_wmask - self.dff.height)
self.wmask_dff_insts[port].place(wmask_pos[port])
# Add the data flops below the write mask flops.
data_pos[port] = vector(self.bank.bank_array_ll.x,
-1.5*max_gap_size - 2*self.dff.height)
-max_gap_size - max_gap_size_wmask - 2*self.dff.height)
self.data_dff_insts[port].place(data_pos[port])
else:
wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0)
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
# Add the data flops below the bank to the right of the lower-left of bank array
# This relies on the lower-left of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ll.x,
-max_gap_size - self.dff.height)
self.data_dff_insts[port].place(data_pos[port])
else:
# Add the data flops below the bank to the right of the lower-left of bank array
# This relies on the lower-left of the array of the bank
# decoder in upper left, bank in upper right, sensing in lower right.
# These flops go below the sensing and leave a gap to channel route to the
# sense amps.
if port in self.write_ports:
data_pos[port] = vector(self.bank.bank_array_ll.x,
-max_gap_size - self.dff.height)
self.data_dff_insts[port].place(data_pos[port])
wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0)
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
else:
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
# Add the col address flops below the bank to the left of the lower-left of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size - self.col_addr_dff_insts[port].height)
if self.write_size:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size_wmask - self.col_addr_dff_insts[port].height)
else:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size - self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port])
else:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x,0)
@ -125,13 +130,6 @@ class sram_1bank(sram_base):
y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
row_addr_pos[port] = vector(x_offset, y_offset)
self.row_addr_dff_insts[port].place(row_addr_pos[port])
# Add the col address flops below the bank to the left of the lower-left of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
-max_gap_size - self.col_addr_dff_insts[port].height)
self.col_addr_dff_insts[port].place(col_addr_pos[port])
if len(self.all_ports)>1:
# Port 1
@ -140,15 +138,14 @@ class sram_1bank(sram_base):
if port in self.write_ports:
if self.write_size:
# Add the write mask flops below the write mask AND array.
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + 0.5*max_gap_size + self.dff.height)
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width,
self.bank.height + max_gap_size_wmask + self.dff.height)
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
# Add the data flops below the write mask flops
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
self.bank.height + 1.5*max_gap_size + 2*self.dff.height)
self.bank.height + max_gap_size_wmask + max_gap_size + 2*self.dff.height)
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
else:
# Add the data flops above the bank to the left of the upper-right of bank array
# This relies on the upper-right of the array of the bank
@ -161,8 +158,12 @@ class sram_1bank(sram_base):
# Add the col address flops above the bank to the right of the upper-right of bank array
if self.col_addr_dff:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.dff.height)
if self.write_size:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size_wmask + self.dff.height)
else:
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
self.bank.height + max_gap_size + self.dff.height)
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
else:
col_addr_pos[port] = self.bank_inst.ur()
@ -354,11 +355,16 @@ class sram_1bank(sram_base):
""" Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least)
for port in self.write_ports:
if port%2:
offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
if self.write_size:
if port % 2:
offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size + 2)*self.m3_pitch)
else:
offset = self.data_dff_insts[port].ul() + vector(0, 2 * self.m3_pitch)
else:
offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
if port%2:
offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
else:
offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
@ -377,7 +383,10 @@ class sram_1bank(sram_base):
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
if self.write_size:
for x in bank_names:
pin_offset = self.bank_inst.get_pin(x).bc()
if port % 2:
pin_offset = self.bank_inst.get_pin(x).uc()
else:
pin_offset = self.bank_inst.get_pin(x).bc()
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_offset)
self.add_via_center(layers=("metal2", "via2", "metal3"),
@ -398,7 +407,7 @@ class sram_1bank(sram_base):
# This is where the channel will start (y-dimension at least)
for port in self.write_ports:
if port % 2:
offset = self.wmask_dff_insts[port].ll() - vector(0, (self.word_size + 2) * self.m1_pitch)
offset = self.wmask_dff_insts[port].ll() - vector(0, (self.num_wmasks+2) * self.m1_pitch)
else:
offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch)

View File

@ -27,7 +27,7 @@ class sram_base(design, verilog, lef):
"""
def __init__(self, name, sram_config):
design.__init__(self, name)
lef.__init__(self, ["metal1", "metal2", "metal3"])
lef.__init__(self, ["metal1", "metal2", "metal3", "metal4"])
verilog.__init__(self)
self.sram_config = sram_config
@ -120,7 +120,7 @@ class sram_base(design, verilog, lef):
self.add_lvs_correspondence_points()
#self.offset_all_coordinates()
self.offset_all_coordinates()
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
# @unittest.skip("SKIPPING psram_1bank_2mux_1rw_1w_wmask_test, multiport layout not complete")
class psram_1bank_2mux_1rw_1w_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 0
c = sram_config(word_size=8,
write_size=4,
num_words=32,
num_banks=1)
c.num_words = 32
c.words_per_row = 2
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w psram "
"with {} bit words, {} words, {} words per "
"row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports,
c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
@unittest.skip("SKIPPING sram_1bank_32b_1024_wmask_test")
class sram_1bank_32b_1024_wmask_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=32,
write_size=8,
num_words=1024,
num_banks=1)
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w sram "
"with {} bit words, {} words, {} bit writes, {} words per "
"row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports,
c.word_size,
c.num_words,
c.write_size,
c.words_per_row,
c.num_banks))
a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -54,7 +54,7 @@ class timing_sram_test(openram_test):
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s.s, tempspice, corner)
import tech
loads = [tech.spice["msflop_in_cap"]*4]
loads = [tech.spice["dff_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data

View File

@ -49,7 +49,7 @@ class model_delay_test(openram_test):
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s.s, tempspice, corner)
import tech
loads = [tech.spice["msflop_in_cap"]*4]
loads = [tech.spice["dff_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
# Run a spice characterization

View File

@ -47,7 +47,7 @@ class timing_sram_test(openram_test):
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s.s, tempspice, corner)
import tech
loads = [tech.spice["msflop_in_cap"]*4]
loads = [tech.spice["dff_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data

View File

@ -19,6 +19,7 @@ class lib_model_corners_lib_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.netlist_only = True
from characterizer import lib
from sram import sram

View File

@ -19,7 +19,8 @@ class lib_sram_model_test(openram_test):
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.netlist_only = True
from characterizer import lib
from sram import sram
from sram_config import sram_config

View File

@ -38,9 +38,12 @@ class openram_back_end_test(openram_test):
os.chmod(out_path, 0o0750)
# specify the same verbosity for the system call
verbosity = ""
options = ""
for i in range(OPTS.debug_level):
verbosity += " -v"
options += " -v"
if OPTS.spice_name:
options += " -s {}".format(OPTS.spice_name)
# Always perform code coverage
if OPTS.coverage == 0:
@ -52,7 +55,7 @@ class openram_back_end_test(openram_test):
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
out_file,
out_path,
verbosity,
options,
config_name,
out_path)
debug.info(1, cmd)
@ -83,10 +86,11 @@ class openram_back_end_test(openram_test):
# now clean up the directory
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
if OPTS.purge_temp:
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
globals.end_openram()
# run the test from the command line

View File

@ -39,10 +39,12 @@ class openram_front_end_test(openram_test):
os.chmod(out_path, 0o0750)
# specify the same verbosity for the system call
verbosity = ""
options = ""
for i in range(OPTS.debug_level):
verbosity += " -v"
options += " -v"
if OPTS.spice_name:
options += " -s {}".format(OPTS.spice_name)
# Always perform code coverage
if OPTS.coverage == 0:
@ -54,22 +56,17 @@ class openram_front_end_test(openram_test):
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
out_file,
out_path,
verbosity,
options,
config_name,
out_path)
debug.info(1, cmd)
os.system(cmd)
# assert an error until we actually check a result
for extension in ["v", "lef", "sp"]:
for extension in ["v", "lef", "sp", "gds"]:
filename = "{0}/{1}.{2}".format(out_path,out_file,extension)
debug.info(1,"Checking for file: " + filename)
self.assertEqual(os.path.exists(filename),True)
# assert an error if we output the incomplete gds!
for extension in ["gds"]:
filename = "{0}/{1}.{2}".format(out_path,out_file,extension)
debug.info(1,"Checking file does NOT exist: " + filename)
self.assertEqual(os.path.exists(filename),False)
# Make sure there is any .lib file
import glob
@ -89,10 +86,11 @@ class openram_front_end_test(openram_test):
self.assertEqual(len(re.findall('WARNING',output)),0)
# now clean up the directory
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
# now clean up the directory
if OPTS.purge_temp:
if os.path.exists(out_path):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
globals.end_openram()

View File

@ -303,37 +303,16 @@ spice["fall_time"] = 0.005 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
#sram signal names
#FIXME: We don't use these everywhere...
spice["vdd_name"] = "vdd"
spice["gnd_name"] = "gnd"
spice["control_signals"] = ["CSB", "WEB"]
spice["data_name"] = "DATA"
spice["addr_name"] = "ADDR"
spice["minwidth_tx"] = drc["minwidth_tx"]
spice["channel"] = drc["minlength_channel"]
spice["clk"] = "clk"
# analytical delay parameters
spice["vdd_nominal"] = 1.0 # Typical Threshold voltage in Volts
spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
spice["v_threshold_typical"] = 0.4 # Typical Threshold voltage in Volts
spice["nom_threshold"] = 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
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff
spice["msflop_setup"] = 9 # DFF setup time in ps
spice["msflop_hold"] = 1 # DFF hold time in ps
spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["msflop_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["dff_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_in_cap"] = 0.2091 # Input capacitance (D) [Femto-farad]
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@ -341,19 +320,13 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
spice["dff_leakage"] = 1 # Leakage power of flop in nW
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
spice["flop_transition_prob"] = 0.5 # Transition probability of inverter.
spice["inv_transition_prob"] = 0.5 # Transition probability of inverter.
spice["nand2_transition_prob"] = 0.1875 # Transition probability of 2-input nand.
spice["nand3_transition_prob"] = 0.1094 # Transition probability of 3-input nand.
spice["nor2_transition_prob"] = 0.1875 # Transition probability of 2-input nor.
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Parameters related to sense amp enable timing and delay chain/RBL sizing
parameter['le_tau'] = 2.25 #In pico-seconds.
parameter['cap_relative_per_ff'] = 7.5 #Units of Relative Capacitance/ Femto-Farad
parameter["le_tau"] = 2.25 #In pico-seconds.
parameter["cap_relative_per_ff"] = 7.5 #Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 30.6 #relative capacitance
parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = 2.4 #Tau delay units
@ -361,7 +334,7 @@ parameter["sa_en_pmos_size"] = 0.72 #micro-meters
parameter["sa_en_nmos_size"] = 0.27 #micro-meters
parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
parameter["sa_inv_nmos_size"] = 0.27 #micro-meters
parameter['bitcell_drain_cap'] = 0.1 #In Femto-Farad, approximation of drain capacitance
parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of drain capacitance
###################################################
##END Spice Simulation Parameters

File diff suppressed because it is too large Load Diff

View File

@ -44,4 +44,14 @@ Contributions and modifications to this kit are welcomed and encouraged.
ncsu_basekit/ Base kit for custom design
osu_soc/ Standard-cell kit for synthesis, place, & route
FreePDK45.lyp is converted automatically from the .tf using:
https://github.com/klayoutmatthias/tf_import
Command line:
klayout -z -rd tf_file=FreePDK45.tf -rd lyp_file=FreePDK45.lyp
You can then view layouts with:
klayout file.gds -l mosis.lyp
glade_freepdk45.py is a script for Glade:
https://peardrop.co.uk/
to load the .tf using:
glade -script ~/openram/technology/freepdk45/tf/glade_freepdk45.py -gds file.gds

View File

@ -1223,6 +1223,7 @@ drDefinePacket(
( display prBoundary blank solid purple purple )
( display prBoundaryBnd blank solid cyan cyan )
( display prBoundaryLbl blank solid purple purple )
( display comment blank solid purple purple )
( display align blank solid tan tan )
( display hardFence blank solid red red )
( display softFence blank solid yellow yellow )

View File

@ -219,8 +219,6 @@ spice["nmos"]="n"
spice["pmos"]="p"
# This is a map of corners to model files
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
# FIXME: Uncomment when we have the new spice models
#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] }
spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
"FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
"FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
@ -242,37 +240,17 @@ spice["fall_time"] = 0.05 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
#sram signal names
#FIXME: We don't use these everywhere...
spice["vdd_name"] = "vdd"
spice["gnd_name"] = "gnd"
spice["control_signals"] = ["CSB", "WEB"]
spice["data_name"] = "DATA"
spice["addr_name"] = "ADDR"
spice["minwidth_tx"] = drc["minwidth_tx"]
spice["channel"] = drc["minlength_channel"]
spice["clk"] = "clk"
# analytical delay parameters
spice["nom_threshold"] = 1.3 # Typical Threshold voltage in Volts
# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45.
spice["vdd_nominal"] = 5.0 # Typical Threshold voltage in Volts
spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
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
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff
spice["msflop_setup"] = 9 # DFF setup time in ps
spice["msflop_hold"] = 1 # DFF hold time in ps
spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@ -280,27 +258,21 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
spice["dff_leakage"] = 1 # Leakage power of flop in nW
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
spice["flop_transition_prob"] = 0.5 # Transition probability of inverter.
spice["inv_transition_prob"] = 0.5 # Transition probability of inverter.
spice["nand2_transition_prob"] = 0.1875 # Transition probability of 2-input nand.
spice["nand3_transition_prob"] = 0.1094 # Transition probability of 3-input nand.
spice["nor2_transition_prob"] = 0.1875 # Transition probability of 2-input nor.
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Logical Effort relative values for the Handmade cells
parameter['le_tau'] = 23 #In pico-seconds.
parameter["le_tau"] = 23 #In pico-seconds.
parameter["min_inv_para_delay"] = 0.73 #In relative delay units
parameter['cap_relative_per_ff'] = 0.91 #Units of Relative Capacitance/ Femto-Farad
parameter["cap_relative_per_ff"] = 0.91 #Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 27.5 #In relative capacitance units
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
parameter["sa_en_pmos_size"] = 24*_lambda_
parameter["sa_en_nmos_size"] = 9*_lambda_
parameter["sa_inv_pmos_size"] = 18*_lambda_
parameter["sa_inv_nmos_size"] = 9*_lambda_
parameter['bitcell_drain_cap'] = 0.2 #In Femto-Farad, approximation of drain capacitance
parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of drain capacitance
###################################################
##END Spice Simulation Parameters

View File

@ -70,6 +70,7 @@ parameter={}
parameter["min_tx_size"] = 4*_lambda_
parameter["beta"] = 2
# These 6T sizes are used in the parameterized bitcell.
parameter["6T_inv_nmos_size"] = 8*_lambda_
parameter["6T_inv_pmos_size"] = 3*_lambda_
parameter["6T_access_size"] = 4*_lambda_
@ -246,8 +247,6 @@ spice["nmos"]="n"
spice["pmos"]="p"
# This is a map of corners to model files
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
# FIXME: Uncomment when we have the new spice models
#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] }
spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
"FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
"FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
@ -269,37 +268,17 @@ spice["fall_time"] = 0.05 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
#sram signal names
#FIXME: We don't use these everywhere...
spice["vdd_name"] = "vdd"
spice["gnd_name"] = "gnd"
spice["control_signals"] = ["CSB", "WEB"]
spice["data_name"] = "DATA"
spice["addr_name"] = "ADDR"
spice["minwidth_tx"] = drc["minwidth_tx"]
spice["channel"] = drc["minlength_channel"]
spice["clk"] = "clk"
# analytical delay parameters
spice["nom_threshold"] = 1.3 # Nominal Threshold voltage in Volts
# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45.
spice["vdd_nominal"] = 5.0 # Typical Threshold voltage in Volts
spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
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
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff
spice["msflop_setup"] = 9 # DFF setup time in ps
spice["msflop_hold"] = 1 # DFF hold time in ps
spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@ -307,27 +286,21 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
spice["dff_leakage"] = 1 # Leakage power of flop in nW
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
spice["flop_transition_prob"] = .5 # Transition probability of inverter.
spice["inv_transition_prob"] = .5 # Transition probability of inverter.
spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand.
spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand.
spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Logical Effort relative values for the Handmade cells
parameter['le_tau'] = 23 #In pico-seconds.
parameter["le_tau"] = 23 #In pico-seconds.
parameter["min_inv_para_delay"] = .73 #In relative delay units
parameter['cap_relative_per_ff'] = .91 #Units of Relative Capacitance/ Femto-Farad
parameter["cap_relative_per_ff"] = .91 #Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 27.5 #In relative capacitance units
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
parameter["sa_en_pmos_size"] = 24*_lambda_
parameter["sa_en_nmos_size"] = 9*_lambda_
parameter["sa_inv_pmos_size"] = 18*_lambda_
parameter["sa_inv_nmos_size"] = 9*_lambda_
parameter['bitcell_drain_cap'] = 0.2 #In Femto-Farad, approximation of drain capacitance
parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of drain capacitance
###################################################
##END Spice Simulation Parameters

View File

@ -18,4 +18,16 @@ be found in the file cdb2oa/OA_Conversion.txt.
This kit is not yet fully supported. Please post problems and solutions at
http://www.chiptalk.org -> Forums -> NCSU CDK -> NCSU CDK 1.6.0.beta for Virtuoso 6.1
Modified 2018 by MRG to contain SCN4ME Via3/Metal4 layers.
Modified 2018 by MRG to contain SCN4ME Via3/Metal4 layers.
mosis.lyp is converted automatically from the .tf using:
https://github.com/klayoutmatthias/tf_import
Command line:
klayout -z -rd tf_file=FreePDK45.tf -rd lyp_file=FreePDK45.ly
You can then view layouts with:
klayout file.gds -l mosis.lyp
glade_scn4m_subm.py is a script for Glade:
https://peardrop.co.uk/
to load the .tf using:
glade -script ~/openram/technology/scn3me_subm/tf/glade_scn3me_subm.py -gds file.gds

File diff suppressed because it is too large Load Diff

View File

@ -552,6 +552,8 @@ layerRules(
( ("P1Con" "drawing") 47 0 t )
( ("Metal1" "drawing") 49 0 t )
( ("Metal2" "drawing") 51 0 t )
( ("Metal3" "drawing") 62 0 t )
( ("Metal4" "drawing") 31 0 t )
( ("annotate" "drawing") 0 0 nil )
( ("annotate" "drawing1") 0 0 nil )
( ("annotate" "drawing2") 0 0 nil )
@ -562,7 +564,6 @@ layerRules(
( ("annotate" "drawing7") 0 0 nil )
( ("annotate" "drawing8") 0 0 nil )
( ("annotate" "drawing9") 0 0 nil )
( ("Via" "drawing") 50 0 t )
( ("Glass" "drawing") 52 0 t )
( ("XP" "drawing") 60 0 t )
( ("Metal2" "pin") 0 0 nil )
@ -590,8 +591,9 @@ layerRules(
( ("P1Con" "net") 0 0 nil )
( ("Metal1" "net") 0 0 nil )
( ("Metal2" "net") 0 0 nil )
( ("Metal3" "net") 0 0 nil )
( ("Metal4" "net") 0 0 nil )
( ("device" "label") 0 0 nil )
( ("Via" "net") 0 0 nil )
( ("pin" "label") 0 0 nil )
( ("text" "drawing") 63 0 t )
( ("pin" "drawing") 0 0 nil )
@ -649,11 +651,12 @@ layerRules(
( Metal2 0 0 nil )
( Glass 0 0 nil )
( XP 0 0 nil )
( ("Via2" "drawing") 50 0 t )
( ("Via" "drawing") 50 0 t )
( ("Via" "net") 0 0 nil )
( ("Via2" "drawing") 61 0 t )
( ("Via2" "net") 0 0 nil )
( ("Metal3" "drawing") 50 0 t )
( ("Metal3" "net") 0 0 nil )
( ("Metal3" "pin") 0 0 nil )
( ("Via3" "drawing") 30 0 t )
( ("Via3" "net") 0 0 nil )
( ("CapWell" "drawing") 0 0 nil )
( ("CapWell" "net") 0 0 nil )
( ("SiBlock" "drawing") 0 0 nil )
@ -665,6 +668,7 @@ layerRules(
viaLayers(
;( layer1 viaLayer layer2 )
;( ------ -------- ------ )
( Metal3 Via3 Metal4 )
( Metal2 Via2 Metal3 )
( Metal1 Via Metal2 )
( Active ActX Poly1 )
@ -798,6 +802,10 @@ electricalRules(
( currentDensity "Metal1" 1.0 )
( currentDensity "Via" 1.0 )
( currentDensity "Metal2" 1.0 )
( currentDensity "Via2" 1.0 )
( currentDensity "Metal3" 1.0 )
( currentDensity "Via3" 1.0 )
( currentDensity "Metal4" 1.0 )
) ;characterizationRules
) ;electricalRules
@ -824,10 +832,13 @@ leRules(
( Metal2 drawing )
( Via2 drawing )
( Metal3 drawing )
( Via3 drawing )
( Metal4 drawing )
( Poly1 pin )
( Metal1 pin )
( Metal2 pin )
( Metal3 pin )
( Metal4 pin )
( Poly2 drawing )
( P2Con drawing )
( instance drawing )
@ -853,7 +864,7 @@ leRules(
lxRules(
lxExtractLayers(
(Metal1 Metal2 Metal3)
(Metal1 Metal2 Metal3 Metal4)
) ;lxExtractLayers
) ;lxRules