mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into s8_single_port
This commit is contained in:
commit
d69ca2b1ed
|
|
@ -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
|
||||
|
|
@ -120,34 +140,47 @@ class cell_properties():
|
|||
|
||||
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._ptx = _ptx(model_is_subckt=False,
|
||||
bin_spice_models=False)
|
||||
|
||||
self._dff_buff = _dff_buff(use_custom_ports = False,
|
||||
custom_buff_ports = ["D", "qint", "clk", "vdd", "gnd"],
|
||||
add_body_contacts = False)
|
||||
self._pgate = _pgate(add_implants=False)
|
||||
|
||||
self._dff_buff_array = _dff_buff_array(use_custom_ports = False,
|
||||
add_body_contacts = 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
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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 ]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
|
@ -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,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,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,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,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,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 """
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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