Merged with dev

This commit is contained in:
Hunter Nichols 2020-11-10 15:47:56 -08:00
commit 84ba5c55d1
375 changed files with 20170 additions and 15576 deletions

View File

@ -34,7 +34,7 @@ class contact(hierarchy_design.hierarchy_design):
# This will ignore the name parameter since # This will ignore the name parameter since
# we can guarantee a unique name here # we can guarantee a unique name here
super().__init__(name) super().__init__(name, name)
debug.info(4, "create contact object {0}".format(name)) debug.info(4, "create contact object {0}".format(name))
self.add_comment("layers: {0}".format(layer_stack)) self.add_comment("layers: {0}".format(layer_stack))
@ -51,8 +51,8 @@ class contact(hierarchy_design.hierarchy_design):
# Non-preferred directions # Non-preferred directions
if directions == "nonpref": if directions == "nonpref":
first_dir = "H" if self.get_preferred_direction(layer_stack[0])=="V" else "V" first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V"
second_dir = "H" if self.get_preferred_direction(layer_stack[2])=="V" else "V" second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V"
self.directions = (first_dir, second_dir) self.directions = (first_dir, second_dir)
# Preferred directions # Preferred directions
elif directions == "pref": elif directions == "pref":

View File

@ -7,13 +7,15 @@
# #
from globals import OPTS from globals import OPTS
class _pins: class _pins:
def __init__(self, pin_dict): def __init__(self, pin_dict):
# make the pins elements of the class to allow "." access. # make the pins elements of the class to allow "." access.
# For example: props.bitcell.cell_6t.pin.bl = "foobar" # 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 self.__dict__[k] = v
class _cell: class _cell:
def __init__(self, pin_dict): def __init__(self, pin_dict):
pin_dict.update(self._default_power_pins()) pin_dict.update(self._default_power_pins())
@ -24,13 +26,27 @@ class _cell:
return self._pins return self._pins
def _default_power_pins(self): def _default_power_pins(self):
return { 'vdd' : 'vdd', 'gnd' : 'gnd' } return {'vdd': 'vdd',
'gnd': 'gnd'}
class _mirror_axis: class _mirror_axis:
def __init__(self, x, y): def __init__(self, x, y):
self.x = x self.x = x
self.y = y 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: class _bitcell:
def __init__(self, mirror, cell_s8_6t, cell_6t, cell_1rw1r, cell_1w1r): def __init__(self, mirror, cell_s8_6t, cell_6t, cell_1rw1r, cell_1w1r):
self.mirror = mirror self.mirror = mirror
@ -42,27 +58,27 @@ class _bitcell:
def _default(): def _default():
axis = _mirror_axis(True, False) axis = _mirror_axis(True, False)
cell_s8_6t = _cell({'bl' : 'bl', cell_s8_6t = _cell({'bl': 'bl',
'br' : 'br', 'br': 'br',
'wl': 'wl'}) 'wl': 'wl'})
cell_6t = _cell({'bl' : 'bl', cell_6t = _cell({'bl': 'bl',
'br' : 'br', 'br': 'br',
'wl' : 'wl'}) 'wl': 'wl'})
cell_1rw1r = _cell({'bl0' : 'bl0', cell_1rw1r = _cell({'bl0': 'bl0',
'br0' : 'br0', 'br0': 'br0',
'bl1' : 'bl1', 'bl1': 'bl1',
'br1' : 'br1', 'br1': 'br1',
'wl0' : 'wl0', 'wl0': 'wl0',
'wl1' : 'wl1'}) 'wl1': 'wl1'})
cell_1w1r = _cell({'bl0' : 'bl0', cell_1w1r = _cell({'bl0': 'bl0',
'br0' : 'br0', 'br0': 'br0',
'bl1' : 'bl1', 'bl1': 'bl1',
'br1' : 'br1', 'br1': 'br1',
'wl0' : 'wl0', 'wl0': 'wl0',
'wl1' : 'wl1'}) 'wl1': 'wl1'})
return _bitcell(cell_s8_6t=cell_s8_6t, return _bitcell(cell_s8_6t=cell_s8_6t,
cell_6t=cell_6t, cell_6t=cell_6t,
@ -94,21 +110,25 @@ class _dff:
self.custom_type_list = custom_type_list self.custom_type_list = custom_type_list
self.clk_pin = clk_pin self.clk_pin = clk_pin
class _dff_buff: class _dff_buff:
def __init__(self, use_custom_ports, custom_buff_ports, add_body_contacts): def __init__(self, use_custom_ports, custom_buff_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports self.use_custom_ports = use_custom_ports
self.buf_ports = custom_buff_ports self.buf_ports = custom_buff_ports
self.add_body_contacts = add_body_contacts self.add_body_contacts = add_body_contacts
class _dff_buff_array: class _dff_buff_array:
def __init__(self, use_custom_ports, add_body_contacts): def __init__(self, use_custom_ports, add_body_contacts):
self.use_custom_ports = use_custom_ports self.use_custom_ports = use_custom_ports
self.add_body_contacts = add_body_contacts self.add_body_contacts = add_body_contacts
class _bitcell_array: class _bitcell_array:
def __init__(self, use_custom_cell_arrangement): def __init__(self, use_custom_cell_arrangement):
self.use_custom_cell_arrangement = use_custom_cell_arrangement self.use_custom_cell_arrangement = use_custom_cell_arrangement
class cell_properties(): class cell_properties():
""" """
This contains meta information about the custom designed cells. For This contains meta information about the custom designed cells. For
@ -117,37 +137,65 @@ class cell_properties():
""" """
def __init__(self): def __init__(self):
self.names = {} self.names = {}
self.names["bitcell"] = "cell_6t"
self.names["bitcell_1rw_1r"] = "cell_1rw_1r"
self.names["bitcell_1w_1r"] = "cell_1w_1r"
self.names["dummy_bitcell"] = "dummy_cell_6t"
self.names["dummy_bitcell_1rw_1r"] = "dummy_cell_1rw_1r"
self.names["dummy_bitcell_1w_1r"] = "dummy_cell_1w_1r"
self.names["replica_bitcell"] = "replica_cell_6t"
self.names["replica_bitcell_1rw_1r"] = "replica_cell_1rw_1r"
self.names["replica_bitcell_1w_1r"] = "replica_cell_1w_1r"
self.names["col_cap_bitcell_6t"] = "col_cap_cell_6t"
self.names["col_cap_bitcell_1rw_1r"] = "col_cap_cell_1rw_1r"
self.names["col_cap_bitcell_1w_1r"] = "col_cap_cell_1w_1r"
self.names["row_cap_bitcell_6t"] = "row_cap_cell_6t"
self.names["row_cap_bitcell_1rw_1r"] = "row_cap_cell_1rw_1r"
self.names["row_cap_bitcell_1w_1r"] = "row_cap_cell_1w_1r"
self._bitcell = _bitcell._default() self._bitcell = _bitcell._default()
self._dff = _dff(use_custom_ports = False, self._ptx = _ptx(model_is_subckt=False,
custom_port_list = ["D", "Q", "clk", "vdd", "gnd"], bin_spice_models=False)
custom_type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
clk_pin= "clk")
self._dff_buff = _dff_buff(use_custom_ports = False, self._pgate = _pgate(add_implants=False)
custom_buff_ports = ["D", "qint", "clk", "vdd", "gnd"],
add_body_contacts = False)
self._dff_buff_array = _dff_buff_array(use_custom_ports = False, self._dff = _dff(use_custom_ports=False,
add_body_contacts = 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', self._write_driver = _cell({'din': 'din',
'bl' : 'bl', 'bl': 'bl',
'br' : 'br', 'br': 'br',
'en' : 'en'}) 'en': 'en'})
self._sense_amp = _cell({'bl' : 'bl', self._sense_amp = _cell({'bl': 'bl',
'br' : 'br', 'br': 'br',
'dout' : 'dout', 'dout': 'dout',
'en' : 'en'}) 'en': 'en'})
self._bitcell_array = _bitcell_array(use_custom_cell_arrangement = []) self._bitcell_array = _bitcell_array(use_custom_cell_arrangement=[])
@property @property
def bitcell(self): def bitcell(self):
return self._bitcell return self._bitcell
@property
def ptx(self):
return self._ptx
@property
def pgate(self):
return self._pgate
@property @property
def dff(self): def dff(self):
return self._dff return self._dff

View File

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

View File

@ -8,22 +8,29 @@
from hierarchy_design import hierarchy_design from hierarchy_design import hierarchy_design
from utils import round_to_grid from utils import round_to_grid
import contact import contact
from tech import preferred_directions
from tech import cell_properties as props
from globals import OPTS from globals import OPTS
import re import re
import debug
class design(hierarchy_design): class design(hierarchy_design):
""" """
This is the same as the hierarchy_design class except it contains This is the same as the hierarchy_design class except it contains
some DRC/layer constants and analytical models for other modules to reuse. some DRC/layer constants and analytical models for other modules to reuse.
""" """
def __init__(self, name): def __init__(self, name, cell_name=None):
super().__init__(name) # This allows us to use different GDS/spice circuits for hard cells instead of the default ones
# Except bitcell names are generated automatically by the globals.py setup_bitcells routines
# depending on the number of ports.
if name in props.names:
cell_name = props.names[name]
elif not cell_name:
cell_name = name
super().__init__(name, cell_name)
self.setup_drc_constants()
self.setup_layer_constants()
self.setup_multiport_constants() self.setup_multiport_constants()
def check_pins(self): def check_pins(self):
@ -32,7 +39,98 @@ class design(hierarchy_design):
for pin in pins: for pin in pins:
print(pin_name, pin) 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 These are some layer constants used
in many places in the compiler. in many places in the compiler.
@ -46,7 +144,7 @@ class design(hierarchy_design):
# Set the stack as a local helper # Set the stack as a local helper
try: try:
layer_stack = getattr(tech, key) layer_stack = getattr(tech, key)
setattr(self, key, layer_stack) setattr(design, key, layer_stack)
except AttributeError: except AttributeError:
pass pass
@ -55,14 +153,14 @@ class design(hierarchy_design):
continue continue
# Add the pitch # Add the pitch
setattr(self, setattr(design,
"{}_pitch".format(layer), "{}_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) # Add the non-preferrd pitch (which has vias in the "wrong" way)
setattr(self, setattr(design,
"{}_nonpref_pitch".format(layer), "{}_nonpref_pitch".format(layer),
self.compute_pitch(layer, False)) design.compute_pitch(layer, False))
if False: if False:
from tech import preferred_directions from tech import preferred_directions
@ -73,17 +171,18 @@ class design(hierarchy_design):
continue continue
try: try:
print("{0} width {1} space {2}".format(name, print("{0} width {1} space {2}".format(name,
getattr(self, "{}_width".format(name)), getattr(design, "{}_width".format(name)),
getattr(self, "{}_space".format(name)))) getattr(design, "{}_space".format(name))))
print("pitch {0} nonpref {1}".format(getattr(self, "{}_pitch".format(name)), print("pitch {0} nonpref {1}".format(getattr(design, "{}_pitch".format(name)),
getattr(self, "{}_nonpref_pitch".format(name)))) getattr(design, "{}_nonpref_pitch".format(name))))
except AttributeError: except AttributeError:
pass pass
import sys import sys
sys.exit(1) sys.exit(1)
def compute_pitch(self, layer, preferred=True): @staticmethod
def compute_pitch(layer, preferred=True):
""" """
This is the preferred direction pitch This is the preferred direction pitch
@ -95,13 +194,18 @@ class design(hierarchy_design):
for stack in layer_stacks: for stack in layer_stacks:
# Compute the pitch with both vias above and below (if they exist) # Compute the pitch with both vias above and below (if they exist)
if stack[0] == layer: if stack[0] == layer:
pitches.append(self.compute_layer_pitch(stack, preferred)) pitches.append(design.compute_layer_pitch(stack, preferred))
if stack[2] == layer: 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) 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 (layer1, via, layer2) = layer_stack
try: try:
@ -113,16 +217,16 @@ class design(hierarchy_design):
contact1 = getattr(contact, layer2 + "_via") contact1 = getattr(contact, layer2 + "_via")
if preferred: if preferred:
if self.get_preferred_direction(layer1) == "V": if preferred_directions[layer1] == "V":
contact_width = contact1.first_layer_width contact_width = contact1.first_layer_width
else: else:
contact_width = contact1.first_layer_height contact_width = contact1.first_layer_height
else: else:
if self.get_preferred_direction(layer1) == "V": if preferred_directions[layer1] == "V":
contact_width = contact1.first_layer_height contact_width = contact1.first_layer_height
else: else:
contact_width = contact1.first_layer_width contact_width = contact1.first_layer_width
layer_space = getattr(self, layer1 + "_space") layer_space = getattr(design, layer1 + "_space")
#print(layer_stack) #print(layer_stack)
#print(contact1) #print(contact1)
@ -130,94 +234,6 @@ class design(hierarchy_design):
return round_to_grid(pitch) 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): def setup_multiport_constants(self):
""" """
@ -266,3 +282,6 @@ class design(hierarchy_design):
total_module_power += inst.mod.analytical_power(corner, load) total_module_power += inst.mod.analytical_power(corner, load)
return total_module_power return total_module_power
design.setup_drc_constants()
design.setup_layer_constants()

View File

@ -227,7 +227,7 @@ class instance(geometry):
self.mod.gds_write_file(self.gds) self.mod.gds_write_file(self.gds)
# now write an instance of my module/structure # now write an instance of my module/structure
new_layout.addInstance(self.gds, new_layout.addInstance(self.gds,
self.mod.name, self.mod.cell_name,
offsetInMicrons=self.offset, offsetInMicrons=self.offset,
mirror=self.mirror, mirror=self.mirror,
rotate=self.rotate) rotate=self.rotate)
@ -402,11 +402,11 @@ class instance(geometry):
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.name + " " + self.mirror + " R=" + str(self.rotate) + ")" return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.cell_name + " " + self.mirror + " R=" + str(self.rotate) + ")"
def __repr__(self): def __repr__(self):
""" override print function output """ """ override print function output """
return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.name + " " + self.mirror + " R=" + str(self.rotate) + ")" return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.cell_name + " " + self.mirror + " R=" + str(self.rotate) + ")"
class path(geometry): class path(geometry):

View File

@ -20,9 +20,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
""" """
name_map = [] name_map = []
def __init__(self, name): def __init__(self, name, cell_name):
self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" self.gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds"
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.sp_file = OPTS.openram_tech + "sp_lib/" + cell_name + ".sp"
# If we have a separate lvs directory, then all the lvs files # If we have a separate lvs directory, then all the lvs files
# should be in there (all or nothing!) # should be in there (all or nothing!)
@ -33,7 +33,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
lvs_dir = OPTS.openram_tech + lvs_subdir + "/" lvs_dir = OPTS.openram_tech + lvs_subdir + "/"
if os.path.exists(lvs_dir): if os.path.exists(lvs_dir):
self.lvs_file = lvs_dir + name + ".sp" self.lvs_file = lvs_dir + cell_name + ".sp"
else: else:
self.lvs_file = self.sp_file self.lvs_file = self.sp_file
@ -41,8 +41,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.lvs_errors = "skipped" self.lvs_errors = "skipped"
self.name = name self.name = name
hierarchy_spice.spice.__init__(self, name) self.cell_name = cell_name
hierarchy_layout.layout.__init__(self, name) hierarchy_spice.spice.__init__(self, name, cell_name)
hierarchy_layout.layout.__init__(self, name, cell_name)
self.init_graph_params() self.init_graph_params()
def get_layout_pins(self, inst): def get_layout_pins(self, inst):
@ -76,20 +77,20 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.lvs_write(tempspice) self.lvs_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
# Final verification option does not allow nets to be connected by label. # Final verification option does not allow nets to be connected by label.
self.drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification) self.drc_errors = verify.run_drc(self.cell_name, tempgds, extract=True, final_verification=final_verification)
self.lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) self.lvs_errors = verify.run_lvs(self.cell_name, tempgds, tempspice, final_verification=final_verification)
# force_check is used to determine decoder height and other things, so we shouldn't fail # force_check is used to determine decoder height and other things, so we shouldn't fail
# if that flag is set # if that flag is set
if OPTS.inline_lvsdrc and not force_check: if OPTS.inline_lvsdrc and not force_check:
debug.check(self.drc_errors == 0, debug.check(self.drc_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.name, "DRC failed for {0} with {1} error(s)".format(self.cell_name,
self.drc_errors)) self.drc_errors))
debug.check(self.lvs_errors == 0, debug.check(self.lvs_errors == 0,
"LVS failed for {0} with {1} errors(s)".format(self.name, "LVS failed for {0} with {1} errors(s)".format(self.cell_name,
self.lvs_errors)) self.lvs_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
@ -104,14 +105,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only: if OPTS.netlist_only:
return return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.cell_name)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification) num_errors = verify.run_drc(self.cell_name, tempgds, final_verification=final_verification)
debug.check(num_errors == 0, debug.check(num_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.name, "DRC failed for {0} with {1} error(s)".format(self.cell_name,
num_errors)) num_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempgds) os.remove(tempgds)
def LVS(self, final_verification=False): def LVS(self, final_verification=False):
@ -125,15 +126,15 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only: if OPTS.netlist_only:
return return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name) tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.cell_name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice) self.lvs_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0, debug.check(num_errors == 0,
"LVS failed for {0} with {1} error(s)".format(self.name, "LVS failed for {0} with {1} error(s)".format(self.cell_name,
num_errors)) num_errors))
if OPTS.purge_temp: if not OPTS.keep_temp:
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
@ -217,7 +218,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
pins = ",".join(self.pins) pins = ",".join(self.pins)
insts = [" {}".format(x) for x in self.insts] insts = [" {}".format(x) for x in self.insts]
objs = [" {}".format(x) for x in self.objs] objs = [" {}".format(x) for x in self.objs]
s = "********** design {0} **********".format(self.name) s = "********** design {0} **********".format(self.cell_name)
s += "\n pins ({0})={1}\n".format(len(self.pins), pins) s += "\n pins ({0})={1}\n".format(len(self.pins), pins)
s += "\n objs ({0})=\n{1}\n".format(len(self.objs), "\n".join(objs)) s += "\n objs ({0})=\n{1}\n".format(len(self.objs), "\n".join(objs))
s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts)) s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts))

View File

@ -31,8 +31,9 @@ class layout():
layout/netlist and perform LVS/DRC. layout/netlist and perform LVS/DRC.
""" """
def __init__(self, name): def __init__(self, name, cell_name):
self.name = name self.name = name
self.cell_name = cell_name
self.width = None self.width = None
self.height = None self.height = None
self.bounding_box = None self.bounding_box = None
@ -215,7 +216,7 @@ class layout():
# Contacts are not really instances, so skip them # Contacts are not really instances, so skip them
if "contact" not in mod.name: if "contact" not in mod.name:
# Check that the instance name is unique # Check that the instance name is unique
debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.name, name)) debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.cell_name, name))
self.inst_names.add(name) self.inst_names.add(name)
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
@ -316,7 +317,7 @@ class layout():
return any_pin return any_pin
except Exception: except Exception:
self.gds_write("missing_pin.gds") self.gds_write("missing_pin.gds")
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text, self.name), -1) debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text, self.cell_name), -1)
def get_pins(self, text): def get_pins(self, text):
""" """
@ -537,10 +538,6 @@ class layout():
position_list=coordinates, position_list=coordinates,
widen_short_wires=widen_short_wires) 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): def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """ """ Add a three layer via structure. """
from sram_factory import factory from sram_factory import factory

View File

@ -10,6 +10,7 @@ import re
import os import os
import math import math
import tech import tech
from pprint import pformat
from delay_data import delay_data from delay_data import delay_data
from wire_spice_model import wire_spice_model from wire_spice_model import wire_spice_model
from power_data import power_data from power_data import power_data
@ -26,8 +27,9 @@ class spice():
Class consisting of a set of modules and instances of these modules Class consisting of a set of modules and instances of these modules
""" """
def __init__(self, name): def __init__(self, name, cell_name):
self.name = name self.name = name
self.cell_name = cell_name
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"] self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
@ -164,7 +166,6 @@ class spice():
num_pins = len(self.insts[-1].mod.pins) num_pins = len(self.insts[-1].mod.pins)
num_args = len(args) num_args = len(args)
if (check and num_pins != num_args): if (check and num_pins != num_args):
from pprint import pformat
if num_pins < num_args: if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
arg_pins = args arg_pins = args
@ -181,7 +182,6 @@ class spice():
self.conns.append(args) self.conns.append(args)
if check and (len(self.insts)!=len(self.conns)): if check and (len(self.insts)!=len(self.conns)):
from pprint import pformat
insts_string=pformat(self.insts) insts_string=pformat(self.insts)
conns_string=pformat(self.conns) conns_string=pformat(self.conns)
@ -214,7 +214,7 @@ class spice():
f.close() f.close()
# find the correct subckt line in the file # find the correct subckt line in the file
subckt = re.compile("^.subckt {}".format(self.name), re.IGNORECASE) subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE)
subckt_line = list(filter(subckt.search, self.spice))[0] subckt_line = list(filter(subckt.search, self.spice))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
self.pins = subckt_line.split(" ")[2:] self.pins = subckt_line.split(" ")[2:]
@ -234,7 +234,7 @@ class spice():
# pins and subckt should be the same # pins and subckt should be the same
# find the correct subckt line in the file # find the correct subckt line in the file
subckt = re.compile("^.subckt {}".format(self.name), re.IGNORECASE) subckt = re.compile("^.subckt {}".format(self.cell_name), re.IGNORECASE)
subckt_line = list(filter(subckt.search, self.lvs))[0] subckt_line = list(filter(subckt.search, self.lvs))[0]
# parses line into ports and remove subckt # parses line into ports and remove subckt
lvs_pins = subckt_line.split(" ")[2:] lvs_pins = subckt_line.split(" ")[2:]
@ -293,7 +293,7 @@ class spice():
return return
# write out the first spice line (the subcircuit) # write out the first spice line (the subcircuit)
sp.write("\n.SUBCKT {0} {1}\n".format(self.name, sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name,
" ".join(self.pins))) " ".join(self.pins)))
for pin in self.pins: for pin in self.pins:
@ -304,7 +304,7 @@ class spice():
# every instance must have a set of connections, even if it is empty. # every instance must have a set of connections, even if it is empty.
if len(self.insts) != len(self.conns): if len(self.insts) != len(self.conns):
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.cell_name,
len(self.insts), len(self.insts),
len(self.conns))) len(self.conns)))
debug.error("Instances: \n" + str(self.insts)) debug.error("Instances: \n" + str(self.insts))
@ -330,9 +330,9 @@ class spice():
else: else:
sp.write("X{0} {1} {2}\n".format(self.insts[i].name, sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
" ".join(self.conns[i]), " ".join(self.conns[i]),
self.insts[i].mod.name)) self.insts[i].mod.cell_name))
sp.write(".ENDS {0}\n".format(self.name)) sp.write(".ENDS {0}\n".format(self.cell_name))
else: else:
# If spice is a hard module, output the spice file contents. # If spice is a hard module, output the spice file contents.
@ -390,7 +390,7 @@ class spice():
.format(self.__class__.__name__)) .format(self.__class__.__name__))
debug.warning("Class {0} name {1}" debug.warning("Class {0} name {1}"
.format(self.__class__.__name__, .format(self.__class__.__name__,
self.name)) self.cell_name))
return None return None
def get_cin(self): def get_cin(self):
@ -408,7 +408,7 @@ class spice():
.format(self.__class__.__name__)) .format(self.__class__.__name__))
debug.warning("Class {0} name {1}" debug.warning("Class {0} name {1}"
.format(self.__class__.__name__, .format(self.__class__.__name__,
self.name)) self.cell_name))
return 0 return 0
def cal_delay_with_rc(self, corner, r, c, slew, swing=0.5): def cal_delay_with_rc(self, corner, r, c, slew, swing=0.5):

View File

@ -5,14 +5,9 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import gdsMill
import tech
import globals
import math
import debug import debug
import datetime from tech import layer_names
from collections import defaultdict
import pdb
class lef: class lef:
""" """
@ -20,13 +15,13 @@ class lef:
and write them to LEF file. and write them to LEF file.
This is inherited by the sram_base class. This is inherited by the sram_base class.
""" """
def __init__(self,layers): def __init__(self, layers):
# LEF db units per micron # LEF db units per micron
self.lef_units = 2000 self.lef_units = 2000
# These are the layers of the obstructions # These are the layers of the obstructions
self.lef_layers = layers self.lef_layers = layers
# Round to ensure float values are divisible by 0.0025 (the manufacturing grid) # Round to ensure float values are divisible by 0.0025 (the manufacturing grid)
self.round_grid = 4; self.round_grid = 4
def lef_write(self, lef_name): def lef_write(self, lef_name):
"""Write the entire lef of the object to the file.""" """Write the entire lef of the object to the file."""
@ -34,7 +29,7 @@ class lef:
self.indent = "" # To maintain the indent level easily self.indent = "" # To maintain the indent level easily
self.lef = open(lef_name,"w") self.lef = open(lef_name, "w")
self.lef_write_header() self.lef_write_header()
for pin in self.pins: for pin in self.pins:
self.lef_write_pin(pin) self.lef_write_pin(pin)
@ -52,30 +47,29 @@ class lef:
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units)) self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
self.lef.write("END UNITS\n") self.lef.write("END UNITS\n")
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name)) self.lef.write("{0}MACRO {1}\n".format(self.indent, self.name))
self.indent += " " self.indent += " "
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent)) self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent, self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
round(self.width,self.round_grid), round(self.width, self.round_grid),
round(self.height,self.round_grid))) round(self.height, self.round_grid)))
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent)) self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
def lef_write_footer(self): def lef_write_footer(self):
self.lef.write("{0}END {1}\n".format(self.indent,self.name)) self.lef.write("{0}END {1}\n".format(self.indent, self.name))
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("END LIBRARY\n") self.lef.write("END LIBRARY\n")
def lef_write_pin(self, name): def lef_write_pin(self, name):
pin_dir = self.get_pin_dir(name) pin_dir = self.get_pin_dir(name)
pin_type = self.get_pin_type(name) pin_type = self.get_pin_type(name)
self.lef.write("{0}PIN {1}\n".format(self.indent,name)) self.lef.write("{0}PIN {1}\n".format(self.indent, name))
self.indent += " " self.indent += " "
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent,pin_dir)) self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent, pin_dir))
if pin_type in ["POWER","GROUND"]: if pin_type in ["POWER", "GROUND"]:
self.lef.write("{0}USE {1} ; \n".format(self.indent,pin_type)) self.lef.write("{0}USE {1} ; \n".format(self.indent, pin_type))
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent)) self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
self.lef.write("{0}PORT\n".format(self.indent)) self.lef.write("{0}PORT\n".format(self.indent))
@ -84,7 +78,7 @@ class lef:
# We could sort these together to minimize different layer sections, but meh. # We could sort these together to minimize different layer sections, but meh.
pin_list = self.get_pins(name) pin_list = self.get_pins(name)
for pin in pin_list: for pin in pin_list:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer)) self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[pin.layer]))
self.lef_write_shape(pin.rect) self.lef_write_shape(pin.rect)
# End the PORT # End the PORT
@ -93,19 +87,16 @@ class lef:
# End the PIN # End the PIN
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("{0}END {1}\n".format(self.indent,name)) self.lef.write("{0}END {1}\n".format(self.indent, name))
def lef_write_obstructions(self): def lef_write_obstructions(self):
""" Write all the obstructions on each layer """ """ Write all the obstructions on each layer """
self.lef.write("{0}OBS\n".format(self.indent)) self.lef.write("{0}OBS\n".format(self.indent))
for layer in self.lef_layers: for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer)) self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
self.indent += " " self.indent += " "
# pdb.set_trace() blockages = self.get_blockages(layer, True)
blockages = self.get_blockages(layer,True)
for b in blockages: for b in blockages:
# if len(b) > 2:
# print(b)
self.lef_write_shape(b) self.lef_write_shape(b)
self.indent = self.indent[:-3] self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent)) self.lef.write("{0}END\n".format(self.indent))
@ -116,13 +107,19 @@ class lef:
self.lef.write("{0}RECT ".format(self.indent)) self.lef.write("{0}RECT ".format(self.indent))
for item in rect: for item in rect:
# print(rect) # print(rect)
self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")
else: else:
""" Write a LEF polygon """ """ Write a LEF polygon """
self.lef.write("{0}POLYGON ".format(self.indent)) self.lef.write("{0}POLYGON ".format(self.indent))
for item in rect: for item in rect:
self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid))) self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
# for i in range(0,len(rect)): # for i in range(0,len(rect)):
# self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid))) # self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")

View File

@ -4,10 +4,12 @@
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
#
import os
import math
import gdsMill import gdsMill
import tech import tech
import math
import globals import globals
import debug import debug
from vector import vector from vector import vector
@ -57,10 +59,11 @@ def auto_measure_libcell(pin_list, name, units, lpp):
Return these as a set of properties including the cell width/height too. Return these as a set of properties including the cell width/height too.
""" """
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(cell_gds)
cell_vlsi = _get_gds_reader(units, cell_gds)
# FIXME: This duplicates a lot of functionality of get_gds_size and
# get_gds_pins, it should probably just call those functions?
cell = {} cell = {}
measure_result = cell_vlsi.getLayoutBorder(lpp[0]) measure_result = cell_vlsi.getLayoutBorder(lpp[0])
if measure_result: if measure_result:
@ -73,22 +76,47 @@ def auto_measure_libcell(pin_list, name, units, lpp):
return cell return cell
_GDS_READER_CACHE = {}
def _get_gds_reader(units, gds_filename):
gds_absname = os.path.realpath(gds_filename)
k = (units, gds_absname)
try:
return _GDS_READER_CACHE[k]
except KeyError:
debug.info(4, "Creating VLSI layout from {}".format(gds_absname))
cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(gds_absname)
_GDS_READER_CACHE[k] = cell_vlsi
return cell_vlsi
_GDS_SIZE_CACHE = {}
def get_gds_size(name, gds_filename, units, lpp): def get_gds_size(name, gds_filename, units, lpp):
""" """
Open a GDS file and return the size from either the Open a GDS file and return the size from either the
bounding box or a border layer. bounding box or a border layer.
""" """
debug.info(4, "Creating VLSI layout for {}".format(name)) k = (name, os.path.realpath(gds_filename), units, lpp)
cell_vlsi = gdsMill.VlsiLayout(units=units) try:
reader = gdsMill.Gds2reader(cell_vlsi) return _GDS_SIZE_CACHE[k]
reader.loadFromFile(gds_filename) except KeyError:
cell_vlsi = _get_gds_reader(units, gds_filename)
measure_result = cell_vlsi.getLayoutBorder(lpp) measure_result = cell_vlsi.getLayoutBorder(lpp)
if not measure_result: if not measure_result:
debug.info(2, "Layout border failed. Trying to measure size for {}".format(name)) debug.info(2, "Layout border failed. Trying to measure size for {}".format(name))
measure_result = cell_vlsi.measureSize(name) measure_result = cell_vlsi.measureSize(name)
# returns width,height
return measure_result _GDS_SIZE_CACHE[k] = measure_result
# returns width,height
return measure_result
def get_libcell_size(name, units, lpp): def get_libcell_size(name, units, lpp):
@ -101,27 +129,34 @@ def get_libcell_size(name, units, lpp):
return(get_gds_size(name, cell_gds, units, lpp)) return(get_gds_size(name, cell_gds, units, lpp))
_GDS_PINS_CACHE = {}
def get_gds_pins(pin_names, name, gds_filename, units): def get_gds_pins(pin_names, name, gds_filename, units):
""" """
Open a GDS file and find the pins in pin_names as text on a given layer. Open a GDS file and find the pins in pin_names as text on a given layer.
Return these as a rectangle layer pair for each pin. Return these as a rectangle layer pair for each pin.
""" """
cell_vlsi = gdsMill.VlsiLayout(units=units) k = (tuple(pin_names), name, os.path.realpath(gds_filename), units)
reader = gdsMill.Gds2reader(cell_vlsi) try:
reader.loadFromFile(gds_filename) return dict(_GDS_PINS_CACHE[k])
except KeyError:
cell_vlsi = _get_gds_reader(units, gds_filename)
cell = {} cell = {}
for pin_name in pin_names: for pin_name in pin_names:
cell[str(pin_name)] = [] cell[str(pin_name)] = []
pin_list = cell_vlsi.getPinShape(str(pin_name)) pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list: for pin_shape in pin_list:
(lpp, boundary) = pin_shape (lpp, boundary) = pin_shape
rect = [vector(boundary[0], boundary[1]), rect = [vector(boundary[0], boundary[1]),
vector(boundary[2], boundary[3])] vector(boundary[2], boundary[3])]
# this is a list because other cells/designs # this is a list because other cells/designs
# may have must-connect pins # may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp)) cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
return cell
_GDS_PINS_CACHE[k] = cell
return dict(cell)
def get_libcell_pins(pin_list, name, units): def get_libcell_pins(pin_list, name, units):
@ -132,7 +167,3 @@ def get_libcell_pins(pin_list, name, units):
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
return(get_gds_pins(pin_list, name, cell_gds, units)) return(get_gds_pins(pin_list, name, cell_gds, units))

View File

@ -6,11 +6,9 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
from globals import OPTS
class bitcell(bitcell_base.bitcell_base): class bitcell(bitcell_base.bitcell_base):
""" """
@ -20,8 +18,6 @@ class bitcell(bitcell_base.bitcell_base):
library. library.
""" """
# If we have a split WL bitcell, if not be backwards
# compatible in the tech file
pin_names = [props.bitcell.cell_6t.pin.bl, pin_names = [props.bitcell.cell_6t.pin.bl,
props.bitcell.cell_6t.pin.br, props.bitcell.cell_6t.pin.br,
props.bitcell.cell_6t.pin.wl, props.bitcell.cell_6t.pin.wl,
@ -30,24 +26,12 @@ class bitcell(bitcell_base.bitcell_base):
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar'] storage_nets = ['Q', 'Q_bar']
(width, height) = utils.get_libcell_size("cell_6t", def __init__(self, name):
GDS["unit"], super().__init__(name)
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
bitcell_base.bitcell_base.__init__(self, "cell_6t")
debug.info(2, "Create bitcell") debug.info(2, "Create bitcell")
self.width = bitcell.width
self.height = bitcell.height
self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets) 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): def get_all_wl_names(self):
""" Creates a list of all wordline pin names """ """ Creates a list of all wordline pin names """
row_pins = [props.bitcell.cell_6t.pin.wl] row_pins = [props.bitcell.cell_6t.pin.wl]

View File

@ -6,10 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer, parameter, drc
from tech import cell_properties as props from tech import cell_properties as props
import logical_effort
import bitcell_base import bitcell_base
@ -29,27 +26,17 @@ class bitcell_1rw_1r(bitcell_base.bitcell_base):
props.bitcell.cell_1rw1r.pin.wl1, props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd, props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd] props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"INPUT", "INPUT", "POWER", "GROUND"] "INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar'] storage_nets = ['Q', 'Q_bar']
(width, height) = utils.get_libcell_size("cell_1rw_1r",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
bitcell_base.bitcell_base.__init__(self, "cell_1rw_1r")
debug.info(2, "Create bitcell with 1RW and 1R Port") debug.info(2, "Create bitcell with 1RW and 1R Port")
self.width = bitcell_1rw_1r.width
self.height = bitcell_1rw_1r.height
self.pin_map = bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets) self.nets_match = self.do_nets_exist(self.storage_nets)
pin_names = bitcell_1rw_1r.pin_names pin_names = self.pin_names
self.bl_names = [pin_names[0], pin_names[2]] self.bl_names = [pin_names[0], pin_names[2]]
self.br_names = [pin_names[1], pin_names[3]] self.br_names = [pin_names[1], pin_names[3]]
self.wl_names = [pin_names[4], pin_names[5]] self.wl_names = [pin_names[4], pin_names[5]]

View File

@ -6,8 +6,6 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
@ -31,28 +29,18 @@ class bitcell_1w_1r(bitcell_base.bitcell_base):
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT",
"INPUT", "INPUT", "POWER", "GROUND"] "INPUT", "INPUT", "POWER", "GROUND"]
storage_nets = ['Q', 'Q_bar'] storage_nets = ['Q', 'Q_bar']
(width, height) = utils.get_libcell_size("cell_1w_1r",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1w_1r", GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
bitcell_base.bitcell_base.__init__(self, "cell_1w_1r")
debug.info(2, "Create bitcell with 1W and 1R Port") debug.info(2, "Create bitcell with 1W and 1R Port")
self.width = bitcell_1w_1r.width
self.height = bitcell_1w_1r.height
self.pin_map = bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
self.nets_match = self.do_nets_exist(self.storage_nets) self.nets_match = self.do_nets_exist(self.storage_nets)
pin_names = bitcell_1w_1r.pin_names pin_names = self.pin_names
self.bl_names = [pin_names[0], pin_names[2]] self.bl_names = [pin_names[0], pin_names[2]]
self.br_names = [pin_names[1], pin_names[3]] self.br_names = [pin_names[1], pin_names[3]]
self.wl_names = [pin_names[4], pin_names[5]] self.wl_names = [pin_names[4], pin_names[5]]
def get_bitcell_pins(self, col, row): def get_bitcell_pins(self, col, row):
""" """
Creates a list of connections in the bitcell, Creates a list of connections in the bitcell,

View File

@ -8,18 +8,30 @@
import debug import debug
import design import design
import utils
from globals import OPTS from globals import OPTS
import logical_effort import logical_effort
from tech import parameter, drc, layer from tech import GDS, parameter, drc, layer
class bitcell_base(design.design): class bitcell_base(design.design):
""" """
Base bitcell parameters to be over-riden. Base bitcell parameters to be over-riden.
""" """
def __init__(self, name): cell_size_layer = "boundary"
def __init__(self, name, hard_cell=True):
design.design.__init__(self, name) design.design.__init__(self, name)
if hard_cell:
(self.width, self.height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
self.pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.add_pin_types(self.type_list)
def get_stage_effort(self, load): def get_stage_effort(self, load):
parasitic_delay = 1 parasitic_delay = 1
# This accounts for bitline being drained # This accounts for bitline being drained

View File

@ -6,39 +6,25 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
""" """
todo""" Column end cap cell.
"""
pin_names = [props.bitcell.cell_1rw1r.pin.bl0, pin_names = [props.bitcell.cell_1rw1r.pin.bl0,
props.bitcell.cell_1rw1r.pin.br0, props.bitcell.cell_1rw1r.pin.br0,
props.bitcell.cell_1rw1r.pin.bl1, props.bitcell.cell_1rw1r.pin.bl1,
props.bitcell.cell_1rw1r.pin.br1, props.bitcell.cell_1rw1r.pin.br1,
props.bitcell.cell_1rw1r.pin.vdd] props.bitcell.cell_1rw1r.pin.vdd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"POWER", "GROUND"] "POWER", "GROUND"]
(width, height) = utils.get_libcell_size("col_cap_cell_1rw_1r", def __init__(self, name="col_cap_cell_1rw_1r"):
GDS["unit"], bitcell_base.bitcell_base.__init__(self, name)
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names,
"col_cap_cell_1rw_1r",
GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
bitcell_base.bitcell_base.__init__(self, "col_cap_cell_1rw_1r")
debug.info(2, "Create col_cap bitcell 1rw+1r object") debug.info(2, "Create col_cap bitcell 1rw+1r object")
self.width = col_cap_bitcell_1rw_1r.width
self.height = col_cap_bitcell_1rw_1r.height
self.pin_map = col_cap_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.no_instances = True self.no_instances = True

View File

@ -6,8 +6,6 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
@ -24,19 +22,10 @@ class dummy_bitcell(bitcell_base.bitcell_base):
props.bitcell.cell_6t.pin.wl, props.bitcell.cell_6t.pin.wl,
props.bitcell.cell_6t.pin.vdd, props.bitcell.cell_6t.pin.vdd,
props.bitcell.cell_6t.pin.gnd] props.bitcell.cell_6t.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width, height) = utils.get_libcell_size("dummy_cell_6t", def __init__(self, name):
GDS["unit"], super().__init__(name)
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_6t", GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
bitcell_base.bitcell_base.__init__(self, "dummy_cell_6t")
debug.info(2, "Create dummy bitcell") debug.info(2, "Create dummy bitcell")
self.width = dummy_bitcell.width
self.height = dummy_bitcell.height
self.pin_map = dummy_bitcell.pin_map

View File

@ -6,8 +6,6 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
@ -27,23 +25,11 @@ class dummy_bitcell_1rw_1r(bitcell_base.bitcell_base):
props.bitcell.cell_1rw1r.pin.wl1, props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd, props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd] props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT",
"INPUT", "INPUT", "POWER", "GROUND"] "INPUT", "INPUT", "POWER", "GROUND"]
(width, height) = utils.get_libcell_size("dummy_cell_1rw_1r",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names,
"dummy_cell_1rw_1r",
GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
bitcell_base.bitcell_base.__init__(self, "dummy_cell_1rw_1r")
debug.info(2, "Create dummy bitcell 1rw+1r object") debug.info(2, "Create dummy bitcell 1rw+1r object")
self.width = dummy_bitcell_1rw_1r.width
self.height = dummy_bitcell_1rw_1r.height
self.pin_map = dummy_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)

View File

@ -6,8 +6,6 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
@ -29,21 +27,11 @@ class dummy_bitcell_1w_1r(bitcell_base.bitcell_base):
props.bitcell.cell_1w1r.pin.gnd] props.bitcell.cell_1w1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT",
"INPUT", "INPUT", "POWER", "GROUND"] "INPUT", "INPUT", "POWER", "GROUND"]
(width, height) = utils.get_libcell_size("dummy_cell_1w_1r",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names,
"dummy_cell_1w_1r",
GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
bitcell_base.bitcell_base.__init__(self, "dummy_cell_1w_1r")
debug.info(2, "Create dummy bitcell 1w+1r object") debug.info(2, "Create dummy bitcell 1w+1r object")
self.width = dummy_bitcell_1w_1r.width
self.height = dummy_bitcell_1w_1r.height
self.pin_map = dummy_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)

View File

@ -7,17 +7,17 @@
# #
import debug import debug
import design import design
from tech import drc, spice,parameter
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class dummy_pbitcell(design.design): class dummy_pbitcell(design.design):
""" """
Creates a replica bitcell using pbitcell Creates a replica bitcell using pbitcell
""" """
def __init__(self, name): def __init__(self, name, cell_name=None):
self.num_rw_ports = OPTS.num_rw_ports self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
@ -54,7 +54,8 @@ class dummy_pbitcell(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.prbc = factory.create(module_type="pbitcell",dummy_bitcell=True) self.prbc = factory.create(module_type="pbitcell",
dummy_bitcell=True)
self.add_mod(self.prbc) self.add_mod(self.prbc)
self.height = self.prbc.height self.height = self.prbc.height
@ -75,7 +76,7 @@ class dummy_pbitcell(design.design):
self.connect_inst(temp) self.connect_inst(temp)
def place_pbitcell(self): def place_pbitcell(self):
self.prbc_inst.place(offset=vector(0,0)) self.prbc_inst.place(offset=vector(0, 0))
def route_rbc_connections(self): def route_rbc_connections(self):
for port in range(self.total_ports): for port in range(self.total_ports):

View File

@ -30,7 +30,7 @@ class pbitcell(bitcell_base.bitcell_base):
self.replica_bitcell = replica_bitcell self.replica_bitcell = replica_bitcell
self.dummy_bitcell = dummy_bitcell self.dummy_bitcell = dummy_bitcell
bitcell_base.bitcell_base.__init__(self, name) bitcell_base.bitcell_base.__init__(self, name, hard_cell=False)
fmt_str = "{0} rw ports, {1} w ports and {2} r ports" fmt_str = "{0} rw ports, {1} w ports and {2} r ports"
info_string = fmt_str.format(self.num_rw_ports, info_string = fmt_str.format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,

View File

@ -5,15 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design
import debug import debug
import utils import bitcell_base
from tech import GDS,layer,drc,parameter,cell_properties
from tech import cell_properties as props from tech import cell_properties as props
from tech import parameter, drc
import logical_effort
from globals import OPTS
class replica_bitcell(design.design): class replica_bitcell(bitcell_base.bitcell_base):
""" """
A single bit cell (6T, 8T, etc.) A single bit cell (6T, 8T, etc.)
This module implements the single memory cell used in the design. It This module implements the single memory cell used in the design. It
@ -27,42 +26,29 @@ class replica_bitcell(design.design):
props.bitcell.cell_6t.pin.gnd] props.bitcell.cell_6t.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: def __init__(self, name):
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) super().__init__(name)
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
else:
(width,height) = (0,0)
pin_map = []
def __init__(self, name=""):
# Ignore the name argument
design.design.__init__(self, "replica_cell_6t")
debug.info(2, "Create replica bitcell object") debug.info(2, "Create replica bitcell object")
self.width = replica_bitcell.width
self.height = replica_bitcell.height
self.pin_map = replica_bitcell.pin_map
self.add_pin_types(self.type_list)
def get_stage_effort(self, load): def get_stage_effort(self, load):
parasitic_delay = 1 parasitic_delay = 1
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
read_port_load = 0.5 #min size NMOS gate load read_port_load = 0.5 # min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
def input_load(self): def input_load(self):
"""Return the relative capacitance of the access transistor gates""" """Return the relative capacitance of the access transistor gates"""
# FIXME: This applies to bitline capacitances as well. # FIXME: This applies to bitline capacitances as well.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"] / drc["minwidth_tx"]
return 2*access_tx_cin return 2 * access_tx_cin
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage.""" """Bitcell power in nW. Only characterizes leakage."""
from tech import spice from tech import spice
leakage = spice["bitcell_leakage"] leakage = spice["bitcell_leakage"]
dynamic = 0 #temporary dynamic = 0 # FIXME
total_power = self.return_power(dynamic, leakage) total_power = self.return_power(dynamic, leakage)
return total_power return total_power

View File

@ -5,13 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design
import debug import debug
import utils import bitcell_base
from tech import GDS,layer,drc,parameter
from tech import cell_properties as props from tech import cell_properties as props
from tech import parameter, drc
import logical_effort
class replica_bitcell_1rw_1r(design.design):
class replica_bitcell_1rw_1r(bitcell_base.bitcell_base):
""" """
A single bit cell which is forced to store a 0. A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It This module implements the single memory cell used in the design. It
@ -26,42 +27,33 @@ class replica_bitcell_1rw_1r(design.design):
props.bitcell.cell_1rw1r.pin.wl1, props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.vdd, props.bitcell.cell_1rw1r.pin.vdd,
props.bitcell.cell_1rw1r.pin.gnd] props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
design.design.__init__(self, "replica_cell_1rw_1r")
debug.info(2, "Create replica bitcell 1rw+1r object") debug.info(2, "Create replica bitcell 1rw+1r object")
self.width = replica_bitcell_1rw_1r.width
self.height = replica_bitcell_1rw_1r.height
self.pin_map = replica_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
def get_stage_effort(self, load): def get_stage_effort(self, load):
parasitic_delay = 1 parasitic_delay = 1
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
read_port_load = 0.5 #min size NMOS gate load read_port_load = 0.5 # min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
def input_load(self): def input_load(self):
"""Return the relative capacitance of the access transistor gates""" """Return the relative capacitance of the access transistor gates"""
# FIXME: This applies to bitline capacitances as well. # FIXME: This applies to bitline capacitances as well.
# FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"] / drc["minwidth_tx"]
return 2*access_tx_cin return 2 * access_tx_cin
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex """Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function.""" to use the add_graph_edges function."""
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell.cell_1rw1r.pin pins = props.bitcell.cell_1rw1r.pin
#Edges hardcoded here. Essentially wl->bl/br for both ports. # Edges hardcoded here. Essentially wl->bl/br for both ports.
# Port 0 edges # Port 0 edges
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.bl0], self) graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.bl0], self)
graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.br0], self) graph.add_edge(pin_dict[pins.wl0], pin_dict[pins.br0], self)

View File

@ -5,13 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design
import debug import debug
import utils import bitcell_base
from tech import GDS,layer,drc,parameter
from tech import cell_properties as props from tech import cell_properties as props
from tech import parameter, drc
import logical_effort
class replica_bitcell_1w_1r(design.design):
class replica_bitcell_1w_1r(bitcell_base.bitcell_base):
""" """
A single bit cell which is forced to store a 0. A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It This module implements the single memory cell used in the design. It
@ -26,43 +27,34 @@ class replica_bitcell_1w_1r(design.design):
props.bitcell.cell_1w1r.pin.wl1, props.bitcell.cell_1w1r.pin.wl1,
props.bitcell.cell_1w1r.pin.vdd, props.bitcell.cell_1w1r.pin.vdd,
props.bitcell.cell_1w1r.pin.gnd] props.bitcell.cell_1w1r.pin.gnd]
type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1w_1r", GDS["unit"])
def __init__(self, name=""): def __init__(self, name):
# Ignore the name argument super().__init__(name)
design.design.__init__(self, "replica_cell_1w_1r")
debug.info(2, "Create replica bitcell 1w+1r object") debug.info(2, "Create replica bitcell 1w+1r object")
self.width = replica_bitcell_1w_1r.width
self.height = replica_bitcell_1w_1r.height
self.pin_map = replica_bitcell_1w_1r.pin_map
self.add_pin_types(self.type_list)
def get_stage_effort(self, load): def get_stage_effort(self, load):
parasitic_delay = 1 parasitic_delay = 1
size = 0.5 #This accounts for bitline being drained thought the access TX and internal node size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
cin = 3 #Assumes always a minimum sizes inverter. Could be specified in the tech.py file. cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
read_port_load = 0.5 #min size NMOS gate load read_port_load = 0.5 # min size NMOS gate load
return logical_effort.logical_effort('bitline', size, cin, load+read_port_load, parasitic_delay, False) return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
def input_load(self): def input_load(self):
"""Return the relative capacitance of the access transistor gates""" """Return the relative capacitance of the access transistor gates"""
# FIXME: This applies to bitline capacitances as well. # FIXME: This applies to bitline capacitances as well.
# FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] access_tx_cin = parameter["6T_access_size"] / drc["minwidth_tx"]
return 2*access_tx_cin return 2 * access_tx_cin
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges to graph. Multiport bitcell timing graph is too complex """Adds edges to graph. Multiport bitcell timing graph is too complex
to use the add_graph_edges function.""" to use the add_graph_edges function."""
debug.info(1,'Adding edges for {}'.format(inst_name)) debug.info(1, 'Adding edges for {}'.format(inst_name))
pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)} pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
pins = props.bitcell.cell_1w1r.pin pins = props.bitcell.cell_1w1r.pin
#Edges hardcoded here. Essentially wl->bl/br for the read port. # Edges hardcoded here. Essentially wl->bl/br for the read port.
# Port 1 edges # Port 1 edges
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self) graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.bl1], self)
graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self) graph.add_edge(pin_dict[pins.wl1], pin_dict[pins.br1], self)

View File

@ -7,23 +7,25 @@
# #
import debug import debug
import design import design
from tech import drc, spice,parameter
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class replica_pbitcell(design.design): class replica_pbitcell(design.design):
""" """
Creates a replica bitcell using pbitcell Creates a replica bitcell using pbitcell
""" """
def __init__(self, name): def __init__(self, name, cell_name=None):
if not cell_name:
cell_name = name
self.num_rw_ports = OPTS.num_rw_ports self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
design.design.__init__(self, name) design.design.__init__(self, name, cell_name)
debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,
self.num_r_ports)) self.num_r_ports))
@ -54,7 +56,8 @@ class replica_pbitcell(design.design):
self.add_pin("gnd") self.add_pin("gnd")
def add_modules(self): def add_modules(self):
self.prbc = factory.create(module_type="pbitcell",replica_bitcell=True) self.prbc = factory.create(module_type="pbitcell",
replica_bitcell=True)
self.add_mod(self.prbc) self.add_mod(self.prbc)
self.height = self.prbc.height self.height = self.prbc.height
@ -75,7 +78,7 @@ class replica_pbitcell(design.design):
self.connect_inst(temp) self.connect_inst(temp)
def place_pbitcell(self): def place_pbitcell(self):
self.prbc_inst.place(offset=vector(0,0)) self.prbc_inst.place(offset=vector(0, 0))
def route_rbc_connections(self): def route_rbc_connections(self):
for port in range(self.total_ports): for port in range(self.total_ports):

View File

@ -6,39 +6,22 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import utils
from tech import GDS, layer
from tech import cell_properties as props from tech import cell_properties as props
import bitcell_base import bitcell_base
class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base):
""" """
A single bit cell which is forced to store a 0. Row end cap cell.
This module implements the single memory cell used in the design. It """
is a hand-made cell, so the layout and netlist should be available in
the technology library. """
pin_names = [props.bitcell.cell_1rw1r.pin.wl0, pin_names = [props.bitcell.cell_1rw1r.pin.wl0,
props.bitcell.cell_1rw1r.pin.wl1, props.bitcell.cell_1rw1r.pin.wl1,
props.bitcell.cell_1rw1r.pin.gnd] props.bitcell.cell_1rw1r.pin.gnd]
type_list = ["INPUT", "INPUT", "GROUND"] type_list = ["INPUT", "INPUT", "GROUND"]
(width, height) = utils.get_libcell_size("row_cap_cell_1rw_1r", def __init__(self, name="row_cap_cell_1rw_1r"):
GDS["unit"], bitcell_base.bitcell_base.__init__(self, name)
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names,
"row_cap_cell_1rw_1r",
GDS["unit"])
def __init__(self, name=""):
# Ignore the name argument
bitcell_base.bitcell_base.__init__(self, "row_cap_cell_1rw_1r")
debug.info(2, "Create row_cap bitcell 1rw+1r object") debug.info(2, "Create row_cap bitcell 1rw+1r object")
self.width = row_cap_bitcell_1rw_1r.width
self.height = row_cap_bitcell_1rw_1r.height
self.pin_map = row_cap_bitcell_1rw_1r.pin_map
self.add_pin_types(self.type_list)
self.no_instances = True self.no_instances = True

View File

@ -306,7 +306,8 @@ class delay(simulation):
self.create_test_cycles() self.create_test_cycles()
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.delay_stim_sp = "delay_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.delay_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period, self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period,
self.load, self.load,
@ -350,7 +351,8 @@ class delay(simulation):
self.check_arguments() self.check_arguments()
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.power_stim_sp = "power_stim.sp"
temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.power_stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period)) self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)
@ -616,7 +618,7 @@ class delay(simulation):
self.write_delay_stimulus() self.write_delay_stimulus()
self.stim.run_sim() self.stim.run_sim(self.delay_stim_sp)
return self.check_measurements() return self.check_measurements()
@ -772,7 +774,7 @@ class delay(simulation):
debug.info(1, "Performing leakage power simulations.") debug.info(1, "Performing leakage power simulations.")
self.write_power_stimulus(trim=False) self.write_power_stimulus(trim=False)
self.stim.run_sim() self.stim.run_sim(self.power_stim_sp)
leakage_power=parse_spice_list("timing", "leakage_power") leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(leakage_power!="Failed", "Could not measure leakage power.") debug.check(leakage_power!="Failed", "Could not measure leakage power.")
debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3)) debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3))
@ -780,7 +782,7 @@ class delay(simulation):
# sys.exit(1) # sys.exit(1)
self.write_power_stimulus(trim=True) self.write_power_stimulus(trim=True)
self.stim.run_sim() self.stim.run_sim(self.power_stim_sp)
trim_leakage_power=parse_spice_list("timing", "leakage_power") trim_leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.") debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.")
debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3)) debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3))

View File

@ -21,13 +21,24 @@ class functional(simulation):
for successful SRAM operation. for successful SRAM operation.
""" """
def __init__(self, sram, spfile, corner, cycles=15): def __init__(self, sram, spfile, corner=None, cycles=15, period=None, output_path=None):
super().__init__(sram, spfile, corner) super().__init__(sram, spfile, corner)
# Seed the characterizer with a constant seed for unit tests # Seed the characterizer with a constant seed for unit tests
if OPTS.is_unit_test: if OPTS.is_unit_test:
random.seed(12345) random.seed(12345)
if not corner:
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
if period:
self.period = period
if not output_path:
self.output_path = OPTS.openram_temp
else:
self.output_path = output_path
if self.write_size: if self.write_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
@ -58,15 +69,14 @@ class functional(simulation):
self.read_check = [] self.read_check = []
self.read_results = [] self.read_results = []
def run(self, feasible_period=None):
if feasible_period: # period defaults to tech.py feasible period otherwise.
self.period = feasible_period
# Generate a random sequence of reads and writes # Generate a random sequence of reads and writes
self.create_random_memory_sequence() self.create_random_memory_sequence()
# Run SPICE simulation # Write SPICE simulation
self.write_functional_stimulus() self.write_functional_stimulus()
self.stim.run_sim()
def run(self):
self.stim.run_sim(self.stim_sp)
# read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error. # read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error.
(success, error) = self.read_stim_results() (success, error) = self.read_stim_results()
@ -330,7 +340,8 @@ class functional(simulation):
def write_functional_stimulus(self): def write_functional_stimulus(self):
""" Writes SPICE stimulus. """ """ Writes SPICE stimulus. """
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.stim_sp = "functional_stim.sp"
temp_stim = "{0}/{1}".format(self.output_path, self.stim_sp)
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period)) self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)

View File

@ -27,23 +27,22 @@ class setup_hold():
self.model_location = OPTS.openram_tech + "sp_lib/dff.sp" self.model_location = OPTS.openram_tech + "sp_lib/dff.sp"
self.period = tech.spice["feasible_period"] self.period = tech.spice["feasible_period"]
debug.info(2,"Feasible period from technology file: {0} ".format(self.period)) debug.info(2, "Feasible period from technology file: {0} ".format(self.period))
self.set_corner(corner) self.set_corner(corner)
def set_corner(self, corner):
def set_corner(self,corner):
""" Set the corner values """ """ Set the corner values """
self.corner = corner self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner (self.process, self.vdd_voltage, self.temperature) = corner
self.gnd_voltage = 0 self.gnd_voltage = 0
def write_stimulus(self, mode, target_time, correct_value): def write_stimulus(self, mode, target_time, correct_value):
"""Creates a stimulus file for SRAM setup/hold time calculation""" """Creates a stimulus file for SRAM setup/hold time calculation"""
# creates and opens the stimulus file for writing # creates and opens the stimulus file for writing
temp_stim = OPTS.openram_temp + "stim.sp" self.stim_sp = "sh_stim.sp"
temp_stim = OPTS.openram_temp + self.stim_sp
self.sf = open(temp_stim, "w") self.sf = open(temp_stim, "w")
self.stim = stimuli(self.sf, self.corner) self.stim = stimuli(self.sf, self.corner)
@ -63,8 +62,7 @@ class setup_hold():
self.write_measures(mode=mode, self.write_measures(mode=mode,
correct_value=correct_value) correct_value=correct_value)
self.stim.write_control(4 * self.period)
self.stim.write_control(4*self.period)
self.sf.close() self.sf.close()
@ -79,7 +77,6 @@ class setup_hold():
self.sf.write("\n* Global Power Supplies\n") self.sf.write("\n* Global Power Supplies\n")
self.stim.write_supply() self.stim.write_supply()
def write_data(self, mode, target_time, correct_value): def write_data(self, mode, target_time, correct_value):
"""Create the data signals for setup/hold analysis. First period is to """Create the data signals for setup/hold analysis. First period is to
initialize it to the opposite polarity. Second period is used for initialize it to the opposite polarity. Second period is used for
@ -113,14 +110,12 @@ class setup_hold():
# without using .IC on an internal node. # without using .IC on an internal node.
# Return input to value after one period. # Return input to value after one period.
# The second pulse is the characterization one at 2*period # The second pulse is the characterization one at 2*period
clk_times=[0, 0.1*self.period,self.period,2*self.period], clk_times=[0, 0.1 * self.period, self.period, 2 * self.period],
data_values=[0, 1, 0, 1], data_values=[0, 1, 0, 1],
period=2*self.period, period=2 * self.period,
slew=self.constrained_input_slew, slew=self.constrained_input_slew,
setup=0) setup=0)
def write_measures(self, mode, correct_value): def write_measures(self, mode, correct_value):
""" Measure statements for setup/hold with right phases. """ """ Measure statements for setup/hold with right phases. """
@ -139,7 +134,6 @@ class setup_hold():
else: else:
din_rise_or_fall = "RISE" din_rise_or_fall = "RISE"
self.sf.write("\n* Measure statements for pass/fail verification\n") self.sf.write("\n* Measure statements for pass/fail verification\n")
trig_name = "clk" trig_name = "clk"
targ_name = "dout" targ_name = "dout"
@ -152,8 +146,8 @@ class setup_hold():
targ_val=targ_val, targ_val=targ_val,
trig_dir="RISE", trig_dir="RISE",
targ_dir=dout_rise_or_fall, targ_dir=dout_rise_or_fall,
trig_td=1.9*self.period, trig_td=1.9 * self.period,
targ_td=1.9*self.period) targ_td=1.9 * self.period)
targ_name = "data" targ_name = "data"
# Start triggers right after initialize value is returned to normal # Start triggers right after initialize value is returned to normal
@ -165,11 +159,8 @@ class setup_hold():
targ_val=targ_val, targ_val=targ_val,
trig_dir="RISE", trig_dir="RISE",
targ_dir=din_rise_or_fall, targ_dir=din_rise_or_fall,
trig_td=1.2*self.period, trig_td=1.2 * self.period,
targ_td=1.2*self.period) targ_td=1.2 * self.period)
def bidir_search(self, correct_value, mode): def bidir_search(self, correct_value, mode):
""" This will perform a bidirectional search for either setup or hold times. """ This will perform a bidirectional search for either setup or hold times.
@ -182,23 +173,26 @@ class setup_hold():
# this time. They are also unbalanced so that the average won't be right on the clock edge in the # this time. They are also unbalanced so that the average won't be right on the clock edge in the
# first iteration. # first iteration.
if mode == "SETUP": if mode == "SETUP":
feasible_bound = 1.25*self.period feasible_bound = 1.25 * self.period
infeasible_bound = 2.5*self.period infeasible_bound = 2.5 * self.period
else: else:
infeasible_bound = 1.5*self.period infeasible_bound = 1.5 * self.period
feasible_bound = 2.75*self.period feasible_bound = 2.75 * self.period
# Initial check if reference feasible bound time passes for correct_value, if not, we can't start the search! # Initial check if reference feasible bound time passes for correct_value, if not, we can't start the search!
self.write_stimulus(mode=mode, self.write_stimulus(mode=mode,
target_time=feasible_bound, target_time=feasible_bound,
correct_value=correct_value) correct_value=correct_value)
self.stim.run_sim() self.stim.run_sim(self.stim_sp)
ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time)) debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time))
if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float: if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float:
debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound,ideal_clk_to_q,setuphold_time),2) debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound,
ideal_clk_to_q,
setuphold_time),
2)
if mode == "SETUP": # SETUP is clk-din, not din-clk if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9 setuphold_time *= -1e9
@ -206,57 +200,53 @@ class setup_hold():
setuphold_time *= 1e9 setuphold_time *= 1e9
passing_setuphold_time = setuphold_time passing_setuphold_time = setuphold_time
debug.info(2,"Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode,
setuphold_time, setuphold_time,
feasible_bound, feasible_bound,
2*self.period)) 2 * self.period))
#raw_input("Press Enter to continue...") #raw_input("Press Enter to continue...")
while True: while True:
target_time = (feasible_bound + infeasible_bound)/2 target_time = (feasible_bound + infeasible_bound) / 2
self.write_stimulus(mode=mode, self.write_stimulus(mode=mode,
target_time=target_time, target_time=target_time,
correct_value=correct_value) correct_value=correct_value)
debug.info(2,"{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode, debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode,
correct_value, correct_value,
target_time, target_time,
infeasible_bound, infeasible_bound,
feasible_bound)) feasible_bound))
self.stim.run_sim(self.stim_sp)
self.stim.run_sim()
clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time"))
if type(clk_to_q)==float and (clk_to_q<1.1*ideal_clk_to_q) and type(setuphold_time)==float: if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q) and type(setuphold_time)==float:
if mode == "SETUP": # SETUP is clk-din, not din-clk if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9 setuphold_time *= -1e9
else: else:
setuphold_time *= 1e9 setuphold_time *= 1e9
debug.info(2,"PASS Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q,setuphold_time)) debug.info(2, "PASS Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time))
passing_setuphold_time = setuphold_time passing_setuphold_time = setuphold_time
feasible_bound = target_time feasible_bound = target_time
else: else:
debug.info(2,"FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q,setuphold_time)) debug.info(2, "FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time))
infeasible_bound = target_time infeasible_bound = target_time
#raw_input("Press Enter to continue...")
if relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001): if relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001):
debug.info(3,"CONVERGE {0} vs {1}".format(feasible_bound,infeasible_bound)) debug.info(3, "CONVERGE {0} vs {1}".format(feasible_bound, infeasible_bound))
break break
debug.info(2,"Converged on {0} time {1}.".format(mode,passing_setuphold_time)) debug.info(2, "Converged on {0} time {1}.".format(mode, passing_setuphold_time))
return passing_setuphold_time return passing_setuphold_time
def setup_LH_time(self): def setup_LH_time(self):
"""Calculates the setup time for low-to-high transition for a DFF """Calculates the setup time for low-to-high transition for a DFF
""" """
return self.bidir_search(1, "SETUP") return self.bidir_search(1, "SETUP")
def setup_HL_time(self): def setup_HL_time(self):
"""Calculates the setup time for high-to-low transition for a DFF """Calculates the setup time for high-to-low transition for a DFF
""" """
@ -272,7 +262,6 @@ class setup_hold():
""" """
return self.bidir_search(0, "HOLD") return self.bidir_search(0, "HOLD")
def analyze(self, related_slews, constrained_slews): def analyze(self, related_slews, constrained_slews):
"""main function to calculate both setup and hold time for the """main function to calculate both setup and hold time for the
DFF and returns a dictionary that contains 4 lists for both DFF and returns a dictionary that contains 4 lists for both
@ -301,10 +290,10 @@ class setup_hold():
# } # }
# return times # return times
for self.related_input_slew in related_slews: for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews: for self.constrained_input_slew in constrained_slews:
debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,self.constrained_input_slew)) debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,
self.constrained_input_slew))
LH_setup_time = self.setup_LH_time() LH_setup_time = self.setup_LH_time()
debug.info(1, " Setup Time for low_to_high transition: {0}".format(LH_setup_time)) debug.info(1, " Setup Time for low_to_high transition: {0}".format(LH_setup_time))
HL_setup_time = self.setup_HL_time() HL_setup_time = self.setup_HL_time()
@ -325,7 +314,7 @@ class setup_hold():
} }
return times return times
def analytical_setuphold(self,related_slews, constrained_slews): def analytical_setuphold(self, related_slews, constrained_slews):
""" Just return the fixed setup/hold times from the technology. """ Just return the fixed setup/hold times from the technology.
""" """
LH_setup = [] LH_setup = []
@ -336,10 +325,10 @@ class setup_hold():
for self.related_input_slew in related_slews: for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews: for self.constrained_input_slew in constrained_slews:
# convert from ps to ns # convert from ps to ns
LH_setup.append(tech.spice["dff_setup"]/1e3) LH_setup.append(tech.spice["dff_setup"] / 1e3)
HL_setup.append(tech.spice["dff_setup"]/1e3) HL_setup.append(tech.spice["dff_setup"] / 1e3)
LH_hold.append(tech.spice["dff_hold"]/1e3) LH_hold.append(tech.spice["dff_hold"] / 1e3)
HL_hold.append(tech.spice["dff_hold"]/1e3) HL_hold.append(tech.spice["dff_hold"] / 1e3)
times = {"setup_times_LH": LH_setup, times = {"setup_times_LH": LH_setup,
"setup_times_HL": HL_setup, "setup_times_HL": HL_setup,

View File

@ -33,10 +33,21 @@ class stimuli():
self.sf = stim_file self.sf = stim_file
(self.process, self.voltage, self.temperature) = corner (self.process, self.voltage, self.temperature) = corner
found = False
self.device_libraries = []
self.device_models = []
try: try:
self.device_libraries = tech.spice["fet_libraries"][self.process] self.device_libraries += tech.spice["fet_libraries"][self.process]
except: found = True
self.device_models = tech.spice["fet_models"][self.process] except KeyError:
pass
try:
self.device_models += tech.spice["fet_models"][self.process]
found = True
except KeyError:
pass
if not found:
debug.error("Must define either fet_libraries or fet_models.", -1)
def inst_model(self, pins, model_name): def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """ """ Function to instantiate a generic model with a set of pins """
@ -249,7 +260,7 @@ class stimuli():
# create plots for all signals # create plots for all signals
self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
if OPTS.debug_level>0: if OPTS.verbose_level>0:
if OPTS.spice_name in ["hspice", "xa"]: if OPTS.spice_name in ["hspice", "xa"]:
self.sf.write(".probe V(*)\n") self.sf.write(".probe V(*)\n")
else: else:
@ -265,21 +276,16 @@ class stimuli():
"""Writes include statements, inputs are lists of model files""" """Writes include statements, inputs are lists of model files"""
self.sf.write("* {} process corner\n".format(self.process)) self.sf.write("* {} process corner\n".format(self.process))
if OPTS.tech_name == "sky130": for item in self.device_libraries:
for item in self.device_libraries: if os.path.isfile(item[0]):
if os.path.isfile(item[0]): self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1]))
self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1])) else:
else: debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]))
debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]))
includes = [circuit] includes = self.device_models + [circuit]
else:
includes = self.device_models + [circuit]
for item in list(includes): for item in list(includes):
if os.path.isfile(item): self.sf.write(".include \"{0}\"\n".format(item))
self.sf.write(".include \"{0}\"\n".format(item))
else:
debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item))
def write_supply(self): def write_supply(self):
""" Writes supply voltage statements """ """ Writes supply voltage statements """
@ -290,9 +296,9 @@ class stimuli():
self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n") self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n")
self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0)) self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0))
def run_sim(self): def run_sim(self, name):
""" Run hspice in batch mode and output rawfile to parse. """ """ Run hspice in batch mode and output rawfile to parse. """
temp_stim = "{0}stim.sp".format(OPTS.openram_temp) temp_stim = "{0}{1}".format(OPTS.openram_temp, name)
import datetime import datetime
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
debug.check(OPTS.spice_exe != "", "No spice simulator has been found.") debug.check(OPTS.spice_exe != "", "No spice simulator has been found.")

View File

@ -6,7 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import design import design
from tech import GDS, layer, spice, parameter from tech import GDS, layer, spice
from tech import cell_properties as props from tech import cell_properties as props
import utils import utils
@ -23,18 +23,22 @@ class dff(design.design):
pin_names = props.dff.custom_port_list pin_names = props.dff.custom_port_list
type_list = props.dff.custom_type_list type_list = props.dff.custom_type_list
clk_pin = props.dff.clk_pin clk_pin = props.dff.clk_pin
cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("dff",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
def __init__(self, name="dff"): def __init__(self, name="dff"):
design.design.__init__(self, name) super().__init__(name)
self.width = dff.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = dff.height GDS["unit"],
self.pin_map = dff.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
@ -49,7 +53,6 @@ class dff(design.design):
def calculate_effective_capacitance(self, load): def calculate_effective_capacitance(self, load):
"""Computes effective capacitance. Results in fF""" """Computes effective capacitance. Results in fF"""
from tech import parameter
c_load = load c_load = load
c_para = spice["dff_out_cap"]#ff c_para = spice["dff_out_cap"]#ff
transition_prob = 0.5 transition_prob = 0.5

View File

@ -9,7 +9,6 @@ import design
from tech import GDS, layer, spice, parameter from tech import GDS, layer, spice, parameter
import logical_effort import logical_effort
import utils import utils
import debug
class inv_dec(design.design): class inv_dec(design.design):
@ -19,18 +18,22 @@ class inv_dec(design.design):
pin_names = ["A", "Z", "vdd", "gnd"] pin_names = ["A", "Z", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("inv_dec",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "inv_dec", GDS["unit"])
def __init__(self, name="inv_dec", height=None): def __init__(self, name="inv_dec", height=None):
design.design.__init__(self, name) super().__init__(name)
self.width = inv_dec.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = inv_dec.height GDS["unit"],
self.pin_map = inv_dec.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):

View File

@ -18,18 +18,22 @@ class nand2_dec(design.design):
pin_names = ["A", "B", "Z", "vdd", "gnd"] pin_names = ["A", "B", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("nand2_dec",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "nand2_dec", GDS["unit"])
def __init__(self, name="nand2_dec", height=None): def __init__(self, name="nand2_dec", height=None):
design.design.__init__(self, name) super().__init__(name)
self.width = nand2_dec.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = nand2_dec.height GDS["unit"],
self.pin_map = nand2_dec.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
# FIXME: For now... # FIXME: For now...

View File

@ -18,18 +18,22 @@ class nand3_dec(design.design):
pin_names = ["A", "B", "C", "Z", "vdd", "gnd"] pin_names = ["A", "B", "C", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("nand3_dec",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "nand3_dec", GDS["unit"])
def __init__(self, name="nand3_dec", height=None): def __init__(self, name="nand3_dec", height=None):
design.design.__init__(self, name) super().__init__(name)
self.width = nand3_dec.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = nand3_dec.height GDS["unit"],
self.pin_map = nand3_dec.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
# FIXME: For now... # FIXME: For now...

View File

@ -18,18 +18,22 @@ class nand4_dec(design.design):
pin_names = ["A", "B", "C", "D", "Z", "vdd", "gnd"] pin_names = ["A", "B", "C", "D", "Z", "vdd", "gnd"]
type_list = ["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("nand4_dec",
GDS["unit"],
layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "nand4_dec", GDS["unit"])
def __init__(self, name="nand4_dec", height=None): def __init__(self, name="nand4_dec", height=None):
design.design.__init__(self, name) super().__init__(name)
self.width = nand4_dec.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = nand4_dec.height GDS["unit"],
self.pin_map = nand4_dec.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
# FIXME: For now... # FIXME: For now...

View File

@ -10,7 +10,6 @@ import debug
import utils import utils
from tech import GDS, layer, parameter, drc from tech import GDS, layer, parameter, drc
from tech import cell_properties as props from tech import cell_properties as props
from globals import OPTS
import logical_effort import logical_effort
@ -28,12 +27,24 @@ class sense_amp(design.design):
props.sense_amp.pin.vdd, props.sense_amp.pin.vdd,
props.sense_amp.pin.gnd] props.sense_amp.pin.gnd]
type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: cell_size_layer = "boundary"
(width, height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"]) def __init__(self, name="sense_amp"):
else: super().__init__(name)
(width, height) = (0, 0) debug.info(2, "Create sense_amp")
pin_map = []
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
def get_bl_names(self): def get_bl_names(self):
return props.sense_amp.pin.bl return props.sense_amp.pin.bl
@ -49,15 +60,6 @@ class sense_amp(design.design):
def en_name(self): def en_name(self):
return props.sense_amp.pin.en return props.sense_amp.pin.en
def __init__(self, name):
super().__init__(name)
debug.info(2, "Create sense_amp")
self.width = sense_amp.width
self.height = sense_amp.height
self.pin_map = sense_amp.pin_map
self.add_pin_types(self.type_list)
def get_cin(self): def get_cin(self):
# FIXME: This input load will be applied to both the s_en timing and bitline timing. # FIXME: This input load will be applied to both the s_en timing and bitline timing.

View File

@ -8,7 +8,8 @@
import debug import debug
import design import design
import utils import utils
from tech import GDS,layer from tech import GDS, layer
class tri_gate(design.design): class tri_gate(design.design):
""" """
@ -19,8 +20,7 @@ class tri_gate(design.design):
pin_names = ["in", "out", "en", "en_bar", "vdd", "gnd"] pin_names = ["in", "out", "en", "en_bar", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"]) cell_size_layer = "boundary"
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"])
unique_id = 1 unique_id = 1
@ -28,12 +28,20 @@ class tri_gate(design.design):
if name=="": if name=="":
name = "tri{0}".format(tri_gate.unique_id) name = "tri{0}".format(tri_gate.unique_id)
tri_gate.unique_id += 1 tri_gate.unique_id += 1
design.design.__init__(self, name) super().__init__(self, name)
debug.info(2, "Create tri_gate") debug.info(2, "Create tri_gate")
self.width = tri_gate.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = tri_gate.height GDS["unit"],
self.pin_map = tri_gate.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):

View File

@ -8,10 +8,10 @@
import debug import debug
import design import design
import utils import utils
from globals import OPTS from tech import GDS, layer
from tech import GDS,layer
from tech import cell_properties as props from tech import cell_properties as props
class write_driver(design.design): class write_driver(design.design):
""" """
Tristate write driver to be active during write operations only. Tristate write driver to be active during write operations only.
@ -28,20 +28,23 @@ class write_driver(design.design):
props.write_driver.pin.gnd] props.write_driver.pin.gnd]
type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: cell_size_layer = "boundary"
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"])
else:
(width,height) = (0,0)
pin_map = []
def __init__(self, name): def __init__(self, name):
design.design.__init__(self, name) super().__init__(name)
debug.info(2, "Create write_driver") debug.info(2, "Create write_driver")
self.width = write_driver.width (width, height) = utils.get_libcell_size(self.cell_name,
self.height = write_driver.height GDS["unit"],
self.pin_map = write_driver.pin_map layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
self.cell_name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def get_bl_names(self): def get_bl_names(self):

View File

@ -9,6 +9,7 @@ import os
import inspect import inspect
import globals import globals
import sys import sys
import pdb
# the debug levels: # the debug levels:
# 0 = minimum output (default) # 0 = minimum output (default)
@ -26,9 +27,9 @@ def check(check, str):
log("ERROR: file {0}: line {1}: {2}\n".format( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0: if globals.OPTS.debug:
import pdb
pdb.set_trace() pdb.set_trace()
assert 0 assert 0
@ -40,9 +41,9 @@ def error(str, return_value=0):
log("ERROR: file {0}: line {1}: {2}\n".format( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0 and return_value != 0: if globals.OPTS.debug:
import pdb
pdb.set_trace() pdb.set_trace()
assert return_value == 0 assert return_value == 0
@ -96,7 +97,7 @@ log.create_file = True
def info(lev, str): def info(lev, str):
from globals import OPTS from globals import OPTS
if (OPTS.debug_level >= lev): if (OPTS.verbose_level >= lev):
frm = inspect.stack()[1] frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0]) mod = inspect.getmodule(frm[0])
# classname = frm.f_globals['__name__'] # classname = frm.f_globals['__name__']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 256
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 0
num_w_ports = 0
tech_name = "sky130"
nominal_corner_only = True
route_supplies = False
check_lvsdrc = True
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -9,11 +9,11 @@ num_r_ports = 1
num_w_ports = 0 num_w_ports = 0
tech_name = "sky130" tech_name = "sky130"
nominal_corners_only = True nominal_corner_only = True
route_supplies = True route_supplies = False
check_lvsdrc = True check_lvsdrc = True
perimeter_pins = True perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 512
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 0
num_w_ports = 0
tech_name = "sky130"
nominal_corner_only = True
route_supplies = False
check_lvsdrc = True
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -9,11 +9,11 @@ num_r_ports = 1
num_w_ports = 0 num_w_ports = 0
tech_name = "sky130" tech_name = "sky130"
nominal_corners_only = True nominal_corner_only = True
route_supplies = True route_supplies = False
check_lvsdrc = True check_lvsdrc = True
perimeter_pins = True perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,

View File

@ -0,0 +1,26 @@
word_size = 32
num_words = 1024
write_size = 8
local_array_size = 16
num_rw_ports = 1
num_r_ports = 0
num_w_ports = 0
tech_name = "sky130"
nominal_corner_only = True
route_supplies = False
check_lvsdrc = True
perimeter_pins = False
#netlist_only = True
#analytical_delay = False
output_path = "macros/sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)
output_name = "sram_1rw_{0}_{1}_{2}_{3}".format(word_size,
num_words,
write_size,
tech_name)

View File

@ -9,11 +9,11 @@ num_r_ports = 1
num_w_ports = 0 num_w_ports = 0
tech_name = "sky130" tech_name = "sky130"
nominal_corners_only = True nominal_corner_only = True
route_supplies = True route_supplies = False
check_lvsdrc = True check_lvsdrc = True
perimeter_pins = True perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False
output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,7 +63,7 @@ def parse_args():
optparse.make_option("-v", optparse.make_option("-v",
"--verbose", "--verbose",
action="count", action="count",
dest="debug_level", dest="verbose_level",
help="Increase the verbosity level"), help="Increase the verbosity level"),
optparse.make_option("-t", optparse.make_option("-t",
"--tech", "--tech",
@ -83,11 +83,16 @@ def parse_args():
action="store_false", action="store_false",
dest="analytical_delay", dest="analytical_delay",
help="Perform characterization to calculate delays (default is analytical models)"), help="Perform characterization to calculate delays (default is analytical models)"),
optparse.make_option("-k",
"--keeptemp",
action="store_true",
dest="keep_temp",
help="Keep the contents of the temp directory after a successful run"),
optparse.make_option("-d", optparse.make_option("-d",
"--dontpurge", "--debug",
action="store_false", action="store_true",
dest="purge_temp", dest="debug",
help="Don't purge the contents of the temp directory after a successful run") help="Run in debug mode to drop to pdb on failure")
# -h --help is implicit. # -h --help is implicit.
} }
@ -143,7 +148,7 @@ def check_versions():
major_required = 3 major_required = 3
minor_required = 5 minor_required = 5
if not (major_python_version == major_required and minor_python_version >= minor_required): if not (major_python_version == major_required and minor_python_version >= minor_required):
debug.error("Python {0}.{1} or greater is required.".format(major_required,minor_required),-1) debug.error("Python {0}.{1} or greater is required.".format(major_required, minor_required), -1)
# FIXME: Check versions of other tools here?? # FIXME: Check versions of other tools here??
# or, this could be done in each module (e.g. verify, characterizer, etc.) # or, this could be done in each module (e.g. verify, characterizer, etc.)
@ -152,7 +157,7 @@ def check_versions():
try: try:
import coverage import coverage
OPTS.coverage = 1 OPTS.coverage = 1
except: except ModuleNotFoundError:
OPTS.coverage = 0 OPTS.coverage = 0
@ -189,6 +194,9 @@ def init_openram(config_file, is_unit_test=True):
OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy()
return return
# Setup correct bitcell names
setup_bitcell()
# Import these to find the executables for checkpointing # Import these to find the executables for checkpointing
import characterizer import characterizer
import verify import verify
@ -202,17 +210,12 @@ def setup_bitcell():
""" """
Determine the correct custom or parameterized bitcell for the design. Determine the correct custom or parameterized bitcell for the design.
""" """
global OPTS
# If we have non-1rw ports, # If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually, # and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use # figure out the right bitcell to use
if (OPTS.bitcell == "bitcell"): if OPTS.bitcell == "bitcell":
if (OPTS.num_rw_ports == 1 and OPTS.num_w_ports == 0 and OPTS.num_r_ports == 0): if (OPTS.num_rw_ports == 1 and OPTS.num_w_ports == 0 and OPTS.num_r_ports == 0):
OPTS.bitcell = "bitcell" OPTS.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell"
OPTS.dummy_bitcell = "dummy_bitcell"
else: else:
ports = "" ports = ""
if OPTS.num_rw_ports > 0: if OPTS.num_rw_ports > 0:
@ -226,6 +229,13 @@ def setup_bitcell():
OPTS.bitcell_suffix = "_" + ports OPTS.bitcell_suffix = "_" + ports
OPTS.bitcell = "bitcell" + OPTS.bitcell_suffix OPTS.bitcell = "bitcell" + OPTS.bitcell_suffix
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
elif OPTS.bitcell == "pbitcell":
OPTS.bitcell = "pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
# See if bitcell exists # See if bitcell exists
try: try:
__import__(OPTS.bitcell) __import__(OPTS.bitcell)
@ -234,6 +244,8 @@ def setup_bitcell():
# or its custom replica bitcell # or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode) # Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.") debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1, "Using bitcell: {}".format(OPTS.bitcell)) debug.info(1, "Using bitcell: {}".format(OPTS.bitcell))
@ -250,8 +262,8 @@ def get_tool(tool_type, preferences, default_name=None):
if default_name: if default_name:
exe_name = find_exe(default_name) exe_name = find_exe(default_name)
if exe_name == None: if exe_name == None:
debug.error("{0} not found. Cannot find {1} tool.".format(default_name, debug.error("{0} not found. Cannot find {1} tool.".format(default_name, tool_type)
tool_type), + "Disable DRC/LVS with check_lvsdrc=False to ignore.",
2) 2)
else: else:
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name)) debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
@ -264,8 +276,7 @@ def get_tool(tool_type, preferences, default_name=None):
return(name, exe_name) return(name, exe_name)
else: else:
debug.info(1, debug.info(1,
"Could not find {0}, trying next {1} tool.".format(name, "Could not find {0}, trying next {1} tool.".format(name, tool_type))
tool_type))
else: else:
return(None, "") return(None, "")
@ -303,7 +314,7 @@ def read_config(config_file, is_unit_test=True):
try: try:
config = importlib.import_module(module_name) config = importlib.import_module(module_name)
except: except:
debug.error("Unable to read configuration file: {0}".format(config_file),2) debug.error("Unable to read configuration file: {0}".format(config_file), 2)
OPTS.overridden = {} OPTS.overridden = {}
for k, v in config.__dict__.items(): for k, v in config.__dict__.items():
@ -360,7 +371,7 @@ def cleanup_paths():
We should clean up the temp directory after execution. We should clean up the temp directory after execution.
""" """
global OPTS global OPTS
if not OPTS.purge_temp: if OPTS.keep_temp:
debug.info(0, debug.info(0,
"Preserving temp directory: {}".format(OPTS.openram_temp)) "Preserving temp directory: {}".format(OPTS.openram_temp))
return return
@ -458,7 +469,7 @@ def set_default_corner():
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
OPTS.process_corners = ["TT"] OPTS.process_corners = ["TT"]
else: else:
OPTS.process_corners = tech.spice["fet_models"].keys() OPTS.process_corners = list(tech.spice["fet_models"].keys())
if (OPTS.supply_voltages == ""): if (OPTS.supply_voltages == ""):
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
@ -528,12 +539,12 @@ def print_time(name, now_time, last_time=None, indentation=2):
global OPTS global OPTS
# Don't print during testing # Don't print during testing
if not OPTS.is_unit_test or OPTS.debug_level > 0: if not OPTS.is_unit_test or OPTS.verbose_level > 0:
if last_time: if last_time:
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" time = str(round((now_time - last_time).total_seconds(), 1)) + " seconds"
else: else:
time = now_time.strftime('%m/%d/%Y %H:%M:%S') time = now_time.strftime('%m/%d/%Y %H:%M:%S')
debug.print_raw("{0} {1}: {2}".format("*"*indentation, name, time)) debug.print_raw("{0} {1}: {2}".format("*" * indentation, name, time))
def report_status(): def report_status():
@ -600,4 +611,4 @@ def report_status():
if OPTS.trim_netlist: if OPTS.trim_netlist:
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).") debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
debug.print_raw("Only characterizing nominal corner.") debug.print_raw("Only generating nominal corner timing.")

View File

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

View File

@ -52,7 +52,7 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell) self.add_mod(self.cell)
def create_instances(self): def create_instances(self):

View File

@ -9,6 +9,7 @@ import debug
import design import design
from tech import cell_properties from tech import cell_properties
from sram_factory import factory from sram_factory import factory
from globals import OPTS
class bitcell_base_array(design.design): class bitcell_base_array(design.design):
@ -24,7 +25,7 @@ class bitcell_base_array(design.design):
self.column_offset = column_offset self.column_offset = column_offset
# Bitcell for port names only # Bitcell for port names only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.wordline_names = [[] for port in self.all_ports] self.wordline_names = [[] for port in self.all_ports]
self.all_wordline_names = [] self.all_wordline_names = []

View File

@ -51,7 +51,7 @@ class col_cap_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

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

View File

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

View File

@ -1,271 +0,0 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import design
import debug
from tech import drc
from sram_factory import factory
from vector import vector
from globals import OPTS
class custom_cell(design.design):
"""
Array of tristate drivers to write to the bitlines through the column mux.
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, name, pins, mod):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
self.add_comment("word_size {0}".format(word_size))
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.column_offset = column_offset
self.words_per_row = int(columns / word_size)
if not num_spare_cols:
self.num_spare_cols = 0
else:
self.num_spare_cols = num_spare_cols
if self.write_size:
self.num_wmasks = int(self.word_size / self.write_size)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def get_bl_name(self):
bl_name = "bl"
return bl_name
def get_br_name(self):
br_name = "br"
return br_name
@property
def data_name(self):
return "data"
@property
def en_name(self):
return "en"
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_write_array()
def create_layout(self):
if self.bitcell.width > self.driver.width:
self.width = (self.columns + self.num_spare_cols) * self.bitcell.width
self.width_regular_cols = self.columns * self.bitcell.width
self.single_col_width = self.bitcell.width
else:
self.width = (self.columns + self.num_spare_cols) * self.driver.width
self.width_regular_cols = self.columns * self.driver.width
self.single_col_width = self.driver.width
self.height = self.driver.height
self.place_write_array()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
for i in range(self.word_size + self.num_spare_cols):
self.add_pin(self.data_name + "_{0}".format(i), "INPUT")
for i in range(self.word_size + self.num_spare_cols):
self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT")
self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT")
if self.write_size:
for i in range(self.num_wmasks + self.num_spare_cols):
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
elif self.num_spare_cols and not self.write_size:
for i in range(self.num_spare_cols + 1):
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
else:
self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.driver = factory.create(module_type="write_driver")
self.add_mod(self.driver)
# This is just used for measurements,
# so don't add the module
self.bitcell = factory.create(module_type="bitcell")
def create_write_array(self):
self.driver_insts = {}
w = 0
windex=0
for i in range(0, self.columns, self.words_per_row):
name = "write_driver{}".format(i)
index = int(i / self.words_per_row)
self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver)
if self.write_size:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(windex), "vdd", "gnd"])
w+=1
# when w equals write size, the next en pin can be connected since we are now at the next wmask bit
if w == self.write_size:
w = 0
windex+=1
elif self.num_spare_cols and not self.write_size:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(0), "vdd", "gnd"])
else:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name, "vdd", "gnd"])
for i in range(self.num_spare_cols):
index = self.word_size + i
if self.write_size:
offset = self.num_wmasks
else:
offset = 1
name = "write_driver{}".format(self.columns + i)
self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver)
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(i + offset), "vdd", "gnd"])
def place_write_array(self):
from tech import cell_properties
if self.bitcell.width > self.driver.width:
self.driver_spacing = self.bitcell.width
else:
self.driver_spacing = self.driver.width
for i in range(0, self.columns, self.words_per_row):
index = int(i / self.words_per_row)
xoffset = i * self.driver_spacing
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
# place spare write drivers (if spare columns are specified)
for i in range(self.num_spare_cols):
index = self.word_size + i
xoffset = (self.columns + i) * self.driver_spacing
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
def add_layout_pins(self):
for i in range(self.word_size + self.num_spare_cols):
inst = self.driver_insts[i]
din_pin = inst.get_pin(inst.mod.din_name)
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer=din_pin.layer,
offset=din_pin.ll(),
width=din_pin.width(),
height=din_pin.height())
bl_pin = inst.get_pin(inst.mod.get_bl_names())
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer=bl_pin.layer,
offset=bl_pin.ll(),
width=bl_pin.width(),
height=bl_pin.height())
br_pin = inst.get_pin(inst.mod.get_br_names())
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer=br_pin.layer,
offset=br_pin.ll(),
width=br_pin.width(),
height=br_pin.height())
for n in ["vdd", "gnd"]:
pin_list = self.driver_insts[i].get_pins(n)
for pin in pin_list:
self.add_power_pin(name=n,
loc=pin.center(),
directions=("V", "V"),
start_layer=pin.layer)
if self.write_size:
for bit in range(self.num_wmasks):
inst = self.driver_insts[bit * self.write_size]
en_pin = inst.get_pin(inst.mod.en_name)
# Determine width of wmask modified en_pin with/without col mux
wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing)
if (self.words_per_row == 1):
en_gap = self.driver_spacing - en_pin.width()
else:
en_gap = self.driver_spacing
self.add_layout_pin(text=self.en_name + "_{0}".format(bit),
layer=en_pin.layer,
offset=en_pin.ll(),
width=wmask_en_len - en_gap,
height=en_pin.height())
for i in range(self.num_spare_cols):
inst = self.driver_insts[self.word_size + i]
en_pin = inst.get_pin(inst.mod.en_name)
self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks),
layer="m1",
offset=en_pin.lr() + vector(-drc("minwidth_m1"),0))
elif self.num_spare_cols and not self.write_size:
# shorten enable rail to accomodate those for spare write drivers
inst = self.driver_insts[0]
en_pin = inst.get_pin(inst.mod.en_name)
self.add_layout_pin(text=self.en_name + "_{0}".format(0),
layer="m1",
offset=en_pin.ll(),
width=self.width_regular_cols - self.words_per_row * en_pin.width())
# individual enables for every spare write driver
for i in range(self.num_spare_cols):
inst = self.driver_insts[self.word_size + i]
en_pin = inst.get_pin(inst.mod.en_name)
self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1),
layer="m1",
offset=en_pin.lr() + vector(-drc("minwidth_m1"),0))
else:
inst = self.driver_insts[0]
self.add_layout_pin(text=self.en_name,
layer="m1",
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
width=self.width)
def get_w_en_cin(self):
"""Get the relative capacitance of all the enable connections in the bank"""
# The enable is connected to a nand2 for every row.
return self.driver.get_w_en_cin() * len(self.driver_insts)

View File

@ -7,7 +7,7 @@
# #
import debug import debug
import design import design
from tech import parameter, layer from tech import layer
from tech import cell_properties as props from tech import cell_properties as props
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -23,7 +23,6 @@ class dff_buf(design.design):
unique_id = 1 unique_id = 1
def __init__(self, inv1_size=2, inv2_size=4, name=""): def __init__(self, inv1_size=2, inv2_size=4, name=""):
if name=="": if name=="":
name = "dff_buf_{0}".format(dff_buf.unique_id) name = "dff_buf_{0}".format(dff_buf.unique_id)
dff_buf.unique_id += 1 dff_buf.unique_id += 1

View File

@ -44,8 +44,8 @@ class dummy_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
def create_instances(self): def create_instances(self):

View File

@ -11,6 +11,7 @@ import math
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props
class hierarchical_decoder(design.design): class hierarchical_decoder(design.design):
@ -26,7 +27,7 @@ class hierarchical_decoder(design.design):
self.pre3x8_inst = [] self.pre3x8_inst = []
self.pre4x16_inst = [] self.pre4x16_inst = []
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
self.cell_height = b.height self.cell_height = b.height
self.num_outputs = num_outputs self.num_outputs = num_outputs
@ -181,24 +182,14 @@ class hierarchical_decoder(design.design):
# Inputs to cells are on input layer # Inputs to cells are on input layer
# Outputs from cells are on output layer # Outputs from cells are on output layer
if OPTS.tech_name == "sky130":
self.bus_layer = "m1" self.bus_layer = layer_props.hierarchical_decoder.bus_layer
self.bus_directions = "nonpref" self.bus_directions = layer_props.hierarchical_decoder.bus_directions
self.bus_pitch = self.m1_pitch self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
self.bus_space = self.m2_space self.bus_space = getattr(self, self.bus_layer + "_space")
self.input_layer = "m2" self.input_layer = layer_props.hierarchical_decoder.input_layer
self.output_layer = "li" self.output_layer = layer_props.hierarchical_decoder.output_layer
self.output_layer_pitch = self.li_pitch self.output_layer_pitch = getattr(self, self.output_layer + "_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
# Two extra pitches between modules on left and right # 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.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. must-connects next level up.
""" """
if OPTS.tech_name == "sky130": if layer_props.hierarchical_decoder.vertical_supply:
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
pins = self.and_inst[0].get_pins(n) pins = self.and_inst[0].get_pins(n)
for pin in pins: for pin in pins:
@ -678,9 +669,9 @@ class hierarchical_decoder(design.design):
mid_point2 = vector(x_offset, y_offset) mid_point2 = vector(x_offset, y_offset)
rail_pos = vector(self.predecode_bus[rail_name].cx(), mid_point2.y) 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]) self.add_path(self.output_layer, [pin_pos, mid_point1, mid_point2, rail_pos])
if OPTS.tech_name == "sky130": if layer_props.hierarchical_decoder.vertical_supply:
above_rail = vector(self.predecode_bus[rail_name].cx(), mid_point2.y + (self.cell_height/2)) 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) self.add_path(self.bus_layer, [rail_pos, above_rail], width=self.li_width + self.m1_enclose_mcon * 2)
# pin_pos = pin.center() # pin_pos = pin.center()
# rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y) # rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y)

View File

@ -11,6 +11,7 @@ import math
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props
class hierarchical_predecode(design.design): class hierarchical_predecode(design.design):
@ -20,7 +21,7 @@ class hierarchical_predecode(design.design):
def __init__(self, name, input_number, height=None): def __init__(self, name, input_number, height=None):
self.number_of_inputs = input_number self.number_of_inputs = input_number
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
if not height: if not height:
self.cell_height = b.height self.cell_height = b.height
@ -83,23 +84,14 @@ class hierarchical_predecode(design.design):
# Inputs to cells are on input layer # Inputs to cells are on input layer
# Outputs from cells are on output layer # Outputs from cells are on output layer
if OPTS.tech_name == "sky130":
self.bus_layer = "m1" self.bus_layer = layer_props.hierarchical_predecode.bus_layer
self.bus_directions = "nonpref" self.bus_directions = layer_props.hierarchical_predecode.bus_directions
self.bus_pitch = self.m1_pitch self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
self.bus_space = 1.5 * self.m1_space self.bus_space = layer_props.hierarchical_predecode.bus_space_factor * getattr(self, self.bus_layer + "_space")
self.input_layer = "m2" self.input_layer = layer_props.hierarchical_predecode.input_layer
self.output_layer = "li" self.output_layer = layer_props.hierarchical_predecode.output_layer
self.output_layer_pitch = self.li_pitch self.output_layer_pitch = getattr(self, self.output_layer + "_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.height = self.number_of_outputs * self.and_mod.height 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, height=via.mod.second_layer_height,
width=via.mod.second_layer_width) width=via.mod.second_layer_width)
if OPTS.tech_name == "sky130": if layer_props.hierarchical_predecode.vertical_supply:
below_rail = vector(self.decode_rails[out_pin].cx(), y_offset - (self.cell_height/2)) 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) 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): def route_and_to_rails(self):
# This 2D array defines the connection mapping # This 2D array defines the connection mapping
@ -319,8 +311,8 @@ class hierarchical_predecode(design.design):
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """ """ 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 # We may ahve vertical power supply rails
if OPTS.tech_name == "sky130" and not self.column_decoder: if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder:
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
# This makes a wire from top to bottom for both inv and and gates # This makes a wire from top to bottom for both inv and and gates
for i in [self.inv_inst, self.and_inst]: for i in [self.inv_inst, self.and_inst]:

View File

@ -64,7 +64,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
# This is just used for names # This is just used for names
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.bitcell_array = factory.create(module_type="replica_bitcell_array", self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.cols, cols=self.cols,

View File

@ -46,7 +46,7 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell) self.add_mod(self.cell)
def create_instances(self): def create_instances(self):

View File

@ -10,6 +10,7 @@ from sram_factory import factory
from vector import vector from vector import vector
from tech import layer from tech import layer
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props
class port_address(design.design): class port_address(design.design):
@ -80,7 +81,7 @@ class port_address(design.design):
self.copy_power_pins(inst, "gnd") self.copy_power_pins(inst, "gnd")
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): 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()) self.add_power_pin("vdd", rbl_vdd_pin.center())
else: else:
self.add_power_pin("vdd", rbl_vdd_pin.lc()) self.add_power_pin("vdd", rbl_vdd_pin.lc())
@ -154,7 +155,7 @@ class port_address(design.design):
# The polarity must be switched if we have a hierarchical wordline # The polarity must be switched if we have a hierarchical wordline
# to compensate for the local array inverters # to compensate for the local array inverters
b = factory.create(module_type="bitcell") b = factory.create(module_type=OPTS.bitcell)
if local_array_size > 0: if local_array_size > 0:
self.rbl_driver = factory.create(module_type="inv_dec", self.rbl_driver = factory.create(module_type="inv_dec",

View File

@ -11,6 +11,7 @@ from sram_factory import factory
from collections import namedtuple from collections import namedtuple
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props
class port_data(design.design): class port_data(design.design):
@ -32,7 +33,7 @@ class port_data(design.design):
self.num_spare_cols = 0 self.num_spare_cols = 0
if not bit_offsets: if not bit_offsets:
bitcell = factory.create(module_type="bitcell") bitcell = factory.create(module_type=OPTS.bitcell)
self.bit_offsets = [] self.bit_offsets = []
for i in range(self.num_cols + self.num_spare_cols): for i in range(self.num_cols + self.num_spare_cols):
self.bit_offsets.append(i * bitcell.width) self.bit_offsets.append(i * bitcell.width)
@ -190,7 +191,7 @@ class port_data(design.design):
# and mirroring happens correctly # and mirroring happens correctly
# Used for names/dimensions only # Used for names/dimensions only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
if self.port == 0: if self.port == 0:
# Append an offset on the left # Append an offset on the left
@ -269,7 +270,7 @@ class port_data(design.design):
# create arrays of bitline and bitline_bar names for read, # create arrays of bitline and bitline_bar names for read,
# write, or all ports # write, or all ports
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.bl_names = self.bitcell.get_all_bl_names() self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.get_all_br_names() self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.get_all_wl_names() self.wl_names = self.bitcell.get_all_wl_names()
@ -580,20 +581,20 @@ class port_data(design.design):
inst1_start_bit=self.num_cols + off, inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size) inst2_start_bit=self.word_size)
# This could be a channel route, but in some techs the bitlines elif layer_props.port_data.channel_route_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:
self.channel_route_bitlines(inst1=inst1, self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ, inst1_bls_template=inst1_bls_templ,
inst2=inst2, inst2=inst2,
num_bits=self.word_size + self.num_spare_cols, num_bits=self.word_size + self.num_spare_cols,
inst1_start_bit=start_bit) 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): 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 """ """ 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 # This could be a channel route, but in some techs the bitlines
# are too close together. # 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, self.connect_bitlines(inst1=inst1, inst2=inst2,
num_bits=self.word_size, num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ, inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit) 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): def route_write_driver_to_sense_amp(self, port):
""" Routing of BL and BR between write driver and sense amp """ """ Routing of BL and BR between write driver and sense amp """

View File

@ -281,7 +281,7 @@ class replica_bitcell_array(bitcell_base_array):
self.supplies = ["vdd", "gnd"] self.supplies = ["vdd", "gnd"]
# Used for names/dimensions only # Used for names/dimensions only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
# Main array # Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array", self.bitcell_array_inst=self.add_inst(name="bitcell_array",

View File

@ -9,6 +9,7 @@ from tech import cell_properties
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props
class replica_column(bitcell_base_array): class replica_column(bitcell_base_array):
@ -41,7 +42,7 @@ class replica_column(bitcell_base_array):
"Replica bit cannot be the dummy row.") "Replica bit cannot be the dummy row.")
debug.check(replica_bit <= self.left_rbl or replica_bit >= self.total_size - self.right_rbl - 1, 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.") "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, 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" "sky130 currently requires rows to be even and to start with X mirroring"
+ " (left_rbl must be odd) for LVS.") + " (left_rbl must be odd) for LVS.")
@ -76,9 +77,9 @@ class replica_column(bitcell_base_array):
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.replica_cell = factory.create(module_type="replica_{}".format(OPTS.bitcell)) self.replica_cell = factory.create(module_type=OPTS.replica_bitcell)
self.add_mod(self.replica_cell) self.add_mod(self.replica_cell)
self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
try: try:
edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy") edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy")
@ -87,7 +88,7 @@ class replica_column(bitcell_base_array):
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell) self.add_mod(self.edge_cell)
# Used for pin names only # Used for pin names only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
self.cell_inst = {} self.cell_inst = {}

View File

@ -43,7 +43,7 @@ class row_cap_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

@ -97,7 +97,7 @@ class sense_amp_array(design.design):
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
def create_sense_amp_array(self): def create_sense_amp_array(self):
self.local_insts = [] self.local_insts = []

View File

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

View File

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

View File

@ -99,7 +99,7 @@ class write_driver_array(design.design):
# This is just used for measurements, # This is just used for measurements,
# so don't add the module # so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
def create_write_array(self): def create_write_array(self):
self.driver_insts = [] self.driver_insts = []

View File

@ -81,7 +81,7 @@ class write_mask_and_array(design.design):
# This ensures the write mask AND array will be directly under the corresponding write driver enable wire. # This ensures the write mask AND array will be directly under the corresponding write driver enable wire.
# This is just used for measurements, so don't add the module # This is just used for measurements, so don't add the module
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
self.driver = factory.create(module_type="write_driver") self.driver = factory.create(module_type="write_driver")
if self.bitcell.width > self.driver.width: if self.bitcell.width > self.driver.width:
self.driver_spacing = self.bitcell.width self.driver_spacing = self.bitcell.width

View File

@ -79,7 +79,10 @@ class options(optparse.Values):
os.getpid()) os.getpid())
# This is the verbosity level to control debug information. 0 is none, 1 # This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc. # is minimal, etc.
debug_level = 0 verbose_level = 0
# Drop to pdb on failure?
debug = False
################### ###################
# Run-time vs accuracy options. # Run-time vs accuracy options.
@ -137,7 +140,8 @@ class options(optparse.Values):
# Route the input/output pins to the perimeter # Route the input/output pins to the perimeter
perimeter_pins = False perimeter_pins = False
purge_temp = True keep_temp = False
# These are the default modules that can be over-riden # These are the default modules that can be over-riden
bitcell_suffix = "" bitcell_suffix = ""

View File

@ -10,6 +10,7 @@ import debug
from tech import drc, layer from tech import drc, layer
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props
from globals import OPTS from globals import OPTS
@ -64,7 +65,7 @@ class column_mux(pgate.pgate):
self.add_pn_wells() self.add_pn_wells()
def add_ptx(self): def add_ptx(self):
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type=OPTS.bitcell)
# Adds nmos_lower,nmos_upper to the module # Adds nmos_lower,nmos_upper to the module
self.ptx_width = self.tx_size * drc("minwidth_tx") self.ptx_width = self.tx_size * drc("minwidth_tx")
@ -124,8 +125,8 @@ class column_mux(pgate.pgate):
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space)) + vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
self.nmos_upper.place(nmos_upper_position) self.nmos_upper.place(nmos_upper_position)
if OPTS.tech_name == "sky130": if cell_props.pgate.add_implants:
self.add_implants() self.extend_implants()
def connect_poly(self): def connect_poly(self):
""" Connect the poly gate of the two pass transistors """ """ Connect the poly gate of the two pass transistors """
@ -198,7 +199,7 @@ class column_mux(pgate.pgate):
self.add_path(self.col_mux_stack[2], self.add_path(self.col_mux_stack[2],
[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) [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. Add top-to-bottom implants for adjacency issues in s8.
""" """

View File

@ -146,4 +146,3 @@ class pand2(pgate.pgate):
offset=pin.center(), offset=pin.center(),
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())

View File

@ -161,4 +161,3 @@ class pand3(pgate.pgate):
slew=nand_delay.slew, slew=nand_delay.slew,
load=load) load=load)
return nand_delay + inv_delay return nand_delay + inv_delay

View File

@ -168,4 +168,3 @@ class pdriver(pgate.pgate):
def get_sizes(self): def get_sizes(self):
""" Return the relative sizes of the buffers """ """ Return the relative sizes of the buffers """
return self.size_list return self.size_list

View File

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

Some files were not shown because too many files have changed in this diff Show More