Merge branch 'dev' into s8_single_port

This commit is contained in:
jcirimel 2020-11-03 03:45:34 -08:00
commit d69ca2b1ed
58 changed files with 594 additions and 447 deletions

View File

@ -51,8 +51,8 @@ class contact(hierarchy_design.hierarchy_design):
# Non-preferred directions
if directions == "nonpref":
first_dir = "H" if self.get_preferred_direction(layer_stack[0])=="V" else "V"
second_dir = "H" if self.get_preferred_direction(layer_stack[2])=="V" else "V"
first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V"
second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V"
self.directions = (first_dir, second_dir)
# Preferred directions
elif directions == "pref":

View File

@ -7,6 +7,7 @@
#
from globals import OPTS
class _pins:
def __init__(self, pin_dict):
# make the pins elements of the class to allow "." access.
@ -14,6 +15,7 @@ class _pins:
for k, v in pin_dict.items():
self.__dict__[k] = v
class _cell:
def __init__(self, pin_dict):
pin_dict.update(self._default_power_pins())
@ -24,13 +26,27 @@ class _cell:
return self._pins
def _default_power_pins(self):
return { 'vdd' : 'vdd', 'gnd' : 'gnd' }
return {'vdd': 'vdd',
'gnd': 'gnd'}
class _mirror_axis:
def __init__(self, x, y):
self.x = x
self.y = y
class _ptx:
def __init__(self, model_is_subckt, bin_spice_models):
self.model_is_subckt = model_is_subckt
self.bin_spice_models = bin_spice_models
class _pgate:
def __init__(self, add_implants):
self.add_implants = add_implants
class _bitcell:
def __init__(self, mirror, cell_s8_6t, cell_6t, cell_1rw1r, cell_1w1r):
self.mirror = mirror
@ -94,21 +110,25 @@ class _dff:
self.custom_type_list = custom_type_list
self.clk_pin = clk_pin
class _dff_buff:
def __init__(self, use_custom_ports, custom_buff_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports
self.buf_ports = custom_buff_ports
self.add_body_contacts = add_body_contacts
class _dff_buff_array:
def __init__(self, use_custom_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports
self.add_body_contacts = add_body_contacts
class _bitcell_array:
def __init__(self, use_custom_cell_arrangement):
self.use_custom_cell_arrangement = use_custom_cell_arrangement
class cell_properties():
"""
This contains meta information about the custom designed cells. For
@ -120,6 +140,11 @@ class cell_properties():
self._bitcell = _bitcell._default()
self._ptx = _ptx(model_is_subckt=False,
bin_spice_models=False)
self._pgate = _pgate(add_implants=False)
self._dff = _dff(use_custom_ports=False,
custom_port_list=["D", "Q", "clk", "vdd", "gnd"],
custom_type_list=["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
@ -148,6 +173,14 @@ class cell_properties():
def bitcell(self):
return self._bitcell
@property
def ptx(self):
return self._ptx
@property
def pgate(self):
return self._pgate
@property
def dff(self):
return self._dff

View File

@ -0,0 +1,193 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2020 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.
#
class _bank:
def __init__(self, stack, pitch):
# bank
# column address route: stack, pitch
# m1_stack, m2_pitch (default)
# m2_stack, m3_pitch (sky130)
self.stack = stack
self.pitch = pitch
class _hierarchical_decoder:
def __init__(self,
bus_layer,
bus_directions,
input_layer,
output_layer,
vertical_supply):
# hierarchical_decoder
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
# m2, pref, m2_pitch, m2_space, m1, m3, m3_pitch
# m1, nonpref, m1_pitch, m2_space, m2, li, li_pitch (sky130)
#
# vertical vdd/gnd
# special jogging
self.bus_layer = bus_layer
self.bus_directions = bus_directions
self.input_layer = input_layer
self.output_layer = output_layer
self.vertical_supply = vertical_supply
class _hierarchical_predecode:
def __init__(self,
bus_layer,
bus_directions,
bus_space_factor,
input_layer,
output_layer,
vertical_supply):
# hierarchical_predecode
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
# m2, pref, m2_pitch, m2_space, m1, m1, m1_pitch
# m1, nonpref, m1_pitch, 1`.5*m1_space, m2, li, li_pitch (sky130)
#
# vertical vdd/gnd
# special jogging
self.bus_layer = bus_layer
self.bus_directions = bus_directions
self.bus_space_factor = bus_space_factor
self.input_layer = input_layer
self.output_layer = output_layer
self.vertical_supply = vertical_supply
class _column_mux_array:
def __init__(self,
select_layer,
select_pitch,
bitline_layer):
# column_mux_array
# sel_layer, sel_pitch, bitline_layer
# m1, m2_pitch, m2
# m3, m3_pitch, m1 (sky130)
self.select_layer = select_layer
self.select_pitch= select_pitch
self.bitline_layer = bitline_layer
class _port_address:
def __init__(self,
supply_offset):
# port_adress
# special supply offset
self.supply_offset = supply_offset
class _port_data:
def __init__(self,
channel_route_bitlines,
enable_layer):
# port_data
# connect bitlines instead of chanel route
# sense_amp_array
# en_layer
# m1
# m3 (sky130)
# precharge_array
# en_bar_layer
# m1
# m3 (sky130)
self.channel_route_bitlines = channel_route_bitlines
self.enable_layer = enable_layer
class _replica_column:
def __init__(self,
even_rows):
# replica_column
# even row check (sky130)
self.even_rows = even_rows
class _wordline_driver:
def __init__(self,
vertical_supply):
# wordline_buffer_array
# vertical vdd/gnd (sky130)
# wordline_driver_array
# vertical vdd/gnd (sky130)
# wordline_driver
# vertical vdd/gnd (sky130)
self.vertical_supply = vertical_supply
class layer_properties():
"""
This contains meta information about the module routing layers. These
can be overriden in the tech.py file.
"""
def __init__(self):
self._bank = _bank(stack="m1_stack",
pitch="m2_pitch")
self._hierarchical_decoder = _hierarchical_decoder(bus_layer="m2",
bus_directions="pref",
input_layer="m1",
output_layer="m3",
vertical_supply=False)
self._hierarchical_predecode = _hierarchical_predecode(bus_layer="m2",
bus_directions="pref",
bus_space_factor=1,
input_layer="m1",
output_layer="m1",
vertical_supply=False)
self._column_mux_array = _column_mux_array(select_layer="m1",
select_pitch="m2_pitch",
bitline_layer="m2")
self._port_address = _port_address(supply_offset=False)
self._port_data = _port_data(channel_route_bitlines=True,
enable_layer="m1")
self._replica_column = _replica_column(even_rows=False)
self._wordline_driver = _wordline_driver(vertical_supply=False)
@property
def bank(self):
return self._bank
@property
def column_mux_array(self):
return self._column_mux_array
@property
def hierarchical_decoder(self):
return self._hierarchical_decoder
@property
def hierarchical_predecode(self):
return self._hierarchical_predecode
@property
def port_address(self):
return self._port_address
@property
def port_data(self):
return self._port_data
@property
def replica_column(self):
return self._replica_column
@property
def wordline_driver(self):
return self._wordline_driver

View File

@ -8,6 +8,7 @@
from hierarchy_design import hierarchy_design
from utils import round_to_grid
import contact
from tech import preferred_directions
from globals import OPTS
import re
@ -22,8 +23,6 @@ class design(hierarchy_design):
def __init__(self, name):
super().__init__(name)
self.setup_drc_constants()
self.setup_layer_constants()
self.setup_multiport_constants()
def check_pins(self):
@ -32,7 +31,98 @@ class design(hierarchy_design):
for pin in pins:
print(pin_name, pin)
def setup_layer_constants(self):
@classmethod
def setup_drc_constants(design):
"""
These are some DRC constants used in many places
in the compiler.
"""
# Make some local rules for convenience
from tech import drc
for rule in drc.keys():
# Single layer width rules
match = re.search(r"minwidth_(.*)", rule)
if match:
if match.group(1) == "active_contact":
setattr(design, "contact_width", drc(match.group(0)))
else:
setattr(design, match.group(1) + "_width", drc(match.group(0)))
# Single layer area rules
match = re.search(r"minarea_(.*)", rule)
if match:
setattr(design, match.group(0), drc(match.group(0)))
# Single layer spacing rules
match = re.search(r"(.*)_to_(.*)", rule)
if match and match.group(1) == match.group(2):
setattr(design, match.group(1) + "_space", drc(match.group(0)))
elif match and match.group(1) != match.group(2):
if match.group(2) == "poly_active":
setattr(design, match.group(1) + "_to_contact",
drc(match.group(0)))
else:
setattr(design, match.group(0), drc(match.group(0)))
match = re.search(r"(.*)_enclose_(.*)", rule)
if match:
setattr(design, match.group(0), drc(match.group(0)))
match = re.search(r"(.*)_extend_(.*)", rule)
if match:
setattr(design, match.group(0), drc(match.group(0)))
# Create the maximum well extend active that gets used
# by cells to extend the wells for interaction with other cells
from tech import layer
design.well_extend_active = 0
if "nwell" in layer:
design.well_extend_active = max(design.well_extend_active, design.nwell_extend_active)
if "pwell" in layer:
design.well_extend_active = max(design.well_extend_active, design.pwell_extend_active)
# The active offset is due to the well extension
if "pwell" in layer:
design.pwell_enclose_active = drc("pwell_enclose_active")
else:
design.pwell_enclose_active = 0
if "nwell" in layer:
design.nwell_enclose_active = drc("nwell_enclose_active")
else:
design.nwell_enclose_active = 0
# Use the max of either so that the poly gates will align properly
design.well_enclose_active = max(design.pwell_enclose_active,
design.nwell_enclose_active,
design.active_space)
# These are for debugging previous manual rules
if False:
print("poly_width", design.poly_width)
print("poly_space", design.poly_space)
print("m1_width", design.m1_width)
print("m1_space", design.m1_space)
print("m2_width", design.m2_width)
print("m2_space", design.m2_space)
print("m3_width", design.m3_width)
print("m3_space", design.m3_space)
print("m4_width", design.m4_width)
print("m4_space", design.m4_space)
print("active_width", design.active_width)
print("active_space", design.active_space)
print("contact_width", design.contact_width)
print("poly_to_active", design.poly_to_active)
print("poly_extend_active", design.poly_extend_active)
print("poly_to_contact", design.poly_to_contact)
print("active_contact_to_gate", design.active_contact_to_gate)
print("poly_contact_to_gate", design.poly_contact_to_gate)
print("well_enclose_active", design.well_enclose_active)
print("implant_enclose_active", design.implant_enclose_active)
print("implant_space", design.implant_space)
import sys
sys.exit(1)
@classmethod
def setup_layer_constants(design):
"""
These are some layer constants used
in many places in the compiler.
@ -46,7 +136,7 @@ class design(hierarchy_design):
# Set the stack as a local helper
try:
layer_stack = getattr(tech, key)
setattr(self, key, layer_stack)
setattr(design, key, layer_stack)
except AttributeError:
pass
@ -55,14 +145,14 @@ class design(hierarchy_design):
continue
# Add the pitch
setattr(self,
setattr(design,
"{}_pitch".format(layer),
self.compute_pitch(layer, True))
design.compute_pitch(layer, True))
# Add the non-preferrd pitch (which has vias in the "wrong" way)
setattr(self,
setattr(design,
"{}_nonpref_pitch".format(layer),
self.compute_pitch(layer, False))
design.compute_pitch(layer, False))
if False:
from tech import preferred_directions
@ -73,17 +163,18 @@ class design(hierarchy_design):
continue
try:
print("{0} width {1} space {2}".format(name,
getattr(self, "{}_width".format(name)),
getattr(self, "{}_space".format(name))))
getattr(design, "{}_width".format(name)),
getattr(design, "{}_space".format(name))))
print("pitch {0} nonpref {1}".format(getattr(self, "{}_pitch".format(name)),
getattr(self, "{}_nonpref_pitch".format(name))))
print("pitch {0} nonpref {1}".format(getattr(design, "{}_pitch".format(name)),
getattr(design, "{}_nonpref_pitch".format(name))))
except AttributeError:
pass
import sys
sys.exit(1)
def compute_pitch(self, layer, preferred=True):
@staticmethod
def compute_pitch(layer, preferred=True):
"""
This is the preferred direction pitch
@ -95,13 +186,18 @@ class design(hierarchy_design):
for stack in layer_stacks:
# Compute the pitch with both vias above and below (if they exist)
if stack[0] == layer:
pitches.append(self.compute_layer_pitch(stack, preferred))
pitches.append(design.compute_layer_pitch(stack, preferred))
if stack[2] == layer:
pitches.append(self.compute_layer_pitch(stack[::-1], True))
pitches.append(design.compute_layer_pitch(stack[::-1], True))
return max(pitches)
def compute_layer_pitch(self, layer_stack, preferred):
@staticmethod
def get_preferred_direction(layer):
return preferred_directions[layer]
@staticmethod
def compute_layer_pitch(layer_stack, preferred):
(layer1, via, layer2) = layer_stack
try:
@ -113,16 +209,16 @@ class design(hierarchy_design):
contact1 = getattr(contact, layer2 + "_via")
if preferred:
if self.get_preferred_direction(layer1) == "V":
if preferred_directions[layer1] == "V":
contact_width = contact1.first_layer_width
else:
contact_width = contact1.first_layer_height
else:
if self.get_preferred_direction(layer1) == "V":
if preferred_directions[layer1] == "V":
contact_width = contact1.first_layer_height
else:
contact_width = contact1.first_layer_width
layer_space = getattr(self, layer1 + "_space")
layer_space = getattr(design, layer1 + "_space")
#print(layer_stack)
#print(contact1)
@ -130,94 +226,6 @@ class design(hierarchy_design):
return round_to_grid(pitch)
def setup_drc_constants(self):
"""
These are some DRC constants used in many places
in the compiler.
"""
# Make some local rules for convenience
from tech import drc
for rule in drc.keys():
# Single layer width rules
match = re.search(r"minwidth_(.*)", rule)
if match:
if match.group(1) == "active_contact":
setattr(self, "contact_width", drc(match.group(0)))
else:
setattr(self, match.group(1) + "_width", drc(match.group(0)))
# Single layer area rules
match = re.search(r"minarea_(.*)", rule)
if match:
setattr(self, match.group(0), drc(match.group(0)))
# Single layer spacing rules
match = re.search(r"(.*)_to_(.*)", rule)
if match and match.group(1) == match.group(2):
setattr(self, match.group(1) + "_space", drc(match.group(0)))
elif match and match.group(1) != match.group(2):
if match.group(2) == "poly_active":
setattr(self, match.group(1) + "_to_contact",
drc(match.group(0)))
else:
setattr(self, match.group(0), drc(match.group(0)))
match = re.search(r"(.*)_enclose_(.*)", rule)
if match:
setattr(self, match.group(0), drc(match.group(0)))
match = re.search(r"(.*)_extend_(.*)", rule)
if match:
setattr(self, match.group(0), drc(match.group(0)))
# Create the maximum well extend active that gets used
# by cells to extend the wells for interaction with other cells
from tech import layer
self.well_extend_active = 0
if "nwell" in layer:
self.well_extend_active = max(self.well_extend_active, self.nwell_extend_active)
if "pwell" in layer:
self.well_extend_active = max(self.well_extend_active, self.pwell_extend_active)
# The active offset is due to the well extension
if "pwell" in layer:
self.pwell_enclose_active = drc("pwell_enclose_active")
else:
self.pwell_enclose_active = 0
if "nwell" in layer:
self.nwell_enclose_active = drc("nwell_enclose_active")
else:
self.nwell_enclose_active = 0
# Use the max of either so that the poly gates will align properly
self.well_enclose_active = max(self.pwell_enclose_active,
self.nwell_enclose_active,
self.active_space)
# These are for debugging previous manual rules
if False:
print("poly_width", self.poly_width)
print("poly_space", self.poly_space)
print("m1_width", self.m1_width)
print("m1_space", self.m1_space)
print("m2_width", self.m2_width)
print("m2_space", self.m2_space)
print("m3_width", self.m3_width)
print("m3_space", self.m3_space)
print("m4_width", self.m4_width)
print("m4_space", self.m4_space)
print("active_width", self.active_width)
print("active_space", self.active_space)
print("contact_width", self.contact_width)
print("poly_to_active", self.poly_to_active)
print("poly_extend_active", self.poly_extend_active)
print("poly_to_contact", self.poly_to_contact)
print("active_contact_to_gate", self.active_contact_to_gate)
print("poly_contact_to_gate", self.poly_contact_to_gate)
print("well_enclose_active", self.well_enclose_active)
print("implant_enclose_active", self.implant_enclose_active)
print("implant_space", self.implant_space)
import sys
sys.exit(1)
def setup_multiport_constants(self):
"""
@ -266,3 +274,6 @@ class design(hierarchy_design):
total_module_power += inst.mod.analytical_power(corner, load)
return total_module_power
design.setup_drc_constants()
design.setup_layer_constants()

View File

@ -13,7 +13,6 @@ from tech import drc, GDS
from tech import layer as techlayer
from tech import layer_indices
from tech import layer_stacks
from tech import preferred_directions
import os
from globals import OPTS
from vector import vector
@ -537,10 +536,6 @@ class layout():
position_list=coordinates,
widen_short_wires=widen_short_wires)
def get_preferred_direction(self, layer):
""" Return the preferred routing directions """
return preferred_directions[layer]
def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """
from sram_factory import factory

View File

@ -10,7 +10,7 @@ import utils
from tech import GDS, layer
from tech import cell_properties as props
import bitcell_base
from globals import OPTS
class bitcell(bitcell_base.bitcell_base):
"""
@ -46,8 +46,6 @@ class bitcell(bitcell_base.bitcell_base):
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets)
#debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells")
def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = [props.bitcell.cell_6t.pin.wl]

View File

@ -2,7 +2,7 @@ word_size = 32
num_words = 128
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -6,7 +6,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -0,0 +1,21 @@
word_size = 4
num_words = 16
write_size = 2
num_rw_ports = 1
num_r_ports = 0
num_w_ports = 1
tech_name = "scn4m_subm"
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = False
check_lvsdrc = True
output_path = "temp"
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)

View File

@ -7,7 +7,7 @@ num_r_ports = 0
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -6,7 +6,7 @@ num_r_ports = 1
num_w_ports = 1
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -0,0 +1,21 @@
word_size = 2
num_words = 16
num_rw_ports = 2
num_r_ports = 0
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = False
check_lvsdrc = True
output_path = "temp"
output_name = "sram_1w_1r_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)

View File

@ -2,14 +2,14 @@ word_size = 2
num_words = 16
tech_name = "freepdk45"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]
route_supplies = False
check_lvsdrc = True
# nominal_corners_only = True
# nominal_corner_only = True
load_scales = [0.5, 1, 4]
slew_scales = [0.5, 1]

View File

@ -2,7 +2,7 @@ word_size = 2
num_words = 16
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -2,7 +2,7 @@ word_size = 64
num_words = 1024
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [ 5.0 ]
temperatures = [ 25 ]

View File

@ -2,7 +2,7 @@ word_size = 16
num_words = 256
tech_name = "scn4m_subm"
nominal_corners_only = False
nominal_corner_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "freepdk45"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = False
check_lvsdrc = False

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = False
check_lvsdrc = False

View File

@ -7,7 +7,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -7,7 +7,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = False
check_lvsdrc = False

View File

@ -7,7 +7,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "scn4m_subm"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = False
check_lvsdrc = False

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -9,7 +9,7 @@ num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
nominal_corners_only = True
nominal_corner_only = True
route_supplies = True
check_lvsdrc = True

View File

@ -1,19 +0,0 @@
word_size = 2
num_words = 16
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
#netlist_only = True
route_supplies = True
check_lvsdrc = True
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -1,19 +0,0 @@
word_size = 8
num_words = 128
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = True
check_lvsdrc = True
netlist_only = True
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -1,18 +0,0 @@
word_size = 16
num_words = 256
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = True
check_lvsdrc = True
netlist_only = True
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -1,18 +0,0 @@
word_size = 32
num_words = 128
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = True
check_lvsdrc = True
netlist_only = True
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -1,19 +0,0 @@
word_size = 64
num_words = 128
tech_name = "scn4m_subm"
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
route_supplies = True
check_lvsdrc = True
output_path = "/home/jesse/thesis/outputs/run5"
output_name = "sram_{0}_{1}_{2}".format(word_size,
num_words,
tech_name)
drc_name = "magic"
lvs_name = "netgen"
pex_name = "magic"

View File

@ -1,31 +0,0 @@
word_size = 16
num_words = 16
num_rw_ports = 1
num_r_ports = 1
num_w_ports = 0
tech_name = "sky130"
accuracy_requirement = 0.05
magic_exe = ("magic", "magic")
nominal_corners_only = False
process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
netlist_only = False
route_supplies = "grid"
check_lvsdrc = False
#replica_bitcell_array = "/home/jesse/openram/technology/sky130/modules/replica_bitcell_array.py"
output_path = "sram_" + str(accuracy_requirement)
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,
num_words,
tech_name,
accuracy_requirement
)
write_size=8

View File

@ -9,9 +9,10 @@ import debug
import design
from sram_factory import factory
from math import log, ceil, floor
from tech import drc, layer
from tech import drc
from vector import vector
from globals import OPTS
from tech import layer_properties as layer_props
class bank(design.design):
@ -906,18 +907,13 @@ class bank(design.design):
offset=mid2)
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
def route_column_address_lines(self, port):
""" Connecting the select lines of column mux to the address bus """
if not self.col_addr_size>0:
return
if OPTS.tech_name == "sky130":
stack = self.m2_stack
pitch = self.m3_pitch
else:
stack = self.m1_stack
pitch = self.m2_pitch
stack = getattr(self, layer_props.bank.stack)
pitch = getattr(self, layer_props.bank.pitch)
if self.col_addr_size == 1:

View File

@ -11,7 +11,8 @@ from tech import layer, preferred_directions
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import cell_properties
from tech import cell_properties as cell_props
from tech import layer_properties as layer_props
class column_mux_array(design.design):
@ -33,14 +34,18 @@ class column_mux_array(design.design):
self.bitcell_br = bitcell_br
self.column_offset = column_offset
if OPTS.tech_name == "sky130":
self.sel_layer = "m3"
self.sel_pitch = self.m3_pitch
self.bitline_layer = "m1"
else:
self.sel_layer = "m1"
self.sel_pitch = self.m2_pitch
self.bitline_layer = "m2"
self.sel_layer = layer_props.column_mux_array.select_layer
self.sel_pitch = getattr(self, layer_props.column_mux_array.select_pitch)
self.bitline_layer = layer_props.column_mux_array.bitline_layer
# if OPTS.tech_name == "sky130":
# self.sel_layer = "m3"
# self.sel_pitch = self.m3_pitch
# self.bitline_layer = "m1"
# else:
# self.sel_layer = "m1"
# self.sel_pitch = self.m2_pitch
# self.bitline_layer = "m2"
if preferred_directions[self.sel_layer] == "V":
self.via_directions = ("H", "H")
@ -123,7 +128,7 @@ class column_mux_array(design.design):
# For every column, add a pass gate
for col_num, xoffset in enumerate(self.offsets[0:self.columns]):
if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2:
if cell_props.bitcell.mirror.y and (col_num + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.mux.width
else:

View File

@ -85,8 +85,8 @@ class control_logic(design.design):
def add_modules(self):
""" Add all the required modules """
dff = factory.create(module_type="dff_buf")
dff_height = dff.height
self.dff = factory.create(module_type="dff_buf")
dff_height = self.dff.height
self.ctrl_dff_array = factory.create(module_type="dff_buf_array",
rows=self.num_control_signals,
@ -119,7 +119,7 @@ class control_logic(design.design):
# We will use the maximum since this same value is used to size the wl_en
# and the p_en_bar drivers
max_fanout = max(self.num_rows, self.num_cols)
# max_fanout = max(self.num_rows, self.num_cols)
# wl_en drives every row in the bank
self.wl_en_driver = factory.create(module_type="pdriver",
@ -721,10 +721,8 @@ class control_logic(design.design):
def route_supply(self):
""" Add vdd and gnd to the instance cells """
if OPTS.tech_name == "sky130":
supply_layer = "li"
else:
supply_layer = "m1"
supply_layer = self.dff.get_pin("vdd").layer
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
for inst in self.row_end_inst:
pins = inst.get_pins("vdd")

View File

@ -11,6 +11,7 @@ import math
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import layer_properties as layer_props
class hierarchical_decoder(design.design):
@ -181,24 +182,14 @@ class hierarchical_decoder(design.design):
# Inputs to cells are on input layer
# Outputs from cells are on output layer
if OPTS.tech_name == "sky130":
self.bus_layer = "m1"
self.bus_directions = "nonpref"
self.bus_pitch = self.m1_pitch
self.bus_space = self.m2_space
self.input_layer = "m2"
self.output_layer = "li"
self.output_layer_pitch = self.li_pitch
else:
self.bus_layer = "m2"
self.bus_directions = "pref"
self.bus_pitch = self.m2_pitch
self.bus_space = self.m2_space
# These two layers being the same requires a special jog
# to ensure to conflicts with the output layers
self.input_layer = "m1"
self.output_layer = "m3"
self.output_layer_pitch = self.m3_pitch
self.bus_layer = layer_props.hierarchical_decoder.bus_layer
self.bus_directions = layer_props.hierarchical_decoder.bus_directions
self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
self.bus_space = getattr(self, self.bus_layer + "_space")
self.input_layer = layer_props.hierarchical_decoder.input_layer
self.output_layer = layer_props.hierarchical_decoder.output_layer
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
# Two extra pitches between modules on left and right
self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + self.bus_pitch
@ -606,7 +597,7 @@ class hierarchical_decoder(design.design):
must-connects next level up.
"""
if OPTS.tech_name == "sky130":
if layer_props.hierarchical_decoder.vertical_supply:
for n in ["vdd", "gnd"]:
pins = self.and_inst[0].get_pins(n)
for pin in pins:
@ -678,7 +669,7 @@ class hierarchical_decoder(design.design):
mid_point2 = vector(x_offset, y_offset)
rail_pos = vector(self.predecode_bus[rail_name].cx(), mid_point2.y)
self.add_path(self.output_layer, [pin_pos, mid_point1, mid_point2, rail_pos])
if OPTS.tech_name == "sky130":
if layer_props.hierarchical_decoder.vertical_supply:
above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height / 2))
self.add_path(self.bus_layer, [rail_pos, above_rail], width=self.li_width + self.m1_enclose_mcon * 2)

View File

@ -11,6 +11,7 @@ import math
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import layer_properties as layer_props
class hierarchical_predecode(design.design):
@ -83,23 +84,14 @@ class hierarchical_predecode(design.design):
# Inputs to cells are on input layer
# Outputs from cells are on output layer
if OPTS.tech_name == "sky130":
self.bus_layer = "m1"
self.bus_directions = "nonpref"
self.bus_pitch = self.m1_pitch
self.bus_space = 1.5 * self.m1_space
self.input_layer = "m2"
self.output_layer = "li"
self.output_layer_pitch = self.li_pitch
else:
self.bus_layer = "m2"
self.bus_directions = "pref"
self.bus_pitch = self.m2_pitch
self.bus_space = self.m2_space
# This requires a special jog to ensure to conflicts with the output layers
self.input_layer = "m1"
self.output_layer = "m1"
self.output_layer_pitch = self.m1_pitch
self.bus_layer = layer_props.hierarchical_predecode.bus_layer
self.bus_directions = layer_props.hierarchical_predecode.bus_directions
self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
self.bus_space = layer_props.hierarchical_predecode.bus_space_factor * getattr(self, self.bus_layer + "_space")
self.input_layer = layer_props.hierarchical_predecode.input_layer
self.output_layer = layer_props.hierarchical_predecode.output_layer
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
self.height = self.number_of_outputs * self.and_mod.height
@ -276,7 +268,7 @@ class hierarchical_predecode(design.design):
height=via.mod.second_layer_height,
width=via.mod.second_layer_width)
if OPTS.tech_name == "sky130":
if layer_props.hierarchical_predecode.vertical_supply:
below_rail = vector(self.decode_rails[out_pin].cx(), y_offset - (self.cell_height / 2))
self.add_path(self.bus_layer, [rail_pos, below_rail], width=self.li_width + self.m1_enclose_mcon * 2)
@ -319,8 +311,8 @@ class hierarchical_predecode(design.design):
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
# In sky130, we use hand-made decoder cells with vertical power
if OPTS.tech_name == "sky130" and not self.column_decoder:
# We may ahve vertical power supply rails
if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder:
for n in ["vdd", "gnd"]:
# This makes a wire from top to bottom for both inv and and gates
for i in [self.inv_inst, self.and_inst]:

View File

@ -10,6 +10,7 @@ from sram_factory import factory
from vector import vector
from tech import layer
from globals import OPTS
from tech import layer_properties as layer_props
class port_address(design.design):
@ -80,7 +81,7 @@ class port_address(design.design):
self.copy_power_pins(inst, "gnd")
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"):
if OPTS.tech_name == "sky130":
if layer_props.port_address.supply_offset:
self.add_power_pin("vdd", rbl_vdd_pin.center())
else:
self.add_power_pin("vdd", rbl_vdd_pin.lc())

View File

@ -11,6 +11,7 @@ from sram_factory import factory
from collections import namedtuple
from vector import vector
from globals import OPTS
from tech import layer_properties as layer_props
class port_data(design.design):
@ -580,20 +581,20 @@ class port_data(design.design):
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
# This could be a channel route, but in some techs the bitlines
# are too close together.
elif OPTS.tech_name == "sky130":
self.connect_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
else:
elif layer_props.port_data.channel_route_bitlines:
self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size + self.num_spare_cols,
inst1_start_bit=start_bit)
# This could be a channel route, but in some techs the bitlines
# are too close together.
else:
self.connect_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
def route_write_driver_to_column_mux_or_precharge_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or precharge array """
@ -640,17 +641,16 @@ class port_data(design.design):
# This could be a channel route, but in some techs the bitlines
# are too close together.
elif OPTS.tech_name == "sky130":
self.connect_bitlines(inst1=inst1, inst2=inst2,
num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
else:
elif layer_props.port_data.channel_route_bitlines:
self.channel_route_bitlines(inst1=inst1, inst2=inst2,
num_bits=self.word_size + self.num_spare_cols,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
else:
self.connect_bitlines(inst1=inst1, inst2=inst2,
num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
def route_write_driver_to_sense_amp(self, port):
""" Routing of BL and BR between write driver and sense amp """

View File

@ -9,6 +9,7 @@ from tech import cell_properties
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import layer_properties as layer_props
class replica_column(bitcell_base_array):
@ -41,7 +42,7 @@ class replica_column(bitcell_base_array):
"Replica bit cannot be the dummy row.")
debug.check(replica_bit <= self.left_rbl or replica_bit >= self.total_size - self.right_rbl - 1,
"Replica bit cannot be in the regular array.")
if OPTS.tech_name == "sky130":
if layer_props.replica_column.even_rows:
debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
"sky130 currently requires rows to be even and to start with X mirroring"
+ " (left_rbl must be odd) for LVS.")

View File

@ -7,10 +7,11 @@
#
import debug
import design
from tech import drc, layer
from tech import layer
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import layer_properties as layer_props
class wordline_buffer_array(design.design):
@ -70,7 +71,7 @@ class wordline_buffer_array(design.design):
Add a pin for each row of vdd/gnd which
are must-connects next level up.
"""
if OPTS.tech_name == "sky130":
if layer_props.wordline_driver.vertical_supply:
for name in ["vdd", "gnd"]:
supply_pins = self.wld_inst[0].get_pins(name)
for pin in supply_pins:

View File

@ -11,6 +11,7 @@ from tech import drc, layer
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import layer_properties as layer_props
class wordline_driver_array(design.design):
@ -71,7 +72,7 @@ class wordline_driver_array(design.design):
Add a pin for each row of vdd/gnd which
are must-connects next level up.
"""
if OPTS.tech_name == "sky130":
if layer_props.wordline_driver.vertical_supply:
for name in ["vdd", "gnd"]:
supply_pins = self.wld_inst[0].get_pins(name)
for pin in supply_pins:

View File

@ -10,7 +10,7 @@ import debug
from tech import drc, layer
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import cell_properties as cell_props
class column_mux(pgate.pgate):
@ -124,8 +124,8 @@ class column_mux(pgate.pgate):
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
self.nmos_upper.place(nmos_upper_position)
if OPTS.tech_name == "sky130":
self.add_implants()
if cell_props.pgate.add_implants:
self.extend_implants()
def connect_poly(self):
""" Connect the poly gate of the two pass transistors """
@ -198,7 +198,7 @@ class column_mux(pgate.pgate):
self.add_path(self.col_mux_stack[2],
[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()])
def add_implants(self):
def extend_implants(self):
"""
Add top-to-bottom implants for adjacency issues in s8.
"""

View File

@ -13,8 +13,8 @@ from bisect import bisect_left
from tech import layer, drc
from vector import vector
from globals import OPTS
if(OPTS.tech_name == "sky130"):
from tech import cell_properties as cell_props
if cell_props.ptx.bin_spice_models:
from tech import nmos_bins, pmos_bins
@ -192,7 +192,7 @@ class pgate(design.design):
width=self.width + 2 * self.well_extend_active,
height=pwell_height)
if OPTS.tech_name == "sky130":
if cell_props.pgate.add_implants:
self.extend_implants()
def add_nwell_contact(self, pmos, pmos_pos):

View File

@ -17,6 +17,7 @@ from utils import round_to_grid
import logical_effort
from sram_factory import factory
from errors import drc_error
from tech import cell_properties as cell_props
class pinv(pgate.pgate):
@ -87,7 +88,7 @@ class pinv(pgate.pgate):
self.tx_mults = 1
self.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx")
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
(self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width)
return
@ -132,7 +133,7 @@ class pinv(pgate.pgate):
# Determine the number of mults for each to fit width
# into available space
if OPTS.tech_name != "sky130":
if not cell_props.ptx.bin_spice_models:
self.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx")
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)

View File

@ -12,6 +12,7 @@ from tech import drc, parameter, layer
from vector import vector
from globals import OPTS
from sram_factory import factory
from tech import cell_properties as cell_props
class pinv_dec(pinv.pinv):
@ -50,7 +51,7 @@ class pinv_dec(pinv.pinv):
self.tx_mults = 1
self.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx")
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
@ -140,10 +141,10 @@ class pinv_dec(pinv.pinv):
nmos_drain_pos = self.nmos_inst.get_pin("D").center()
self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y)
if OPTS.tech_name == "sky130":
self.add_implants()
if cell_props.pgate.add_implants:
self.extend_implants()
def add_implants(self):
def extend_implants(self):
"""
Add top-to-bottom implants for adjacency issues in s8.
"""

View File

@ -8,11 +8,11 @@
import pgate
import debug
from tech import drc, parameter, spice
from globals import OPTS
from vector import vector
import logical_effort
from sram_factory import factory
import contact
from tech import cell_properties as cell_props
class pnand2(pgate.pgate):
@ -38,7 +38,7 @@ class pnand2(pgate.pgate):
debug.check(size == 1, "Size 1 pnand2 is only supported now.")
self.tx_mults = 1
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
@ -212,10 +212,9 @@ class pnand2(pgate.pgate):
"B",
position="center")
if OPTS.tech_name == "sky130":
if cell_props.pgate.add_implants:
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
def route_output(self):
""" Route the Z output """

View File

@ -11,8 +11,8 @@ from tech import drc, parameter, spice
from vector import vector
import logical_effort
from sram_factory import factory
from globals import OPTS
import contact
from tech import cell_properties as cell_props
class pnand3(pgate.pgate):
@ -41,7 +41,7 @@ class pnand3(pgate.pgate):
"Size 1 pnand3 is only supported now.")
self.tx_mults = 1
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
@ -246,7 +246,7 @@ class pnand3(pgate.pgate):
"C",
position="right")
if OPTS.tech_name == "sky130":
if cell_props.pgate.add_implants:
self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly"))
def route_output(self):

View File

@ -11,8 +11,8 @@ from tech import drc, parameter, spice
from vector import vector
import logical_effort
from sram_factory import factory
from globals import OPTS
import contact
from tech import cell_properties as cell_props
class pnand4(pgate.pgate):
@ -41,7 +41,7 @@ class pnand4(pgate.pgate):
"Size 1 pnand4 is only supported now.")
self.tx_mults = 1
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
@ -268,7 +268,7 @@ class pnand4(pgate.pgate):
"D",
position="right")
if OPTS.tech_name == "sky130":
if cell_props.pgate.add_implants:
self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly"))
def route_output(self):

View File

@ -5,13 +5,12 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import contact
import pgate
import debug
from globals import OPTS
from tech import drc, parameter, spice
from vector import vector
from sram_factory import factory
from tech import cell_properties as cell_props
class pnor2(pgate.pgate):
@ -37,7 +36,7 @@ class pnor2(pgate.pgate):
debug.check(size==1, "Size 1 pnor2 is only supported now.")
self.tx_mults = 1
if OPTS.tech_name == "sky130":
if cell_props.ptx.bin_spice_models:
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
@ -211,7 +210,7 @@ class pnor2(pgate.pgate):
self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch
if OPTS.tech_name == "sky130":
if cell_props.pgate.add_implants:
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
def route_output(self):

View File

@ -13,6 +13,7 @@ from tech import parameter, drc
from vector import vector
from globals import OPTS
from sram_factory import factory
from tech import cell_properties as cell_props
class precharge(design.design):
@ -79,7 +80,7 @@ class precharge(design.design):
"""
Initializes the upper and lower pmos
"""
if(OPTS.tech_name == "sky130"):
if cell_props.ptx.bin_spice_models:
self.ptx_width = pgate.nearest_bin("pmos", self.ptx_width)
self.pmos = factory.create(module_type="ptx",
width=self.ptx_width,

View File

@ -14,6 +14,7 @@ import contact
import logical_effort
from globals import OPTS
from pgate import pgate
from tech import cell_properties as cell_props
class ptx(design.design):
@ -129,9 +130,8 @@ class ptx(design.design):
# be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
if OPTS.tech_name == "sky130":
# sky130 simulation cannot use the mult parameter in simulation
(self.tx_width, self.mults) = pgate.best_bin(self.tx_type, self.tx_width)
if cell_props.ptx.model_is_subckt:
# sky130
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
self.tx_width,
@ -150,12 +150,13 @@ class ptx(design.design):
self.spice_device = main_str + area_str
self.spice.append("\n* spice ptx " + self.spice_device)
if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
if cell_props.ptx.model_is_subckt and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
# sky130 requires mult parameter too
# self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
# self.mults,
# self.tx_width,
# drc("minwidth_poly"))
# TEMP FIX: Use old device names if using Calibre.
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort",
self.mults,
self.tx_width,

View File

@ -11,6 +11,7 @@ import design
from sram_factory import factory
from globals import OPTS
from tech import layer
from tech import layer_properties as layer_props
class wordline_driver(design.design):
@ -104,7 +105,7 @@ class wordline_driver(design.design):
def route_supply_rails(self):
""" Add vdd/gnd rails to the top, (middle), and bottom. """
if OPTS.tech_name == "sky130":
if layer_props.wordline_driver.vertical_supply:
for name in ["vdd", "gnd"]:
for inst in [self.nand_inst, self.driver_inst]:
self.copy_layout_pin(inst, name)

View File

@ -552,7 +552,7 @@ class pin_group:
Add the enclosure shape to the given cell.
"""
for enclosure in self.enclosures:
debug.info(2, "Adding enclosure {0} {1}".format(self.name,
debug.info(4, "Adding enclosure {0} {1}".format(self.name,
enclosure))
cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(),
@ -612,7 +612,7 @@ class pin_group:
blockage_set = set()
for pin in self.pins:
debug.info(2, " Converting {0}".format(pin))
debug.info(4, " Converting {0}".format(pin))
# Determine which tracks the pin overlaps
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin)
@ -628,15 +628,15 @@ class pin_group:
# Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids
if len(shared_set) > 0:
debug.info(2, "Removing pins {}".format(shared_set))
debug.info(4, "Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids
if len(shared_set) > 0:
debug.info(2, "Removing pins {}".format(shared_set))
debug.info(4, "Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids
if len(shared_set) > 0:
debug.info(2, "Removing blocks {}".format(shared_set))
debug.info(4, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks
@ -666,5 +666,5 @@ class pin_group:
# Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set
debug.info(2, " pins {}".format(self.grids))
debug.info(2, " secondary {}".format(self.secondary_grids))
debug.info(4, " pins {}".format(self.grids))
debug.info(4, " secondary {}".format(self.secondary_grids))

View File

@ -301,7 +301,6 @@ class router(router_tech):
adj_grids))
self.remove_adjacent_grid(pg1, pg2, adj_grids)
debug.info(1, "Removed {} adjacent grids.".format(removed_grids))
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
@ -539,7 +538,7 @@ class router(router_tech):
sufficient_list.update([full_overlap])
if partial_overlap:
insufficient_list.update([partial_overlap])
debug.info(2,
debug.info(3,
"Converting [ {0} , {1} ] full={2}".format(x,
y,
full_overlap))
@ -632,26 +631,26 @@ class router(router_tech):
pin.layer)
overlap_length = pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord,
pin.rect,
track_pin,
overlap_length))
inflated_overlap_length = inflated_pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord,
inflated_pin.rect,
track_pin,
inflated_overlap_length))
# If it overlaps with the pin, it is sufficient
if overlap_length == math.inf or overlap_length > 0:
debug.info(2," Overlap: {0} >? {1}".format(overlap_length, 0))
debug.info(4," Overlap: {0} >? {1}".format(overlap_length, 0))
return (coord, None)
# If it overlaps with the inflated pin, it is partial
elif inflated_overlap_length == math.inf or inflated_overlap_length > 0:
debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0))
debug.info(4," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0))
return (None, coord)
else:
debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0))
debug.info(4, " No overlap: {0} {1}".format(overlap_length, 0))
return (None, None)
def convert_track_to_pin(self, track):
@ -846,7 +845,7 @@ class router(router_tech):
"Pin component index too large.")
pin_in_tracks = self.pin_groups[pin_name][index].grids
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
debug.info(3,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_source(pin_in_tracks)
def add_path_target(self, paths):
@ -914,7 +913,7 @@ class router(router_tech):
"""
path = self.prepare_path(path)
debug.info(2, "Adding route: {}".format(str(path)))
debug.info(4, "Adding route: {}".format(str(path)))
# If it is only a square, add an enclosure to the track
if len(path) == 1:
self.add_single_enclosure(path[0][0])
@ -1007,8 +1006,7 @@ class router(router_tech):
# returns the path in tracks
(path, cost) = self.rg.route(detour_scale)
if path:
debug.info(1, "Found path: cost={0} ".format(cost))
debug.info(1, str(path))
debug.info(2, "Found path: cost={0} {1}".format(cost, str(path)))
self.paths.append(path)
self.add_route(path)

View File

@ -2,7 +2,7 @@
04_pbitcell_test.py
04_precharge_pbitcell_test.py
04_replica_pbitcell_test.py
04_single_level_column_mux_pbitcell_test.py
04_column_mux_pbitcell_test.py
05_bitcell_1rw_1r_array_test.py
05_bitcell_array_test.py
05_dummy_array_test.py
@ -14,7 +14,7 @@
06_hierarchical_predecode3x8_pbitcell_test.py
06_hierarchical_predecode3x8_test.py
06_hierarchical_predecode4x16_test.py
07_single_level_column_mux_array_pbitcell_test.py
07_column_mux_array_pbitcell_test.py
08_wordline_driver_array_pbitcell_test.py
08_wordline_driver_array_test.py
09_sense_amp_array_test_pbitcell.py

View File

@ -9,6 +9,7 @@ import os
from design_rules import *
from module_type import *
from custom_cell_properties import cell_properties
from custom_layer_properties import layer_properties
"""
File containing the process technology parameters for FreePDK 45nm.
@ -34,6 +35,11 @@ cell_properties.bitcell.mirror.x = True
cell_properties.bitcell.mirror.y = False
cell_properties.bitcell_power_pin_directions = ("V", "V")
###################################################
# Custom cell properties
###################################################
layer_properties = layer_properties()
###################################################
# GDS file info
###################################################

View File

@ -9,6 +9,7 @@ import os
from design_rules import *
from module_type import *
from custom_cell_properties import cell_properties
from custom_layer_properties import layer_properties
"""
File containing the process technology parameters for SCMOS 4m, 0.35um
@ -32,6 +33,11 @@ cell_properties = cell_properties()
cell_properties.bitcell.mirror.x = True
cell_properties.bitcell.mirror.y = False
###################################################
# Custom cell properties
###################################################
layer_properties = layer_properties()
###################################################
# GDS file info
###################################################