mirror of https://github.com/VLSIDA/OpenRAM.git
Merge remote-tracking branch 'private/dev' into dev
This commit is contained in:
commit
da9ed5494c
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@
|
|||
#
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class _pins:
|
||||
def __init__(self, pin_dict):
|
||||
# make the pins elements of the class to allow "." access.
|
||||
# For example: props.bitcell.cell_6t.pin.bl = "foobar"
|
||||
for k,v in pin_dict.items():
|
||||
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
|
||||
|
|
@ -42,27 +58,27 @@ class _bitcell:
|
|||
def _default():
|
||||
axis = _mirror_axis(True, False)
|
||||
|
||||
cell_s8_6t = _cell({'bl' : 'bl',
|
||||
'br' : 'br',
|
||||
cell_s8_6t = _cell({'bl': 'bl',
|
||||
'br': 'br',
|
||||
'wl': 'wl'})
|
||||
|
||||
cell_6t = _cell({'bl' : 'bl',
|
||||
'br' : 'br',
|
||||
'wl' : 'wl'})
|
||||
cell_6t = _cell({'bl': 'bl',
|
||||
'br': 'br',
|
||||
'wl': 'wl'})
|
||||
|
||||
cell_1rw1r = _cell({'bl0' : 'bl0',
|
||||
'br0' : 'br0',
|
||||
'bl1' : 'bl1',
|
||||
'br1' : 'br1',
|
||||
'wl0' : 'wl0',
|
||||
'wl1' : 'wl1'})
|
||||
cell_1rw1r = _cell({'bl0': 'bl0',
|
||||
'br0': 'br0',
|
||||
'bl1': 'bl1',
|
||||
'br1': 'br1',
|
||||
'wl0': 'wl0',
|
||||
'wl1': 'wl1'})
|
||||
|
||||
cell_1w1r = _cell({'bl0' : 'bl0',
|
||||
'br0' : 'br0',
|
||||
'bl1' : 'bl1',
|
||||
'br1' : 'br1',
|
||||
'wl0' : 'wl0',
|
||||
'wl1' : 'wl1'})
|
||||
cell_1w1r = _cell({'bl0': 'bl0',
|
||||
'br0': 'br0',
|
||||
'bl1': 'bl1',
|
||||
'br1': 'br1',
|
||||
'wl0': 'wl0',
|
||||
'wl1': 'wl1'})
|
||||
|
||||
return _bitcell(cell_s8_6t=cell_s8_6t,
|
||||
cell_6t=cell_6t,
|
||||
|
|
@ -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
|
||||
|
|
@ -119,35 +139,48 @@ class cell_properties():
|
|||
self.names = {}
|
||||
|
||||
self._bitcell = _bitcell._default()
|
||||
|
||||
self._dff = _dff(use_custom_ports = False,
|
||||
custom_port_list = ["D", "Q", "clk", "vdd", "gnd"],
|
||||
custom_type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
|
||||
clk_pin= "clk")
|
||||
|
||||
self._dff_buff = _dff_buff(use_custom_ports = False,
|
||||
custom_buff_ports = ["D", "qint", "clk", "vdd", "gnd"],
|
||||
add_body_contacts = False)
|
||||
|
||||
self._dff_buff_array = _dff_buff_array(use_custom_ports = False,
|
||||
add_body_contacts = False)
|
||||
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"],
|
||||
clk_pin="clk")
|
||||
|
||||
self._dff_buff = _dff_buff(use_custom_ports=False,
|
||||
custom_buff_ports=["D", "qint", "clk", "vdd", "gnd"],
|
||||
add_body_contacts=False)
|
||||
|
||||
self._dff_buff_array = _dff_buff_array(use_custom_ports=False,
|
||||
add_body_contacts=False)
|
||||
|
||||
self._write_driver = _cell({'din': 'din',
|
||||
'bl' : 'bl',
|
||||
'br' : 'br',
|
||||
'en' : 'en'})
|
||||
'bl': 'bl',
|
||||
'br': 'br',
|
||||
'en': 'en'})
|
||||
|
||||
self._sense_amp = _cell({'bl' : 'bl',
|
||||
'br' : 'br',
|
||||
'dout' : 'dout',
|
||||
'en' : 'en'})
|
||||
self._sense_amp = _cell({'bl': 'bl',
|
||||
'br': 'br',
|
||||
'dout': 'dout',
|
||||
'en': 'en'})
|
||||
|
||||
self._bitcell_array = _bitcell_array(use_custom_cell_arrangement = [])
|
||||
self._bitcell_array = _bitcell_array(use_custom_cell_arrangement=[])
|
||||
|
||||
@property
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -18,21 +19,110 @@ class design(hierarchy_design):
|
|||
some DRC/layer constants and analytical models for other modules to reuse.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__(name)
|
||||
|
||||
self.setup_drc_constants()
|
||||
self.setup_layer_constants()
|
||||
self.setup_multiport_constants()
|
||||
|
||||
self.setup_multiport_constants()
|
||||
|
||||
def check_pins(self):
|
||||
for pin_name in self.pins:
|
||||
pins = self.get_pins(pin_name)
|
||||
for pin in pins:
|
||||
print(pin_name, pin)
|
||||
|
||||
@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)
|
||||
|
||||
def setup_layer_constants(self):
|
||||
# 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,112 +209,24 @@ 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)
|
||||
pitch = contact_width + layer_space
|
||||
|
||||
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):
|
||||
"""
|
||||
These are contants and lists that aid multiport design.
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
@ -162,7 +162,7 @@ class control_logic(design.design):
|
|||
self.delay_chain=factory.create(module_type="delay_chain",
|
||||
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
||||
self.add_mod(self.delay_chain)
|
||||
|
||||
|
||||
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
|
||||
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||
from math import ceil
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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,25 +182,15 @@ 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
|
||||
self.row_decoder_height = self.and2.height * self.num_outputs
|
||||
|
|
@ -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,9 +669,9 @@ 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":
|
||||
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)
|
||||
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)
|
||||
|
||||
# pin_pos = pin.center()
|
||||
# rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y)
|
||||
|
|
|
|||
|
|
@ -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,24 +84,15 @@ 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
|
||||
|
||||
# x offset for input inverters
|
||||
|
|
@ -276,9 +268,9 @@ class hierarchical_predecode(design.design):
|
|||
height=via.mod.second_layer_height,
|
||||
width=via.mod.second_layer_width)
|
||||
|
||||
if OPTS.tech_name == "sky130":
|
||||
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)
|
||||
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)
|
||||
|
||||
def route_and_to_rails(self):
|
||||
# This 2D array defines the connection mapping
|
||||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
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)
|
||||
else:
|
||||
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)
|
||||
|
||||
|
||||
def route_write_driver_to_sense_amp(self, port):
|
||||
""" Routing of BL and BR between write driver and sense amp """
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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,9 +212,8 @@ 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 """
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -300,4 +301,4 @@ class precharge(design.design):
|
|||
self.add_path(self.bitline_layer,
|
||||
[left_pos, right_pos],
|
||||
width=pmos_pin.height())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
###################################################
|
||||
|
|
|
|||
|
|
@ -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
|
||||
###################################################
|
||||
|
|
|
|||
Loading…
Reference in New Issue