mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev'
This commit is contained in:
commit
062156fbd3
15
README.md
15
README.md
|
|
@ -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 setup script for each technology you want to use
|
||||||
+ a technology directory for each technology with the base cells
|
+ a technology directory for each technology with the base cells
|
||||||
|
|
||||||
All setup scripts should be in the setup\_scripts directory under the
|
We provide two technology examples for [SCMOS] and [FreePDK45]. Each
|
||||||
$OPENRAM\_TECH directory. We provide two technology examples for
|
specific technology (e.g., [FreePDK45]) should be a subdirectory
|
||||||
[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
|
|
||||||
(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files:
|
(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files:
|
||||||
* gds_lib folder with all the .gds (premade) library cells:
|
* gds_lib folder with all the .gds (premade) library cells:
|
||||||
* dff.gds
|
* dff.gds
|
||||||
|
|
@ -183,6 +173,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
|
||||||
* write_driver.gds
|
* write_driver.gds
|
||||||
* cell_6t.gds
|
* cell_6t.gds
|
||||||
* replica\_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.
|
* sp_lib folder with all the .sp (premade) library netlists for the above cells.
|
||||||
* layers.map
|
* layers.map
|
||||||
* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with:
|
* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with:
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
self.sp_write(tempspice)
|
self.sp_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
|
|
||||||
num_drc_errors = verify.run_drc(self.name, tempgds, 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)
|
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_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))
|
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
|
total_drc_errors += num_drc_errors
|
||||||
|
|
@ -83,7 +83,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
global total_drc_errors
|
global total_drc_errors
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
||||||
self.gds_write(tempgds)
|
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
|
total_drc_errors += num_errors
|
||||||
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
|
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)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
|
||||||
self.sp_write(tempspice)
|
self.sp_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
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
|
total_lvs_errors += num_errors
|
||||||
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
|
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import itertools
|
import itertools
|
||||||
|
import collections
|
||||||
import geometry
|
import geometry
|
||||||
import gdsMill
|
import gdsMill
|
||||||
import debug
|
import debug
|
||||||
|
|
@ -839,10 +840,10 @@ class layout():
|
||||||
#hcg = {}
|
#hcg = {}
|
||||||
|
|
||||||
# Initialize the vertical conflict graph (vcg) and make a list of all pins
|
# 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
|
# Create names for the nets for the graphs
|
||||||
nets = {}
|
nets = collections.OrderedDict()
|
||||||
index = 0
|
index = 0
|
||||||
#print(netlist)
|
#print(netlist)
|
||||||
for pin_list in netlist:
|
for pin_list in netlist:
|
||||||
|
|
|
||||||
|
|
@ -319,13 +319,13 @@ class spice():
|
||||||
corner_slew = SLEW_APPROXIMATION*corner_delay
|
corner_slew = SLEW_APPROXIMATION*corner_delay
|
||||||
return delay_data(corner_delay, corner_slew)
|
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"""
|
"""Inform users undefined delay module while building new modules"""
|
||||||
debug.warning("Design Class {0} logical effort function needs to be defined"
|
debug.warning("Design Class {0} logical effort function needs to be defined"
|
||||||
.format(self.__class__.__name__))
|
.format(self.__class__.__name__))
|
||||||
debug.warning("Class {0} name {1}"
|
debug.warning("Class {0} name {1}"
|
||||||
.format(self.__class__.__name__,
|
.format(self.__class__.__name__,
|
||||||
self.name))
|
self.name))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_cin(self):
|
def get_cin(self):
|
||||||
|
|
@ -392,7 +392,7 @@ class spice():
|
||||||
"""Returns delay increase due to voltage.
|
"""Returns delay increase due to voltage.
|
||||||
Implemented as linear factor based off nominal 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):
|
def get_temp_delay_factor(self, temp):
|
||||||
"""Returns delay increase due to temperature (in C).
|
"""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
|
#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
|
#(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_nom = 0.008625*tech.spice["nom_temperature"]
|
||||||
thermal_voltage = .008625*temp
|
thermal_voltage = 0.008625*temp
|
||||||
vthresh = (tech.spice["v_threshold_typical"]+2*(thermal_voltage-thermal_voltage_nom))
|
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.
|
#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):
|
def return_delay(self, delay, slew):
|
||||||
return delay_data(delay, slew)
|
return delay_data(delay, slew)
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ class delay(simulation):
|
||||||
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
||||||
|
|
||||||
port = self.read_ports[0]
|
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))
|
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||||
|
|
||||||
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
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):
|
def get_address_row_number(self, probe_address):
|
||||||
"""Calculates wordline row number of data bit under test using address and column mux size"""
|
"""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)
|
return int(probe_address[self.sram.col_addr_size:],2)
|
||||||
|
|
||||||
def prepare_netlist(self):
|
def prepare_netlist(self):
|
||||||
|
|
@ -1285,13 +1285,13 @@ class delay(simulation):
|
||||||
debug.warning("Analytical characterization results are not supported for multiport.")
|
debug.warning("Analytical characterization results are not supported for multiport.")
|
||||||
|
|
||||||
# Probe set to 0th bit, does not matter for analytical delay.
|
# 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.create_graph()
|
||||||
self.set_internal_spice_names()
|
self.set_internal_spice_names()
|
||||||
self.create_measurement_names()
|
self.create_measurement_names()
|
||||||
|
|
||||||
port = self.read_ports[0]
|
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))
|
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||||
|
|
||||||
# Select the path with the bitline (bl)
|
# Select the path with the bitline (bl)
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ class functional(simulation):
|
||||||
|
|
||||||
# Generate CLK signals
|
# Generate CLK signals
|
||||||
for port in self.all_ports:
|
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,
|
v1=self.gnd_voltage,
|
||||||
v2=self.vdd_voltage,
|
v2=self.vdd_voltage,
|
||||||
offset=self.period,
|
offset=self.period,
|
||||||
|
|
@ -402,7 +402,7 @@ class functional(simulation):
|
||||||
|
|
||||||
# For now, only testing these using first read port.
|
# For now, only testing these using first read port.
|
||||||
port = self.read_ports[0]
|
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())
|
'{}{}_{}'.format(self.dout_name, port, 0).lower())
|
||||||
|
|
||||||
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,8 @@ class lib:
|
||||||
#set the read and write port as inputs.
|
#set the read and write port as inputs.
|
||||||
self.write_data_bus(port)
|
self.write_data_bus(port)
|
||||||
self.write_addr_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_control_pins(port) #need to split this into sram and port control signals
|
||||||
self.write_clk_timing_power(port)
|
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(" bit_to : {0};\n".format(self.sram.addr_size - 1))
|
||||||
self.lib.write(" }\n\n")
|
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):
|
def write_FF_setuphold(self, port):
|
||||||
""" Adds Setup and Hold timing results"""
|
""" Adds Setup and Hold timing results"""
|
||||||
|
|
@ -400,6 +411,20 @@ class lib:
|
||||||
self.lib.write(" }\n")
|
self.lib.write(" }\n")
|
||||||
self.lib.write(" }\n\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):
|
def write_control_pins(self, port):
|
||||||
""" Adds control pins timing results."""
|
""" Adds control pins timing results."""
|
||||||
|
|
|
||||||
|
|
@ -336,10 +336,10 @@ class setup_hold():
|
||||||
for self.related_input_slew in related_slews:
|
for self.related_input_slew in related_slews:
|
||||||
for self.constrained_input_slew in constrained_slews:
|
for self.constrained_input_slew in constrained_slews:
|
||||||
# convert from ps to ns
|
# convert from ps to ns
|
||||||
LH_setup.append(tech.spice["msflop_setup"]/1e3)
|
LH_setup.append(tech.spice["dff_setup"]/1e3)
|
||||||
HL_setup.append(tech.spice["msflop_setup"]/1e3)
|
HL_setup.append(tech.spice["dff_setup"]/1e3)
|
||||||
LH_hold.append(tech.spice["msflop_hold"]/1e3)
|
LH_hold.append(tech.spice["dff_hold"]/1e3)
|
||||||
HL_hold.append(tech.spice["msflop_hold"]/1e3)
|
HL_hold.append(tech.spice["dff_hold"]/1e3)
|
||||||
|
|
||||||
times = {"setup_times_LH": LH_setup,
|
times = {"setup_times_LH": LH_setup,
|
||||||
"setup_times_HL": HL_setup,
|
"setup_times_HL": HL_setup,
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ class simulation():
|
||||||
""" sets feasible timing parameters """
|
""" sets feasible timing parameters """
|
||||||
self.period = tech.spice["feasible_period"]
|
self.period = tech.spice["feasible_period"]
|
||||||
self.slew = tech.spice["rise_time"]*2
|
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_high = self.vdd_voltage - tech.spice["nom_threshold"]
|
||||||
self.v_low = tech.spice["v_threshold_typical"]
|
self.v_low = tech.spice["nom_threshold"]
|
||||||
self.gnd_voltage = 0
|
self.gnd_voltage = 0
|
||||||
|
|
||||||
def create_signal_names(self):
|
def create_signal_names(self):
|
||||||
|
|
@ -301,7 +301,7 @@ class simulation():
|
||||||
pin_names.append("WEB{0}".format(port))
|
pin_names.append("WEB{0}".format(port))
|
||||||
|
|
||||||
for port in range(total_ports):
|
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:
|
if self.write_size:
|
||||||
for port in write_index:
|
for port in write_index:
|
||||||
|
|
@ -312,7 +312,7 @@ class simulation():
|
||||||
for i in range(dbits):
|
for i in range(dbits):
|
||||||
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
|
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("vdd"))
|
||||||
pin_names.append("{0}".format(tech.spice["gnd_name"]))
|
pin_names.append("{0}".format("gnd"))
|
||||||
return pin_names
|
return pin_names
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ class stimuli():
|
||||||
""" Class for providing stimuli functions """
|
""" Class for providing stimuli functions """
|
||||||
|
|
||||||
def __init__(self, stim_file, corner):
|
def __init__(self, stim_file, corner):
|
||||||
self.vdd_name = tech.spice["vdd_name"]
|
self.vdd_name = "vdd"
|
||||||
self.gnd_name = tech.spice["gnd_name"]
|
self.gnd_name = "gnd"
|
||||||
self.pmos_name = tech.spice["pmos"]
|
self.pmos_name = tech.spice["pmos"]
|
||||||
self.nmos_name = tech.spice["nmos"]
|
self.nmos_name = tech.spice["nmos"]
|
||||||
self.tx_width = tech.spice["minwidth_tx"]
|
self.tx_width = tech.drc["minwidth_tx"]
|
||||||
self.tx_length = tech.spice["channel"]
|
self.tx_length = tech.drc["minlength_channel"]
|
||||||
|
|
||||||
self.sf = stim_file
|
self.sf = stim_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).")
|
debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).")
|
||||||
|
|
||||||
if not OPTS.route_supplies:
|
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:
|
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:
|
if not OPTS.check_lvsdrc:
|
||||||
debug.print_raw("DRC/LVS/PEX is disabled (check_lvsdrc=True to enable).")
|
debug.print_raw("DRC/LVS/PEX is disabled (check_lvsdrc=True to enable).")
|
||||||
|
|
||||||
if OPTS.analytical_delay:
|
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:
|
else:
|
||||||
if OPTS.spice_name!="":
|
if OPTS.spice_name!="":
|
||||||
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,9 @@ class bank(design.design):
|
||||||
# Remember the bank center for further placement
|
# Remember the bank center for further placement
|
||||||
self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1)
|
self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1)
|
||||||
self.bank_array_ur = self.bitcell_array_inst.ur()
|
self.bank_array_ur = self.bitcell_array_inst.ur()
|
||||||
|
self.bank_array_ul = self.bitcell_array_inst.ul()
|
||||||
|
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
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()))
|
connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
|
||||||
|
|
||||||
if port in self.write_ports:
|
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:
|
if port in self.read_ports:
|
||||||
connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
|
connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ class bitcell_array(design.design):
|
||||||
bl_wire = self.gen_bl_wire()
|
bl_wire = self.gen_bl_wire()
|
||||||
cell_load = 2 * bl_wire.return_input_cap()
|
cell_load = 2 * bl_wire.return_input_cap()
|
||||||
bl_swing = OPTS.rbl_delay_percentage
|
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)
|
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
|
||||||
|
|
||||||
#Calculate the bitcell power which currently only includes leakage
|
#Calculate the bitcell power which currently only includes leakage
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ class dff(design.design):
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
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_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)
|
total_power = self.return_power(power_dyn, power_leak)
|
||||||
return total_power
|
return total_power
|
||||||
|
|
@ -44,8 +44,8 @@ class dff(design.design):
|
||||||
"""Computes effective capacitance. Results in fF"""
|
"""Computes effective capacitance. Results in fF"""
|
||||||
from tech import parameter
|
from tech import parameter
|
||||||
c_load = load
|
c_load = load
|
||||||
c_para = spice["flop_para_cap"]#ff
|
c_para = spice["dff_out_cap"]#ff
|
||||||
transition_prob = spice["flop_transition_prob"]
|
transition_prob = 0.5
|
||||||
return transition_prob*(c_load + c_para)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def get_clk_cin(self):
|
def get_clk_cin(self):
|
||||||
|
|
@ -57,4 +57,4 @@ class dff(design.design):
|
||||||
def build_graph(self, graph, inst_name, port_nets):
|
def build_graph(self, graph, inst_name, port_nets):
|
||||||
"""Adds edges based on inputs/outputs. Overrides base class function."""
|
"""Adds edges based on inputs/outputs. Overrides base class function."""
|
||||||
self.add_graph_edges(graph, port_nets)
|
self.add_graph_edges(graph, port_nets)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ class port_data(design.design):
|
||||||
|
|
||||||
sram_config.set_local_config(self)
|
sram_config.set_local_config(self)
|
||||||
self.port = port
|
self.port = port
|
||||||
if self.write_size:
|
if self.write_size is not None:
|
||||||
self.num_wmasks = int(self.word_size/self.write_size)
|
self.num_wmasks = int(self.word_size/self.write_size)
|
||||||
else:
|
else:
|
||||||
self.num_wmasks = 0
|
self.num_wmasks = 0
|
||||||
|
|
||||||
if name == "":
|
if name == "":
|
||||||
name = "port_data_{0}".format(self.port)
|
name = "port_data_{0}".format(self.port)
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
@ -58,7 +58,7 @@ class port_data(design.design):
|
||||||
|
|
||||||
if self.write_driver_array:
|
if self.write_driver_array:
|
||||||
self.create_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()
|
self.create_write_mask_and_array()
|
||||||
else:
|
else:
|
||||||
self.write_mask_and_array_inst = None
|
self.write_mask_and_array_inst = None
|
||||||
|
|
@ -70,9 +70,9 @@ class port_data(design.design):
|
||||||
self.create_column_mux_array()
|
self.create_column_mux_array()
|
||||||
else:
|
else:
|
||||||
self.column_mux_array_inst = None
|
self.column_mux_array_inst = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.compute_instance_offsets()
|
self.compute_instance_offsets()
|
||||||
self.place_instances()
|
self.place_instances()
|
||||||
|
|
@ -81,7 +81,7 @@ class port_data(design.design):
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adding pins for port address module"""
|
""" Adding pins for port address module"""
|
||||||
|
|
||||||
self.add_pin("rbl_bl","INOUT")
|
self.add_pin("rbl_bl","INOUT")
|
||||||
self.add_pin("rbl_br","INOUT")
|
self.add_pin("rbl_br","INOUT")
|
||||||
for bit in range(self.num_cols):
|
for bit in range(self.num_cols):
|
||||||
|
|
@ -107,7 +107,7 @@ class port_data(design.design):
|
||||||
self.add_pin("vdd","POWER")
|
self.add_pin("vdd","POWER")
|
||||||
self.add_pin("gnd","GROUND")
|
self.add_pin("gnd","GROUND")
|
||||||
|
|
||||||
|
|
||||||
def route_layout(self):
|
def route_layout(self):
|
||||||
""" Create routing among the modules """
|
""" Create routing among the modules """
|
||||||
self.route_data_lines()
|
self.route_data_lines()
|
||||||
|
|
@ -118,15 +118,15 @@ class port_data(design.design):
|
||||||
""" Add the pins """
|
""" Add the pins """
|
||||||
self.route_bitline_pins()
|
self.route_bitline_pins()
|
||||||
self.route_control_pins()
|
self.route_control_pins()
|
||||||
|
|
||||||
def route_data_lines(self):
|
def route_data_lines(self):
|
||||||
""" Route the bitlines depending on the port type rw, w, or r. """
|
""" Route the bitlines depending on the port type rw, w, or r. """
|
||||||
|
|
||||||
if self.port in self.readwrite_ports:
|
if self.port in self.readwrite_ports:
|
||||||
# (write_mask_and ->) write_driver -> sense_amp -> (column_mux ->) precharge -> bitcell_array
|
# (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_in(self.port)
|
||||||
self.route_write_mask_and_array_to_write_driver(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_sense_amp_out(self.port)
|
||||||
self.route_write_driver_to_sense_amp(self.port)
|
self.route_write_driver_to_sense_amp(self.port)
|
||||||
self.route_sense_amp_to_column_mux_or_precharge_array(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_mask_and_array_to_write_driver(self.port)
|
||||||
self.route_write_driver_in(self.port)
|
self.route_write_driver_in(self.port)
|
||||||
self.route_write_driver_to_column_mux_or_precharge_array(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):
|
def route_supplies(self):
|
||||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||||
|
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
self.copy_power_pins(inst,"vdd")
|
self.copy_power_pins(inst,"vdd")
|
||||||
self.copy_power_pins(inst,"gnd")
|
self.copy_power_pins(inst,"gnd")
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
|
|
||||||
# Extra column +1 is for RBL
|
# Extra column +1 is for RBL
|
||||||
|
|
@ -163,23 +163,23 @@ class port_data(design.design):
|
||||||
|
|
||||||
if self.port in self.read_ports:
|
if self.port in self.read_ports:
|
||||||
self.sense_amp_array = factory.create(module_type="sense_amp_array",
|
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)
|
words_per_row=self.words_per_row)
|
||||||
self.add_mod(self.sense_amp_array)
|
self.add_mod(self.sense_amp_array)
|
||||||
else:
|
else:
|
||||||
self.sense_amp_array = None
|
self.sense_amp_array = None
|
||||||
|
|
||||||
|
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
self.column_mux_array = factory.create(module_type="column_mux_array",
|
self.column_mux_array = factory.create(module_type="column_mux_array",
|
||||||
columns=self.num_cols,
|
columns=self.num_cols,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
bitcell_bl=self.bl_names[self.port],
|
bitcell_bl=self.bl_names[self.port],
|
||||||
bitcell_br=self.br_names[self.port])
|
bitcell_br=self.br_names[self.port])
|
||||||
self.add_mod(self.column_mux_array)
|
self.add_mod(self.column_mux_array)
|
||||||
else:
|
else:
|
||||||
self.column_mux_array = None
|
self.column_mux_array = None
|
||||||
|
|
||||||
|
|
||||||
if self.port in self.write_ports:
|
if self.port in self.write_ports:
|
||||||
self.write_driver_array = factory.create(module_type="write_driver_array",
|
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,
|
word_size=self.word_size,
|
||||||
write_size=self.write_size)
|
write_size=self.write_size)
|
||||||
self.add_mod(self.write_driver_array)
|
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",
|
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
|
||||||
columns=self.num_cols,
|
columns=self.num_cols,
|
||||||
word_size=self.word_size,
|
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)
|
self.add_mod(self.write_mask_and_array)
|
||||||
else:
|
else:
|
||||||
self.write_mask_and_array = None
|
self.write_mask_and_array = None
|
||||||
|
|
@ -207,8 +208,8 @@ class port_data(design.design):
|
||||||
if self.col_addr_size>0:
|
if self.col_addr_size>0:
|
||||||
self.num_col_addr_lines = 2**self.col_addr_size
|
self.num_col_addr_lines = 2**self.col_addr_size
|
||||||
else:
|
else:
|
||||||
self.num_col_addr_lines = 0
|
self.num_col_addr_lines = 0
|
||||||
|
|
||||||
|
|
||||||
# A space for wells or jogging m2 between modules
|
# A space for wells or jogging m2 between modules
|
||||||
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
|
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
|
# 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.bl_names = self.bitcell.get_all_bl_names()
|
||||||
self.br_names = self.bitcell.get_all_br_names()
|
self.br_names = self.bitcell.get_all_br_names()
|
||||||
self.wl_names = self.bitcell.get_all_wl_names()
|
self.wl_names = self.bitcell.get_all_wl_names()
|
||||||
|
|
@ -226,7 +227,7 @@ class port_data(design.design):
|
||||||
if not self.precharge_array:
|
if not self.precharge_array:
|
||||||
self.precharge_array_inst = None
|
self.precharge_array_inst = None
|
||||||
return
|
return
|
||||||
|
|
||||||
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
|
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
|
||||||
mod=self.precharge_array)
|
mod=self.precharge_array)
|
||||||
|
|
||||||
|
|
@ -245,16 +246,16 @@ class port_data(design.design):
|
||||||
temp.extend(["p_en_bar", "vdd"])
|
temp.extend(["p_en_bar", "vdd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
def place_precharge_array(self, offset):
|
def place_precharge_array(self, offset):
|
||||||
""" Placing Precharge """
|
""" Placing Precharge """
|
||||||
|
|
||||||
self.precharge_array_inst.place(offset=offset, mirror="MX")
|
self.precharge_array_inst.place(offset=offset, mirror="MX")
|
||||||
|
|
||||||
|
|
||||||
def create_column_mux_array(self):
|
def create_column_mux_array(self):
|
||||||
""" Creating Column Mux when words_per_row > 1 . """
|
""" Creating Column Mux when words_per_row > 1 . """
|
||||||
|
|
||||||
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
|
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
|
||||||
mod=self.column_mux_array)
|
mod=self.column_mux_array)
|
||||||
|
|
||||||
|
|
@ -270,15 +271,15 @@ class port_data(design.design):
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
def place_column_mux_array(self, offset):
|
def place_column_mux_array(self, offset):
|
||||||
""" Placing Column Mux when words_per_row > 1 . """
|
""" Placing Column Mux when words_per_row > 1 . """
|
||||||
if self.col_addr_size == 0:
|
if self.col_addr_size == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.column_mux_array_inst.place(offset=offset, mirror="MX")
|
self.column_mux_array_inst.place(offset=offset, mirror="MX")
|
||||||
|
|
||||||
|
|
||||||
def create_sense_amp_array(self):
|
def create_sense_amp_array(self):
|
||||||
""" Creating Sense amp """
|
""" Creating Sense amp """
|
||||||
self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
|
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:
|
else:
|
||||||
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
|
temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
|
||||||
temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
|
temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
|
||||||
|
|
||||||
temp.extend(["s_en", "vdd", "gnd"])
|
temp.extend(["s_en", "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
def place_sense_amp_array(self, offset):
|
def place_sense_amp_array(self, offset):
|
||||||
""" Placing Sense amp """
|
""" Placing Sense amp """
|
||||||
self.sense_amp_array_inst.place(offset=offset, mirror="MX")
|
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.bl_names[self.port] + "_out_{0}".format(bit))
|
||||||
temp.append(self.br_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):
|
for i in range(self.num_wmasks):
|
||||||
temp.append("wdriver_sel_{}".format(i))
|
temp.append("wdriver_sel_{}".format(i))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -382,7 +382,7 @@ class replica_bitcell_array(design.design):
|
||||||
bl_wire = self.gen_bl_wire()
|
bl_wire = self.gen_bl_wire()
|
||||||
cell_load = 2 * bl_wire.return_input_cap()
|
cell_load = 2 * bl_wire.return_input_cap()
|
||||||
bl_swing = OPTS.rbl_delay_percentage
|
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)
|
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
|
||||||
|
|
||||||
#Calculate the bitcell power which currently only includes leakage
|
#Calculate the bitcell power which currently only includes leakage
|
||||||
|
|
|
||||||
|
|
@ -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.
|
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)
|
design.design.__init__(self, name)
|
||||||
debug.info(1, "Creating {0}".format(self.name))
|
debug.info(1, "Creating {0}".format(self.name))
|
||||||
self.add_comment("columns: {0}".format(columns))
|
self.add_comment("columns: {0}".format(columns))
|
||||||
|
|
@ -30,6 +30,7 @@ class write_mask_and_array(design.design):
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
self.word_size = word_size
|
self.word_size = word_size
|
||||||
self.write_size = write_size
|
self.write_size = write_size
|
||||||
|
self.port = port
|
||||||
self.words_per_row = int(columns / word_size)
|
self.words_per_row = int(columns / word_size)
|
||||||
self.num_wmasks = int(word_size / write_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):
|
def add_layout_pins(self):
|
||||||
self.nand2 = factory.create(module_type="pnand2")
|
self.nand2 = factory.create(module_type="pnand2")
|
||||||
supply_pin=self.nand2.get_pin("vdd")
|
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")
|
en_pin = self.and2_insts[i].get_pin("B")
|
||||||
# Add the M1->M2 stack
|
|
||||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||||
offset=en_pin.center())
|
offset=en_pin.center())
|
||||||
# Add the M2->M3 stack
|
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
offset=en_pin.center())
|
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("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))
|
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:
|
if i < self.num_wmasks-1:
|
||||||
for n in ["gnd","vdd"]:
|
for n in ["gnd","vdd"]:
|
||||||
pin = self.and2_insts[i].get_pin(n)
|
pin = self.and2_insts[i].get_pin(n)
|
||||||
next_pin = self.and2_insts[i+1].get_pin(n)
|
next_pin = self.and2_insts[i+1].get_pin(n)
|
||||||
self.add_path("metal1",[pin.center(),next_pin.center()])
|
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):
|
def get_cin(self):
|
||||||
"""Get the relative capacitance of all the input connections in the bank"""
|
"""Get the relative capacitance of all the input connections in the bank"""
|
||||||
# The enable is connected to an and2 for every row.
|
# The enable is connected to an and2 for every row.
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,7 @@ debug.print_raw("Words per row: {}".format(c.words_per_row))
|
||||||
output_extensions = ["sp","v","lib","py","html","log"]
|
output_extensions = ["sp","v","lib","py","html","log"]
|
||||||
# Only output lef/gds if back-end
|
# Only output lef/gds if back-end
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
output_extensions.extend(["lef"])
|
output_extensions.extend(["lef","gds"])
|
||||||
# Only output gds if final routing
|
|
||||||
if OPTS.route_supplies:
|
|
||||||
output_extensions.extend(["gds"])
|
|
||||||
|
|
||||||
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
|
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
|
||||||
debug.print_raw("Output files are: ")
|
debug.print_raw("Output files are: ")
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,7 @@ class pinv(pgate.pgate):
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
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_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["inv_leakage"]
|
power_leak = spice["inv_leakage"]
|
||||||
|
|
||||||
|
|
@ -269,7 +269,7 @@ class pinv(pgate.pgate):
|
||||||
"""Computes effective capacitance. Results in fF"""
|
"""Computes effective capacitance. Results in fF"""
|
||||||
c_load = load
|
c_load = load
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
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)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ class pnand2(pgate.pgate):
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
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_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nand2_leakage"]
|
power_leak = spice["nand2_leakage"]
|
||||||
|
|
||||||
|
|
@ -244,7 +244,7 @@ class pnand2(pgate.pgate):
|
||||||
"""Computes effective capacitance. Results in fF"""
|
"""Computes effective capacitance. Results in fF"""
|
||||||
c_load = load
|
c_load = load
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
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)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ class pnand3(pgate.pgate):
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
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_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nand3_leakage"]
|
power_leak = spice["nand3_leakage"]
|
||||||
|
|
||||||
|
|
@ -257,7 +257,7 @@ class pnand3(pgate.pgate):
|
||||||
"""Computes effective capacitance. Results in fF"""
|
"""Computes effective capacitance. Results in fF"""
|
||||||
c_load = load
|
c_load = load
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
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)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ class pnor2(pgate.pgate):
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Returns dynamic and leakage power. Results in nW"""
|
"""Returns dynamic and leakage power. Results in nW"""
|
||||||
c_eff = self.calculate_effective_capacitance(load)
|
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_dyn = self.calc_dynamic_power(corner, c_eff, freq)
|
||||||
power_leak = spice["nor2_leakage"]
|
power_leak = spice["nor2_leakage"]
|
||||||
|
|
||||||
|
|
@ -241,7 +241,7 @@ class pnor2(pgate.pgate):
|
||||||
"""Computes effective capacitance. Results in fF"""
|
"""Computes effective capacitance. Results in fF"""
|
||||||
c_load = load
|
c_load = load
|
||||||
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
|
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)
|
return transition_prob*(c_load + c_para)
|
||||||
|
|
||||||
def build_graph(self, graph, inst_name, port_nets):
|
def build_graph(self, graph, inst_name, port_nets):
|
||||||
|
|
|
||||||
|
|
@ -75,13 +75,12 @@ class sram():
|
||||||
self.lef_write(lefname)
|
self.lef_write(lefname)
|
||||||
print_time("LEF", datetime.datetime.now(), start_time)
|
print_time("LEF", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
if OPTS.route_supplies:
|
# Write the layout
|
||||||
# Write the layout
|
start_time = datetime.datetime.now()
|
||||||
start_time = datetime.datetime.now()
|
gdsname = OPTS.output_path + self.s.name + ".gds"
|
||||||
gdsname = OPTS.output_path + self.s.name + ".gds"
|
debug.print_raw("GDS: Writing to {0}".format(gdsname))
|
||||||
debug.print_raw("GDS: Writing to {0}".format(gdsname))
|
self.gds_write(gdsname)
|
||||||
self.gds_write(gdsname)
|
print_time("GDS", datetime.datetime.now(), start_time)
|
||||||
print_time("GDS", datetime.datetime.now(), start_time)
|
|
||||||
|
|
||||||
# Save the spice file
|
# Save the spice file
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
|
|
@ -130,4 +129,4 @@ class sram():
|
||||||
vname = OPTS.output_path + self.s.name + ".v"
|
vname = OPTS.output_path + self.s.name + ".v"
|
||||||
debug.print_raw("Verilog: Writing to {0}".format(vname))
|
debug.print_raw("Verilog: Writing to {0}".format(vname))
|
||||||
self.verilog_write(vname)
|
self.verilog_write(vname)
|
||||||
print_time("Verilog", datetime.datetime.now(), start_time)
|
print_time("Verilog", datetime.datetime.now(), start_time)
|
||||||
|
|
|
||||||
|
|
@ -70,46 +70,51 @@ class sram_1bank(sram_base):
|
||||||
wmask_pos = [None]*len(self.all_ports)
|
wmask_pos = [None]*len(self.all_ports)
|
||||||
data_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
|
if self.write_size:
|
||||||
# The M1 pitch is for supply rail spacings
|
max_gap_size = self.m3_pitch*self.word_size + 2*self.m1_pitch
|
||||||
max_gap_size = self.m2_pitch*max(self.word_size+1,self.col_addr_size+1) + 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
|
||||||
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.
|
# Add the write mask flops below the write mask AND array.
|
||||||
wmask_pos[port] = vector(self.bank.bank_array_ll.x,
|
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])
|
self.wmask_dff_insts[port].place(wmask_pos[port])
|
||||||
|
|
||||||
# Add the data flops below the write mask flops.
|
# Add the data flops below the write mask flops.
|
||||||
data_pos[port] = vector(self.bank.bank_array_ll.x,
|
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])
|
self.data_dff_insts[port].place(data_pos[port])
|
||||||
else:
|
else:
|
||||||
wmask_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
|
||||||
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
|
# 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:
|
else:
|
||||||
# Add the data flops below the bank to the right of the lower-left of bank array
|
wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0)
|
||||||
# This relies on the lower-left of the array of the bank
|
data_pos[port] = vector(self.bank.bank_array_ll.x,0)
|
||||||
# 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:
|
|
||||||
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
|
# Add the col address flops below the bank to the left of the lower-left of bank array
|
||||||
if self.col_addr_dff:
|
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,
|
if self.write_size:
|
||||||
-max_gap_size - self.col_addr_dff_insts[port].height)
|
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])
|
self.col_addr_dff_insts[port].place(col_addr_pos[port])
|
||||||
else:
|
else:
|
||||||
col_addr_pos[port] = vector(self.bank.bank_array_ll.x,0)
|
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)
|
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)
|
row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(row_addr_pos[port])
|
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:
|
if len(self.all_ports)>1:
|
||||||
# Port 1
|
# Port 1
|
||||||
|
|
@ -140,15 +138,14 @@ class sram_1bank(sram_base):
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
# Add the write mask flops below the write mask AND array.
|
# 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,
|
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width,
|
||||||
self.bank.height + 0.5*max_gap_size + self.dff.height)
|
self.bank.height + max_gap_size_wmask + self.dff.height)
|
||||||
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
|
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
|
||||||
|
|
||||||
# Add the data flops below the write mask flops
|
# 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,
|
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")
|
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Add the data flops above the bank to the left of the upper-right of bank array
|
# 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
|
# 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
|
# Add the col address flops above the bank to the right of the upper-right of bank array
|
||||||
if self.col_addr_dff:
|
if self.col_addr_dff:
|
||||||
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
|
if self.write_size:
|
||||||
self.bank.height + max_gap_size + self.dff.height)
|
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")
|
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
|
||||||
else:
|
else:
|
||||||
col_addr_pos[port] = self.bank_inst.ur()
|
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 """
|
""" Connect the output of the data flops to the write driver """
|
||||||
# This is where the channel will start (y-dimension at least)
|
# This is where the channel will start (y-dimension at least)
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
if port%2:
|
if self.write_size:
|
||||||
offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
|
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:
|
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_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]
|
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]
|
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
for x in bank_names:
|
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"),
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||||
offset=pin_offset)
|
offset=pin_offset)
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
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)
|
# This is where the channel will start (y-dimension at least)
|
||||||
for port in self.write_ports:
|
for port in self.write_ports:
|
||||||
if port % 2:
|
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:
|
else:
|
||||||
offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch)
|
offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class sram_base(design, verilog, lef):
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, sram_config):
|
def __init__(self, name, sram_config):
|
||||||
design.__init__(self, name)
|
design.__init__(self, name)
|
||||||
lef.__init__(self, ["metal1", "metal2", "metal3"])
|
lef.__init__(self, ["metal1", "metal2", "metal3", "metal4"])
|
||||||
verilog.__init__(self)
|
verilog.__init__(self)
|
||||||
|
|
||||||
self.sram_config = sram_config
|
self.sram_config = sram_config
|
||||||
|
|
@ -120,7 +120,7 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
self.add_lvs_correspondence_points()
|
self.add_lvs_correspondence_points()
|
||||||
|
|
||||||
#self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
|
||||||
highest_coord = self.find_highest_coords()
|
highest_coord = self.find_highest_coords()
|
||||||
self.width = highest_coord[0]
|
self.width = highest_coord[0]
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -54,7 +54,7 @@ class timing_sram_test(openram_test):
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
d = delay(s.s, tempspice, corner)
|
d = delay(s.s, tempspice, corner)
|
||||||
import tech
|
import tech
|
||||||
loads = [tech.spice["msflop_in_cap"]*4]
|
loads = [tech.spice["dff_in_cap"]*4]
|
||||||
slews = [tech.spice["rise_time"]*2]
|
slews = [tech.spice["rise_time"]*2]
|
||||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
||||||
#Combine info about port into all data
|
#Combine info about port into all data
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class model_delay_test(openram_test):
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
d = delay(s.s, tempspice, corner)
|
d = delay(s.s, tempspice, corner)
|
||||||
import tech
|
import tech
|
||||||
loads = [tech.spice["msflop_in_cap"]*4]
|
loads = [tech.spice["dff_in_cap"]*4]
|
||||||
slews = [tech.spice["rise_time"]*2]
|
slews = [tech.spice["rise_time"]*2]
|
||||||
|
|
||||||
# Run a spice characterization
|
# Run a spice characterization
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class timing_sram_test(openram_test):
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
d = delay(s.s, tempspice, corner)
|
d = delay(s.s, tempspice, corner)
|
||||||
import tech
|
import tech
|
||||||
loads = [tech.spice["msflop_in_cap"]*4]
|
loads = [tech.spice["dff_in_cap"]*4]
|
||||||
slews = [tech.spice["rise_time"]*2]
|
slews = [tech.spice["rise_time"]*2]
|
||||||
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
|
||||||
#Combine info about port into all data
|
#Combine info about port into all data
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class lib_model_corners_lib_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||||
|
OPTS.netlist_only = True
|
||||||
|
|
||||||
from characterizer import lib
|
from characterizer import lib
|
||||||
from sram import sram
|
from sram import sram
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ class lib_sram_model_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||||
|
OPTS.netlist_only = True
|
||||||
|
|
||||||
from characterizer import lib
|
from characterizer import lib
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,12 @@ class openram_back_end_test(openram_test):
|
||||||
os.chmod(out_path, 0o0750)
|
os.chmod(out_path, 0o0750)
|
||||||
|
|
||||||
# specify the same verbosity for the system call
|
# specify the same verbosity for the system call
|
||||||
verbosity = ""
|
options = ""
|
||||||
for i in range(OPTS.debug_level):
|
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
|
# Always perform code coverage
|
||||||
if OPTS.coverage == 0:
|
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,
|
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
|
||||||
out_file,
|
out_file,
|
||||||
out_path,
|
out_path,
|
||||||
verbosity,
|
options,
|
||||||
config_name,
|
config_name,
|
||||||
out_path)
|
out_path)
|
||||||
debug.info(1, cmd)
|
debug.info(1, cmd)
|
||||||
|
|
@ -83,10 +86,11 @@ class openram_back_end_test(openram_test):
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if os.path.exists(out_path):
|
if OPTS.purge_temp:
|
||||||
shutil.rmtree(out_path, ignore_errors=True)
|
if os.path.exists(out_path):
|
||||||
self.assertEqual(os.path.exists(out_path),False)
|
shutil.rmtree(out_path, ignore_errors=True)
|
||||||
|
self.assertEqual(os.path.exists(out_path),False)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,12 @@ class openram_front_end_test(openram_test):
|
||||||
os.chmod(out_path, 0o0750)
|
os.chmod(out_path, 0o0750)
|
||||||
|
|
||||||
# specify the same verbosity for the system call
|
# specify the same verbosity for the system call
|
||||||
verbosity = ""
|
options = ""
|
||||||
for i in range(OPTS.debug_level):
|
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
|
# Always perform code coverage
|
||||||
if OPTS.coverage == 0:
|
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,
|
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
|
||||||
out_file,
|
out_file,
|
||||||
out_path,
|
out_path,
|
||||||
verbosity,
|
options,
|
||||||
config_name,
|
config_name,
|
||||||
out_path)
|
out_path)
|
||||||
debug.info(1, cmd)
|
debug.info(1, cmd)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
|
||||||
# assert an error until we actually check a result
|
# 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)
|
filename = "{0}/{1}.{2}".format(out_path,out_file,extension)
|
||||||
debug.info(1,"Checking for file: " + filename)
|
debug.info(1,"Checking for file: " + filename)
|
||||||
self.assertEqual(os.path.exists(filename),True)
|
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
|
# Make sure there is any .lib file
|
||||||
import glob
|
import glob
|
||||||
|
|
@ -89,10 +86,11 @@ class openram_front_end_test(openram_test):
|
||||||
self.assertEqual(len(re.findall('WARNING',output)),0)
|
self.assertEqual(len(re.findall('WARNING',output)),0)
|
||||||
|
|
||||||
|
|
||||||
# now clean up the directory
|
# now clean up the directory
|
||||||
if os.path.exists(out_path):
|
if OPTS.purge_temp:
|
||||||
shutil.rmtree(out_path, ignore_errors=True)
|
if os.path.exists(out_path):
|
||||||
self.assertEqual(os.path.exists(out_path),False)
|
shutil.rmtree(out_path, ignore_errors=True)
|
||||||
|
self.assertEqual(os.path.exists(out_path),False)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -303,37 +303,16 @@ spice["fall_time"] = 0.005 # fall time in [Nano-seconds]
|
||||||
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
||||||
spice["nom_temperature"] = 25 # Nominal temperature (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
|
# analytical delay parameters
|
||||||
spice["vdd_nominal"] = 1.0 # Typical Threshold voltage in Volts
|
spice["nom_threshold"] = 0.4 # 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["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
|
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["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_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
|
||||||
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate 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_setup"] = 9 # DFF setup time in ps
|
||||||
spice["dff_hold"] = 1 # DFF hold 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_in_cap"] = 0.2091 # Input capacitance (D) [Femto-farad]
|
||||||
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
|
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
|
||||||
spice["dff_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad]
|
|
||||||
|
|
||||||
# analytical power parameters, many values are temporary
|
# analytical power parameters, many values are temporary
|
||||||
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
|
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["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
|
||||||
spice["nand3_leakage"] = 1 # Leakage power of 3-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["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
|
||||||
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
|
spice["dff_leakage"] = 1 # Leakage power of flop in nW
|
||||||
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
|
|
||||||
|
|
||||||
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
|
spice["default_event_frequency"] = 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.
|
|
||||||
|
|
||||||
#Parameters related to sense amp enable timing and delay chain/RBL sizing
|
#Parameters related to sense amp enable timing and delay chain/RBL sizing
|
||||||
parameter['le_tau'] = 2.25 #In pico-seconds.
|
parameter["le_tau"] = 2.25 #In pico-seconds.
|
||||||
parameter['cap_relative_per_ff'] = 7.5 #Units of Relative Capacitance/ Femto-Farad
|
parameter["cap_relative_per_ff"] = 7.5 #Units of Relative Capacitance/ Femto-Farad
|
||||||
parameter["dff_clk_cin"] = 30.6 #relative capacitance
|
parameter["dff_clk_cin"] = 30.6 #relative capacitance
|
||||||
parameter["6tcell_wl_cin"] = 3 #relative capacitance
|
parameter["6tcell_wl_cin"] = 3 #relative capacitance
|
||||||
parameter["min_inv_para_delay"] = 2.4 #Tau delay units
|
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_en_nmos_size"] = 0.27 #micro-meters
|
||||||
parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
|
parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
|
||||||
parameter["sa_inv_nmos_size"] = 0.27 #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
|
##END Spice Simulation Parameters
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -44,4 +44,14 @@ Contributions and modifications to this kit are welcomed and encouraged.
|
||||||
ncsu_basekit/ Base kit for custom design
|
ncsu_basekit/ Base kit for custom design
|
||||||
osu_soc/ Standard-cell kit for synthesis, place, & route
|
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
|
||||||
|
|
|
||||||
|
|
@ -1223,6 +1223,7 @@ drDefinePacket(
|
||||||
( display prBoundary blank solid purple purple )
|
( display prBoundary blank solid purple purple )
|
||||||
( display prBoundaryBnd blank solid cyan cyan )
|
( display prBoundaryBnd blank solid cyan cyan )
|
||||||
( display prBoundaryLbl blank solid purple purple )
|
( display prBoundaryLbl blank solid purple purple )
|
||||||
|
( display comment blank solid purple purple )
|
||||||
( display align blank solid tan tan )
|
( display align blank solid tan tan )
|
||||||
( display hardFence blank solid red red )
|
( display hardFence blank solid red red )
|
||||||
( display softFence blank solid yellow yellow )
|
( display softFence blank solid yellow yellow )
|
||||||
|
|
|
||||||
|
|
@ -219,8 +219,6 @@ spice["nmos"]="n"
|
||||||
spice["pmos"]="p"
|
spice["pmos"]="p"
|
||||||
# This is a map of corners to model files
|
# This is a map of corners to model files
|
||||||
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
|
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"],
|
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"],
|
"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"],
|
"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["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
||||||
spice["nom_temperature"] = 25 # Nominal temperature (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
|
# 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.
|
# 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_r"] = 0.075 # Unit wire resistance in ohms/square
|
||||||
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
|
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_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
|
||||||
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate 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_setup"] = 9 # DFF setup time in ps
|
||||||
spice["dff_hold"] = 1 # DFF hold 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_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
|
||||||
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
|
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
|
||||||
spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
|
|
||||||
|
|
||||||
# analytical power parameters, many values are temporary
|
# analytical power parameters, many values are temporary
|
||||||
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
|
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["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
|
||||||
spice["nand3_leakage"] = 1 # Leakage power of 3-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["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
|
||||||
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
|
spice["dff_leakage"] = 1 # Leakage power of flop in nW
|
||||||
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
|
|
||||||
|
|
||||||
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
|
spice["default_event_frequency"] = 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.
|
|
||||||
|
|
||||||
#Logical Effort relative values for the Handmade cells
|
#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["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["dff_clk_cin"] = 27.5 #In relative capacitance units
|
||||||
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
|
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
|
||||||
parameter["sa_en_pmos_size"] = 24*_lambda_
|
parameter["sa_en_pmos_size"] = 24*_lambda_
|
||||||
parameter["sa_en_nmos_size"] = 9*_lambda_
|
parameter["sa_en_nmos_size"] = 9*_lambda_
|
||||||
parameter["sa_inv_pmos_size"] = 18*_lambda_
|
parameter["sa_inv_pmos_size"] = 18*_lambda_
|
||||||
parameter["sa_inv_nmos_size"] = 9*_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
|
##END Spice Simulation Parameters
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ parameter={}
|
||||||
parameter["min_tx_size"] = 4*_lambda_
|
parameter["min_tx_size"] = 4*_lambda_
|
||||||
parameter["beta"] = 2
|
parameter["beta"] = 2
|
||||||
|
|
||||||
|
# These 6T sizes are used in the parameterized bitcell.
|
||||||
parameter["6T_inv_nmos_size"] = 8*_lambda_
|
parameter["6T_inv_nmos_size"] = 8*_lambda_
|
||||||
parameter["6T_inv_pmos_size"] = 3*_lambda_
|
parameter["6T_inv_pmos_size"] = 3*_lambda_
|
||||||
parameter["6T_access_size"] = 4*_lambda_
|
parameter["6T_access_size"] = 4*_lambda_
|
||||||
|
|
@ -246,8 +247,6 @@ spice["nmos"]="n"
|
||||||
spice["pmos"]="p"
|
spice["pmos"]="p"
|
||||||
# This is a map of corners to model files
|
# This is a map of corners to model files
|
||||||
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
|
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"],
|
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"],
|
"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"],
|
"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["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
||||||
spice["nom_temperature"] = 25 # Nominal temperature (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
|
# 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.
|
# 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_r"] = 0.075 # Unit wire resistance in ohms/square
|
||||||
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
|
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_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
|
||||||
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate 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_setup"] = 9 # DFF setup time in ps
|
||||||
spice["dff_hold"] = 1 # DFF hold 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_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
|
||||||
spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
|
spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
|
||||||
spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
|
|
||||||
|
|
||||||
# analytical power parameters, many values are temporary
|
# analytical power parameters, many values are temporary
|
||||||
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
|
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["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
|
||||||
spice["nand3_leakage"] = 1 # Leakage power of 3-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["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
|
||||||
spice["msflop_leakage"] = 1 # Leakage power of flop in nW
|
spice["dff_leakage"] = 1 # Leakage power of flop in nW
|
||||||
spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
|
|
||||||
|
|
||||||
spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
|
spice["default_event_frequency"] = 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.
|
|
||||||
|
|
||||||
#Logical Effort relative values for the Handmade cells
|
#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["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["dff_clk_cin"] = 27.5 #In relative capacitance units
|
||||||
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
|
parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
|
||||||
parameter["sa_en_pmos_size"] = 24*_lambda_
|
parameter["sa_en_pmos_size"] = 24*_lambda_
|
||||||
parameter["sa_en_nmos_size"] = 9*_lambda_
|
parameter["sa_en_nmos_size"] = 9*_lambda_
|
||||||
parameter["sa_inv_pmos_size"] = 18*_lambda_
|
parameter["sa_inv_pmos_size"] = 18*_lambda_
|
||||||
parameter["sa_inv_nmos_size"] = 9*_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
|
##END Spice Simulation Parameters
|
||||||
|
|
|
||||||
|
|
@ -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
|
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
|
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
|
|
@ -552,6 +552,8 @@ layerRules(
|
||||||
( ("P1Con" "drawing") 47 0 t )
|
( ("P1Con" "drawing") 47 0 t )
|
||||||
( ("Metal1" "drawing") 49 0 t )
|
( ("Metal1" "drawing") 49 0 t )
|
||||||
( ("Metal2" "drawing") 51 0 t )
|
( ("Metal2" "drawing") 51 0 t )
|
||||||
|
( ("Metal3" "drawing") 62 0 t )
|
||||||
|
( ("Metal4" "drawing") 31 0 t )
|
||||||
( ("annotate" "drawing") 0 0 nil )
|
( ("annotate" "drawing") 0 0 nil )
|
||||||
( ("annotate" "drawing1") 0 0 nil )
|
( ("annotate" "drawing1") 0 0 nil )
|
||||||
( ("annotate" "drawing2") 0 0 nil )
|
( ("annotate" "drawing2") 0 0 nil )
|
||||||
|
|
@ -562,7 +564,6 @@ layerRules(
|
||||||
( ("annotate" "drawing7") 0 0 nil )
|
( ("annotate" "drawing7") 0 0 nil )
|
||||||
( ("annotate" "drawing8") 0 0 nil )
|
( ("annotate" "drawing8") 0 0 nil )
|
||||||
( ("annotate" "drawing9") 0 0 nil )
|
( ("annotate" "drawing9") 0 0 nil )
|
||||||
( ("Via" "drawing") 50 0 t )
|
|
||||||
( ("Glass" "drawing") 52 0 t )
|
( ("Glass" "drawing") 52 0 t )
|
||||||
( ("XP" "drawing") 60 0 t )
|
( ("XP" "drawing") 60 0 t )
|
||||||
( ("Metal2" "pin") 0 0 nil )
|
( ("Metal2" "pin") 0 0 nil )
|
||||||
|
|
@ -590,8 +591,9 @@ layerRules(
|
||||||
( ("P1Con" "net") 0 0 nil )
|
( ("P1Con" "net") 0 0 nil )
|
||||||
( ("Metal1" "net") 0 0 nil )
|
( ("Metal1" "net") 0 0 nil )
|
||||||
( ("Metal2" "net") 0 0 nil )
|
( ("Metal2" "net") 0 0 nil )
|
||||||
|
( ("Metal3" "net") 0 0 nil )
|
||||||
|
( ("Metal4" "net") 0 0 nil )
|
||||||
( ("device" "label") 0 0 nil )
|
( ("device" "label") 0 0 nil )
|
||||||
( ("Via" "net") 0 0 nil )
|
|
||||||
( ("pin" "label") 0 0 nil )
|
( ("pin" "label") 0 0 nil )
|
||||||
( ("text" "drawing") 63 0 t )
|
( ("text" "drawing") 63 0 t )
|
||||||
( ("pin" "drawing") 0 0 nil )
|
( ("pin" "drawing") 0 0 nil )
|
||||||
|
|
@ -649,11 +651,12 @@ layerRules(
|
||||||
( Metal2 0 0 nil )
|
( Metal2 0 0 nil )
|
||||||
( Glass 0 0 nil )
|
( Glass 0 0 nil )
|
||||||
( XP 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 )
|
( ("Via2" "net") 0 0 nil )
|
||||||
( ("Metal3" "drawing") 50 0 t )
|
( ("Via3" "drawing") 30 0 t )
|
||||||
( ("Metal3" "net") 0 0 nil )
|
( ("Via3" "net") 0 0 nil )
|
||||||
( ("Metal3" "pin") 0 0 nil )
|
|
||||||
( ("CapWell" "drawing") 0 0 nil )
|
( ("CapWell" "drawing") 0 0 nil )
|
||||||
( ("CapWell" "net") 0 0 nil )
|
( ("CapWell" "net") 0 0 nil )
|
||||||
( ("SiBlock" "drawing") 0 0 nil )
|
( ("SiBlock" "drawing") 0 0 nil )
|
||||||
|
|
@ -665,6 +668,7 @@ layerRules(
|
||||||
viaLayers(
|
viaLayers(
|
||||||
;( layer1 viaLayer layer2 )
|
;( layer1 viaLayer layer2 )
|
||||||
;( ------ -------- ------ )
|
;( ------ -------- ------ )
|
||||||
|
( Metal3 Via3 Metal4 )
|
||||||
( Metal2 Via2 Metal3 )
|
( Metal2 Via2 Metal3 )
|
||||||
( Metal1 Via Metal2 )
|
( Metal1 Via Metal2 )
|
||||||
( Active ActX Poly1 )
|
( Active ActX Poly1 )
|
||||||
|
|
@ -798,6 +802,10 @@ electricalRules(
|
||||||
( currentDensity "Metal1" 1.0 )
|
( currentDensity "Metal1" 1.0 )
|
||||||
( currentDensity "Via" 1.0 )
|
( currentDensity "Via" 1.0 )
|
||||||
( currentDensity "Metal2" 1.0 )
|
( currentDensity "Metal2" 1.0 )
|
||||||
|
( currentDensity "Via2" 1.0 )
|
||||||
|
( currentDensity "Metal3" 1.0 )
|
||||||
|
( currentDensity "Via3" 1.0 )
|
||||||
|
( currentDensity "Metal4" 1.0 )
|
||||||
) ;characterizationRules
|
) ;characterizationRules
|
||||||
|
|
||||||
) ;electricalRules
|
) ;electricalRules
|
||||||
|
|
@ -824,10 +832,13 @@ leRules(
|
||||||
( Metal2 drawing )
|
( Metal2 drawing )
|
||||||
( Via2 drawing )
|
( Via2 drawing )
|
||||||
( Metal3 drawing )
|
( Metal3 drawing )
|
||||||
|
( Via3 drawing )
|
||||||
|
( Metal4 drawing )
|
||||||
( Poly1 pin )
|
( Poly1 pin )
|
||||||
( Metal1 pin )
|
( Metal1 pin )
|
||||||
( Metal2 pin )
|
( Metal2 pin )
|
||||||
( Metal3 pin )
|
( Metal3 pin )
|
||||||
|
( Metal4 pin )
|
||||||
( Poly2 drawing )
|
( Poly2 drawing )
|
||||||
( P2Con drawing )
|
( P2Con drawing )
|
||||||
( instance drawing )
|
( instance drawing )
|
||||||
|
|
@ -853,7 +864,7 @@ leRules(
|
||||||
|
|
||||||
lxRules(
|
lxRules(
|
||||||
lxExtractLayers(
|
lxExtractLayers(
|
||||||
(Metal1 Metal2 Metal3)
|
(Metal1 Metal2 Metal3 Metal4)
|
||||||
) ;lxExtractLayers
|
) ;lxExtractLayers
|
||||||
) ;lxRules
|
) ;lxRules
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue