mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into s8_single_port
This commit is contained in:
commit
d69ca2b1ed
|
|
@ -51,8 +51,8 @@ class contact(hierarchy_design.hierarchy_design):
|
||||||
|
|
||||||
# Non-preferred directions
|
# 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":
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -119,35 +139,48 @@ class cell_properties():
|
||||||
self.names = {}
|
self.names = {}
|
||||||
|
|
||||||
self._bitcell = _bitcell._default()
|
self._bitcell = _bitcell._default()
|
||||||
|
|
||||||
self._dff = _dff(use_custom_ports = False,
|
|
||||||
custom_port_list = ["D", "Q", "clk", "vdd", "gnd"],
|
|
||||||
custom_type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
|
|
||||||
clk_pin= "clk")
|
|
||||||
|
|
||||||
self._dff_buff = _dff_buff(use_custom_ports = False,
|
|
||||||
custom_buff_ports = ["D", "qint", "clk", "vdd", "gnd"],
|
|
||||||
add_body_contacts = False)
|
|
||||||
|
|
||||||
self._dff_buff_array = _dff_buff_array(use_custom_ports = False,
|
self._ptx = _ptx(model_is_subckt=False,
|
||||||
add_body_contacts = False)
|
bin_spice_models=False)
|
||||||
|
|
||||||
|
self._pgate = _pgate(add_implants=False)
|
||||||
|
|
||||||
|
self._dff = _dff(use_custom_ports=False,
|
||||||
|
custom_port_list=["D", "Q", "clk", "vdd", "gnd"],
|
||||||
|
custom_type_list=["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"],
|
||||||
|
clk_pin="clk")
|
||||||
|
|
||||||
|
self._dff_buff = _dff_buff(use_custom_ports=False,
|
||||||
|
custom_buff_ports=["D", "qint", "clk", "vdd", "gnd"],
|
||||||
|
add_body_contacts=False)
|
||||||
|
|
||||||
|
self._dff_buff_array = _dff_buff_array(use_custom_ports=False,
|
||||||
|
add_body_contacts=False)
|
||||||
|
|
||||||
self._write_driver = _cell({'din': 'din',
|
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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2020 Regents of the University of California and The Board
|
||||||
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||||
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class _bank:
|
||||||
|
def __init__(self, stack, pitch):
|
||||||
|
# bank
|
||||||
|
# column address route: stack, pitch
|
||||||
|
# m1_stack, m2_pitch (default)
|
||||||
|
# m2_stack, m3_pitch (sky130)
|
||||||
|
self.stack = stack
|
||||||
|
self.pitch = pitch
|
||||||
|
|
||||||
|
|
||||||
|
class _hierarchical_decoder:
|
||||||
|
def __init__(self,
|
||||||
|
bus_layer,
|
||||||
|
bus_directions,
|
||||||
|
input_layer,
|
||||||
|
output_layer,
|
||||||
|
vertical_supply):
|
||||||
|
# hierarchical_decoder
|
||||||
|
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
|
||||||
|
# m2, pref, m2_pitch, m2_space, m1, m3, m3_pitch
|
||||||
|
# m1, nonpref, m1_pitch, m2_space, m2, li, li_pitch (sky130)
|
||||||
|
#
|
||||||
|
# vertical vdd/gnd
|
||||||
|
# special jogging
|
||||||
|
self.bus_layer = bus_layer
|
||||||
|
self.bus_directions = bus_directions
|
||||||
|
self.input_layer = input_layer
|
||||||
|
self.output_layer = output_layer
|
||||||
|
self.vertical_supply = vertical_supply
|
||||||
|
|
||||||
|
|
||||||
|
class _hierarchical_predecode:
|
||||||
|
def __init__(self,
|
||||||
|
bus_layer,
|
||||||
|
bus_directions,
|
||||||
|
bus_space_factor,
|
||||||
|
input_layer,
|
||||||
|
output_layer,
|
||||||
|
vertical_supply):
|
||||||
|
# hierarchical_predecode
|
||||||
|
# bus_layer, bus_directions, bus_pitch, bus_space, input_layer, output_layer, output_layer_pitch
|
||||||
|
# m2, pref, m2_pitch, m2_space, m1, m1, m1_pitch
|
||||||
|
# m1, nonpref, m1_pitch, 1`.5*m1_space, m2, li, li_pitch (sky130)
|
||||||
|
#
|
||||||
|
# vertical vdd/gnd
|
||||||
|
# special jogging
|
||||||
|
self.bus_layer = bus_layer
|
||||||
|
self.bus_directions = bus_directions
|
||||||
|
self.bus_space_factor = bus_space_factor
|
||||||
|
self.input_layer = input_layer
|
||||||
|
self.output_layer = output_layer
|
||||||
|
self.vertical_supply = vertical_supply
|
||||||
|
|
||||||
|
|
||||||
|
class _column_mux_array:
|
||||||
|
def __init__(self,
|
||||||
|
select_layer,
|
||||||
|
select_pitch,
|
||||||
|
bitline_layer):
|
||||||
|
# column_mux_array
|
||||||
|
# sel_layer, sel_pitch, bitline_layer
|
||||||
|
# m1, m2_pitch, m2
|
||||||
|
# m3, m3_pitch, m1 (sky130)
|
||||||
|
self.select_layer = select_layer
|
||||||
|
self.select_pitch= select_pitch
|
||||||
|
self.bitline_layer = bitline_layer
|
||||||
|
|
||||||
|
|
||||||
|
class _port_address:
|
||||||
|
def __init__(self,
|
||||||
|
supply_offset):
|
||||||
|
# port_adress
|
||||||
|
# special supply offset
|
||||||
|
self.supply_offset = supply_offset
|
||||||
|
|
||||||
|
|
||||||
|
class _port_data:
|
||||||
|
def __init__(self,
|
||||||
|
channel_route_bitlines,
|
||||||
|
enable_layer):
|
||||||
|
# port_data
|
||||||
|
# connect bitlines instead of chanel route
|
||||||
|
|
||||||
|
# sense_amp_array
|
||||||
|
# en_layer
|
||||||
|
# m1
|
||||||
|
# m3 (sky130)
|
||||||
|
|
||||||
|
# precharge_array
|
||||||
|
# en_bar_layer
|
||||||
|
# m1
|
||||||
|
# m3 (sky130)
|
||||||
|
self.channel_route_bitlines = channel_route_bitlines
|
||||||
|
self.enable_layer = enable_layer
|
||||||
|
|
||||||
|
|
||||||
|
class _replica_column:
|
||||||
|
def __init__(self,
|
||||||
|
even_rows):
|
||||||
|
# replica_column
|
||||||
|
# even row check (sky130)
|
||||||
|
self.even_rows = even_rows
|
||||||
|
|
||||||
|
|
||||||
|
class _wordline_driver:
|
||||||
|
def __init__(self,
|
||||||
|
vertical_supply):
|
||||||
|
# wordline_buffer_array
|
||||||
|
# vertical vdd/gnd (sky130)
|
||||||
|
# wordline_driver_array
|
||||||
|
# vertical vdd/gnd (sky130)
|
||||||
|
# wordline_driver
|
||||||
|
# vertical vdd/gnd (sky130)
|
||||||
|
self.vertical_supply = vertical_supply
|
||||||
|
|
||||||
|
|
||||||
|
class layer_properties():
|
||||||
|
"""
|
||||||
|
This contains meta information about the module routing layers. These
|
||||||
|
can be overriden in the tech.py file.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self._bank = _bank(stack="m1_stack",
|
||||||
|
pitch="m2_pitch")
|
||||||
|
|
||||||
|
self._hierarchical_decoder = _hierarchical_decoder(bus_layer="m2",
|
||||||
|
bus_directions="pref",
|
||||||
|
input_layer="m1",
|
||||||
|
output_layer="m3",
|
||||||
|
vertical_supply=False)
|
||||||
|
|
||||||
|
self._hierarchical_predecode = _hierarchical_predecode(bus_layer="m2",
|
||||||
|
bus_directions="pref",
|
||||||
|
bus_space_factor=1,
|
||||||
|
input_layer="m1",
|
||||||
|
output_layer="m1",
|
||||||
|
vertical_supply=False)
|
||||||
|
|
||||||
|
self._column_mux_array = _column_mux_array(select_layer="m1",
|
||||||
|
select_pitch="m2_pitch",
|
||||||
|
bitline_layer="m2")
|
||||||
|
|
||||||
|
self._port_address = _port_address(supply_offset=False)
|
||||||
|
|
||||||
|
self._port_data = _port_data(channel_route_bitlines=True,
|
||||||
|
enable_layer="m1")
|
||||||
|
|
||||||
|
self._replica_column = _replica_column(even_rows=False)
|
||||||
|
|
||||||
|
self._wordline_driver = _wordline_driver(vertical_supply=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bank(self):
|
||||||
|
return self._bank
|
||||||
|
|
||||||
|
@property
|
||||||
|
def column_mux_array(self):
|
||||||
|
return self._column_mux_array
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hierarchical_decoder(self):
|
||||||
|
return self._hierarchical_decoder
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hierarchical_predecode(self):
|
||||||
|
return self._hierarchical_predecode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_address(self):
|
||||||
|
return self._port_address
|
||||||
|
|
||||||
|
@property
|
||||||
|
def port_data(self):
|
||||||
|
return self._port_data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def replica_column(self):
|
||||||
|
return self._replica_column
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wordline_driver(self):
|
||||||
|
return self._wordline_driver
|
||||||
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
from hierarchy_design import hierarchy_design
|
from 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 globals import OPTS
|
from globals import OPTS
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
@ -18,21 +19,110 @@ class design(hierarchy_design):
|
||||||
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):
|
||||||
super().__init__(name)
|
super().__init__(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):
|
||||||
for pin_name in self.pins:
|
for pin_name in self.pins:
|
||||||
pins = self.get_pins(pin_name)
|
pins = self.get_pins(pin_name)
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
print(pin_name, pin)
|
print(pin_name, pin)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_drc_constants(design):
|
||||||
|
"""
|
||||||
|
These are some DRC constants used in many places
|
||||||
|
in the compiler.
|
||||||
|
"""
|
||||||
|
# Make some local rules for convenience
|
||||||
|
from tech import drc
|
||||||
|
for rule in drc.keys():
|
||||||
|
# Single layer width rules
|
||||||
|
match = re.search(r"minwidth_(.*)", rule)
|
||||||
|
if match:
|
||||||
|
if match.group(1) == "active_contact":
|
||||||
|
setattr(design, "contact_width", drc(match.group(0)))
|
||||||
|
else:
|
||||||
|
setattr(design, match.group(1) + "_width", drc(match.group(0)))
|
||||||
|
|
||||||
|
# Single layer area rules
|
||||||
|
match = re.search(r"minarea_(.*)", rule)
|
||||||
|
if match:
|
||||||
|
setattr(design, match.group(0), drc(match.group(0)))
|
||||||
|
|
||||||
|
# Single layer spacing rules
|
||||||
|
match = re.search(r"(.*)_to_(.*)", rule)
|
||||||
|
if match and match.group(1) == match.group(2):
|
||||||
|
setattr(design, match.group(1) + "_space", drc(match.group(0)))
|
||||||
|
elif match and match.group(1) != match.group(2):
|
||||||
|
if match.group(2) == "poly_active":
|
||||||
|
setattr(design, match.group(1) + "_to_contact",
|
||||||
|
drc(match.group(0)))
|
||||||
|
else:
|
||||||
|
setattr(design, match.group(0), drc(match.group(0)))
|
||||||
|
|
||||||
|
match = re.search(r"(.*)_enclose_(.*)", rule)
|
||||||
|
if match:
|
||||||
|
setattr(design, match.group(0), drc(match.group(0)))
|
||||||
|
|
||||||
|
match = re.search(r"(.*)_extend_(.*)", rule)
|
||||||
|
if match:
|
||||||
|
setattr(design, match.group(0), drc(match.group(0)))
|
||||||
|
|
||||||
|
# Create the maximum well extend active that gets used
|
||||||
|
# by cells to extend the wells for interaction with other cells
|
||||||
|
from tech import layer
|
||||||
|
design.well_extend_active = 0
|
||||||
|
if "nwell" in layer:
|
||||||
|
design.well_extend_active = max(design.well_extend_active, design.nwell_extend_active)
|
||||||
|
if "pwell" in layer:
|
||||||
|
design.well_extend_active = max(design.well_extend_active, design.pwell_extend_active)
|
||||||
|
|
||||||
|
# The active offset is due to the well extension
|
||||||
|
if "pwell" in layer:
|
||||||
|
design.pwell_enclose_active = drc("pwell_enclose_active")
|
||||||
|
else:
|
||||||
|
design.pwell_enclose_active = 0
|
||||||
|
if "nwell" in layer:
|
||||||
|
design.nwell_enclose_active = drc("nwell_enclose_active")
|
||||||
|
else:
|
||||||
|
design.nwell_enclose_active = 0
|
||||||
|
# Use the max of either so that the poly gates will align properly
|
||||||
|
design.well_enclose_active = max(design.pwell_enclose_active,
|
||||||
|
design.nwell_enclose_active,
|
||||||
|
design.active_space)
|
||||||
|
|
||||||
def setup_layer_constants(self):
|
# These are for debugging previous manual rules
|
||||||
|
if False:
|
||||||
|
print("poly_width", design.poly_width)
|
||||||
|
print("poly_space", design.poly_space)
|
||||||
|
print("m1_width", design.m1_width)
|
||||||
|
print("m1_space", design.m1_space)
|
||||||
|
print("m2_width", design.m2_width)
|
||||||
|
print("m2_space", design.m2_space)
|
||||||
|
print("m3_width", design.m3_width)
|
||||||
|
print("m3_space", design.m3_space)
|
||||||
|
print("m4_width", design.m4_width)
|
||||||
|
print("m4_space", design.m4_space)
|
||||||
|
print("active_width", design.active_width)
|
||||||
|
print("active_space", design.active_space)
|
||||||
|
print("contact_width", design.contact_width)
|
||||||
|
print("poly_to_active", design.poly_to_active)
|
||||||
|
print("poly_extend_active", design.poly_extend_active)
|
||||||
|
print("poly_to_contact", design.poly_to_contact)
|
||||||
|
print("active_contact_to_gate", design.active_contact_to_gate)
|
||||||
|
print("poly_contact_to_gate", design.poly_contact_to_gate)
|
||||||
|
print("well_enclose_active", design.well_enclose_active)
|
||||||
|
print("implant_enclose_active", design.implant_enclose_active)
|
||||||
|
print("implant_space", design.implant_space)
|
||||||
|
import sys
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_layer_constants(design):
|
||||||
"""
|
"""
|
||||||
These are some layer constants used
|
These are some layer constants used
|
||||||
in many places in the compiler.
|
in many places in the compiler.
|
||||||
|
|
@ -46,7 +136,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 +145,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 +163,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 +186,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,112 +209,24 @@ 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)
|
||||||
pitch = contact_width + layer_space
|
pitch = contact_width + layer_space
|
||||||
|
|
||||||
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):
|
||||||
"""
|
"""
|
||||||
These are contants and lists that aid multiport design.
|
These are contants and lists that aid multiport design.
|
||||||
|
|
@ -266,3 +274,6 @@ class design(hierarchy_design):
|
||||||
total_module_power += inst.mod.analytical_power(corner, load)
|
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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ from tech import drc, GDS
|
||||||
from tech import layer as techlayer
|
from tech import layer as techlayer
|
||||||
from tech import layer_indices
|
from tech import layer_indices
|
||||||
from tech import layer_stacks
|
from tech import layer_stacks
|
||||||
from tech import preferred_directions
|
|
||||||
import os
|
import os
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from vector import vector
|
from vector import vector
|
||||||
|
|
@ -537,10 +536,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
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import utils
|
||||||
from tech import GDS, layer
|
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):
|
||||||
"""
|
"""
|
||||||
|
|
@ -46,8 +46,6 @@ class bitcell(bitcell_base.bitcell_base):
|
||||||
self.add_pin_types(self.type_list)
|
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]
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
word_size = 4
|
||||||
|
num_words = 16
|
||||||
|
write_size = 2
|
||||||
|
|
||||||
|
num_rw_ports = 1
|
||||||
|
num_r_ports = 0
|
||||||
|
num_w_ports = 1
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corner_only = False
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [5.0]
|
||||||
|
temperatures = [25]
|
||||||
|
|
||||||
|
route_supplies = False
|
||||||
|
check_lvsdrc = True
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,
|
||||||
|
num_words,
|
||||||
|
tech_name)
|
||||||
|
|
@ -7,7 +7,7 @@ num_r_ports = 0
|
||||||
num_w_ports = 0
|
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]
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
word_size = 2
|
||||||
|
num_words = 16
|
||||||
|
|
||||||
|
num_rw_ports = 2
|
||||||
|
num_r_ports = 0
|
||||||
|
num_w_ports = 0
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corner_only = False
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [5.0]
|
||||||
|
temperatures = [25]
|
||||||
|
|
||||||
|
route_supplies = False
|
||||||
|
check_lvsdrc = True
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_1w_1r_{0}_{1}_{2}".format(word_size,
|
||||||
|
num_words,
|
||||||
|
tech_name)
|
||||||
|
|
||||||
|
|
@ -2,14 +2,14 @@ word_size = 2
|
||||||
num_words = 16
|
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]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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 ]
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ 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 = True
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ 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 = True
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ 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 = True
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
word_size = 2
|
|
||||||
num_words = 16
|
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
#netlist_only = True
|
|
||||||
route_supplies = True
|
|
||||||
check_lvsdrc = True
|
|
||||||
|
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name)
|
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
word_size = 8
|
|
||||||
num_words = 128
|
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
route_supplies = True
|
|
||||||
check_lvsdrc = True
|
|
||||||
|
|
||||||
netlist_only = True
|
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name)
|
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
word_size = 16
|
|
||||||
num_words = 256
|
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
route_supplies = True
|
|
||||||
check_lvsdrc = True
|
|
||||||
netlist_only = True
|
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name)
|
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
word_size = 32
|
|
||||||
num_words = 128
|
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
route_supplies = True
|
|
||||||
check_lvsdrc = True
|
|
||||||
netlist_only = True
|
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name)
|
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
word_size = 64
|
|
||||||
num_words = 128
|
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
route_supplies = True
|
|
||||||
check_lvsdrc = True
|
|
||||||
|
|
||||||
output_path = "/home/jesse/thesis/outputs/run5"
|
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name)
|
|
||||||
|
|
||||||
drc_name = "magic"
|
|
||||||
lvs_name = "netgen"
|
|
||||||
pex_name = "magic"
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
word_size = 16
|
|
||||||
num_words = 16
|
|
||||||
|
|
||||||
num_rw_ports = 1
|
|
||||||
num_r_ports = 1
|
|
||||||
num_w_ports = 0
|
|
||||||
|
|
||||||
tech_name = "sky130"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
accuracy_requirement = 0.05
|
|
||||||
magic_exe = ("magic", "magic")
|
|
||||||
nominal_corners_only = False
|
|
||||||
process_corners = ["TT"]
|
|
||||||
supply_voltages = [5.0]
|
|
||||||
temperatures = [25]
|
|
||||||
|
|
||||||
netlist_only = False
|
|
||||||
route_supplies = "grid"
|
|
||||||
check_lvsdrc = False
|
|
||||||
|
|
||||||
#replica_bitcell_array = "/home/jesse/openram/technology/sky130/modules/replica_bitcell_array.py"
|
|
||||||
|
|
||||||
output_path = "sram_" + str(accuracy_requirement)
|
|
||||||
output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,
|
|
||||||
num_words,
|
|
||||||
tech_name,
|
|
||||||
accuracy_requirement
|
|
||||||
)
|
|
||||||
write_size=8
|
|
||||||
|
|
@ -9,9 +9,10 @@ import debug
|
||||||
import design
|
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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
@ -162,7 +162,7 @@ class control_logic(design.design):
|
||||||
self.delay_chain=factory.create(module_type="delay_chain",
|
self.delay_chain=factory.create(module_type="delay_chain",
|
||||||
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
||||||
self.add_mod(self.delay_chain)
|
self.add_mod(self.delay_chain)
|
||||||
|
|
||||||
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
|
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
|
||||||
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -181,25 +182,15 @@ 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_directions = "nonpref"
|
|
||||||
self.bus_pitch = self.m1_pitch
|
|
||||||
self.bus_space = self.m2_space
|
|
||||||
self.input_layer = "m2"
|
|
||||||
self.output_layer = "li"
|
|
||||||
self.output_layer_pitch = self.li_pitch
|
|
||||||
else:
|
|
||||||
self.bus_layer = "m2"
|
|
||||||
self.bus_directions = "pref"
|
|
||||||
self.bus_pitch = self.m2_pitch
|
|
||||||
self.bus_space = self.m2_space
|
|
||||||
# These two layers being the same requires a special jog
|
|
||||||
# to ensure to conflicts with the output layers
|
|
||||||
self.input_layer = "m1"
|
|
||||||
self.output_layer = "m3"
|
|
||||||
self.output_layer_pitch = self.m3_pitch
|
|
||||||
|
|
||||||
|
self.bus_layer = layer_props.hierarchical_decoder.bus_layer
|
||||||
|
self.bus_directions = layer_props.hierarchical_decoder.bus_directions
|
||||||
|
self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
|
||||||
|
self.bus_space = getattr(self, self.bus_layer + "_space")
|
||||||
|
self.input_layer = layer_props.hierarchical_decoder.input_layer
|
||||||
|
self.output_layer = layer_props.hierarchical_decoder.output_layer
|
||||||
|
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
|
||||||
|
|
||||||
# Two extra pitches between modules on left and right
|
# 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
|
||||||
self.row_decoder_height = self.and2.height * self.num_outputs
|
self.row_decoder_height = self.and2.height * self.num_outputs
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -83,24 +84,15 @@ 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
|
||||||
|
|
||||||
# x offset for input inverters
|
# x offset for input inverters
|
||||||
|
|
@ -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]:
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -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 """
|
||||||
|
|
|
||||||
|
|
@ -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.")
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +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 globals import OPTS
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class column_mux(pgate.pgate):
|
class column_mux(pgate.pgate):
|
||||||
|
|
@ -124,8 +124,8 @@ class column_mux(pgate.pgate):
|
||||||
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
|
+ 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 +198,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.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from utils import round_to_grid
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from errors import drc_error
|
from errors import drc_error
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class pinv(pgate.pgate):
|
class pinv(pgate.pgate):
|
||||||
|
|
@ -87,7 +88,7 @@ class pinv(pgate.pgate):
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
(self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width)
|
(self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width)
|
||||||
(self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width)
|
(self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width)
|
||||||
return
|
return
|
||||||
|
|
@ -132,7 +133,7 @@ class pinv(pgate.pgate):
|
||||||
|
|
||||||
# Determine the number of mults for each to fit width
|
# Determine the number of mults for each to fit width
|
||||||
# into available space
|
# into available space
|
||||||
if OPTS.tech_name != "sky130":
|
if not cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
|
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from tech import drc, parameter, layer
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class pinv_dec(pinv.pinv):
|
class pinv_dec(pinv.pinv):
|
||||||
|
|
@ -50,7 +51,7 @@ class pinv_dec(pinv.pinv):
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
||||||
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
|
@ -140,10 +141,10 @@ class pinv_dec(pinv.pinv):
|
||||||
nmos_drain_pos = self.nmos_inst.get_pin("D").center()
|
nmos_drain_pos = self.nmos_inst.get_pin("D").center()
|
||||||
self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y)
|
self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y)
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.pgate.add_implants:
|
||||||
self.add_implants()
|
self.extend_implants()
|
||||||
|
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
from globals import OPTS
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import contact
|
import contact
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class pnand2(pgate.pgate):
|
class pnand2(pgate.pgate):
|
||||||
|
|
@ -38,7 +38,7 @@ class pnand2(pgate.pgate):
|
||||||
debug.check(size == 1, "Size 1 pnand2 is only supported now.")
|
debug.check(size == 1, "Size 1 pnand2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
||||||
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
|
@ -212,9 +212,8 @@ class pnand2(pgate.pgate):
|
||||||
"B",
|
"B",
|
||||||
position="center")
|
position="center")
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.pgate.add_implants:
|
||||||
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
|
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
|
||||||
|
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
""" Route the Z output """
|
""" Route the Z output """
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
|
||||||
import contact
|
import contact
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class pnand3(pgate.pgate):
|
class pnand3(pgate.pgate):
|
||||||
|
|
@ -41,7 +41,7 @@ class pnand3(pgate.pgate):
|
||||||
"Size 1 pnand3 is only supported now.")
|
"Size 1 pnand3 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
||||||
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
|
@ -246,7 +246,7 @@ class pnand3(pgate.pgate):
|
||||||
"C",
|
"C",
|
||||||
position="right")
|
position="right")
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.pgate.add_implants:
|
||||||
self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly"))
|
self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly"))
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ from tech import drc, parameter, spice
|
||||||
from vector import vector
|
from vector import vector
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
|
||||||
import contact
|
import contact
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class pnand4(pgate.pgate):
|
class pnand4(pgate.pgate):
|
||||||
|
|
@ -41,7 +41,7 @@ class pnand4(pgate.pgate):
|
||||||
"Size 1 pnand4 is only supported now.")
|
"Size 1 pnand4 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
||||||
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
|
@ -268,7 +268,7 @@ class pnand4(pgate.pgate):
|
||||||
"D",
|
"D",
|
||||||
position="right")
|
position="right")
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.pgate.add_implants:
|
||||||
self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly"))
|
self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly"))
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@
|
||||||
# (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 contact
|
|
||||||
import pgate
|
import pgate
|
||||||
import debug
|
import debug
|
||||||
from globals import OPTS
|
|
||||||
from tech import drc, parameter, spice
|
from tech import drc, parameter, spice
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class pnor2(pgate.pgate):
|
class pnor2(pgate.pgate):
|
||||||
|
|
@ -37,7 +36,7 @@ class pnor2(pgate.pgate):
|
||||||
debug.check(size==1, "Size 1 pnor2 is only supported now.")
|
debug.check(size==1, "Size 1 pnor2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
|
||||||
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
|
||||||
|
|
||||||
|
|
@ -211,7 +210,7 @@ class pnor2(pgate.pgate):
|
||||||
|
|
||||||
self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch
|
self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.pgate.add_implants:
|
||||||
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
|
self.add_enclosure([apin, bpin], "npc", drc("npc_enclose_poly"))
|
||||||
|
|
||||||
def route_output(self):
|
def route_output(self):
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from tech import parameter, drc
|
||||||
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
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class precharge(design.design):
|
class precharge(design.design):
|
||||||
|
|
@ -79,7 +80,7 @@ class precharge(design.design):
|
||||||
"""
|
"""
|
||||||
Initializes the upper and lower pmos
|
Initializes the upper and lower pmos
|
||||||
"""
|
"""
|
||||||
if(OPTS.tech_name == "sky130"):
|
if cell_props.ptx.bin_spice_models:
|
||||||
self.ptx_width = pgate.nearest_bin("pmos", self.ptx_width)
|
self.ptx_width = pgate.nearest_bin("pmos", self.ptx_width)
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.ptx_width,
|
width=self.ptx_width,
|
||||||
|
|
@ -300,4 +301,4 @@ class precharge(design.design):
|
||||||
self.add_path(self.bitline_layer,
|
self.add_path(self.bitline_layer,
|
||||||
[left_pos, right_pos],
|
[left_pos, right_pos],
|
||||||
width=pmos_pin.height())
|
width=pmos_pin.height())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import contact
|
||||||
import logical_effort
|
import logical_effort
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from pgate import pgate
|
from pgate import pgate
|
||||||
|
from tech import cell_properties as cell_props
|
||||||
|
|
||||||
|
|
||||||
class ptx(design.design):
|
class ptx(design.design):
|
||||||
|
|
@ -129,9 +130,8 @@ class ptx(design.design):
|
||||||
# be decided in the layout later.
|
# be decided in the layout later.
|
||||||
area_sd = 2.5 * self.poly_width * self.tx_width
|
area_sd = 2.5 * self.poly_width * self.tx_width
|
||||||
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
||||||
if OPTS.tech_name == "sky130":
|
if cell_props.ptx.model_is_subckt:
|
||||||
# sky130 simulation cannot use the mult parameter in simulation
|
# sky130
|
||||||
(self.tx_width, self.mults) = pgate.best_bin(self.tx_type, self.tx_width)
|
|
||||||
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||||
self.mults,
|
self.mults,
|
||||||
self.tx_width,
|
self.tx_width,
|
||||||
|
|
@ -150,12 +150,13 @@ class ptx(design.design):
|
||||||
self.spice_device = main_str + area_str
|
self.spice_device = main_str + area_str
|
||||||
self.spice.append("\n* spice ptx " + self.spice_device)
|
self.spice.append("\n* spice ptx " + self.spice_device)
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
|
if cell_props.ptx.model_is_subckt and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
|
||||||
# sky130 requires mult parameter too
|
# sky130 requires mult parameter too
|
||||||
# self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
|
# self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
|
||||||
# self.mults,
|
# self.mults,
|
||||||
# self.tx_width,
|
# self.tx_width,
|
||||||
# drc("minwidth_poly"))
|
# drc("minwidth_poly"))
|
||||||
|
# TEMP FIX: Use old device names if using Calibre.
|
||||||
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort",
|
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format("nshort" if self.tx_type == "nmos" else "pshort",
|
||||||
self.mults,
|
self.mults,
|
||||||
self.tx_width,
|
self.tx_width,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import design
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from tech import layer
|
from tech import layer
|
||||||
|
from tech import layer_properties as layer_props
|
||||||
|
|
||||||
|
|
||||||
class wordline_driver(design.design):
|
class wordline_driver(design.design):
|
||||||
|
|
@ -104,7 +105,7 @@ class wordline_driver(design.design):
|
||||||
|
|
||||||
def route_supply_rails(self):
|
def route_supply_rails(self):
|
||||||
""" Add vdd/gnd rails to the top, (middle), and bottom. """
|
""" Add vdd/gnd rails to the top, (middle), and bottom. """
|
||||||
if OPTS.tech_name == "sky130":
|
if layer_props.wordline_driver.vertical_supply:
|
||||||
for name in ["vdd", "gnd"]:
|
for name in ["vdd", "gnd"]:
|
||||||
for inst in [self.nand_inst, self.driver_inst]:
|
for inst in [self.nand_inst, self.driver_inst]:
|
||||||
self.copy_layout_pin(inst, name)
|
self.copy_layout_pin(inst, name)
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ class pin_group:
|
||||||
Add the enclosure shape to the given cell.
|
Add the enclosure shape to the given cell.
|
||||||
"""
|
"""
|
||||||
for enclosure in self.enclosures:
|
for enclosure in self.enclosures:
|
||||||
debug.info(2, "Adding enclosure {0} {1}".format(self.name,
|
debug.info(4, "Adding enclosure {0} {1}".format(self.name,
|
||||||
enclosure))
|
enclosure))
|
||||||
cell.add_rect(layer=enclosure.layer,
|
cell.add_rect(layer=enclosure.layer,
|
||||||
offset=enclosure.ll(),
|
offset=enclosure.ll(),
|
||||||
|
|
@ -612,7 +612,7 @@ class pin_group:
|
||||||
blockage_set = set()
|
blockage_set = set()
|
||||||
|
|
||||||
for pin in self.pins:
|
for pin in self.pins:
|
||||||
debug.info(2, " Converting {0}".format(pin))
|
debug.info(4, " Converting {0}".format(pin))
|
||||||
# Determine which tracks the pin overlaps
|
# Determine which tracks the pin overlaps
|
||||||
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
|
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
|
||||||
pin)
|
pin)
|
||||||
|
|
@ -628,15 +628,15 @@ class pin_group:
|
||||||
# Remember, this excludes the pin blockages already
|
# Remember, this excludes the pin blockages already
|
||||||
shared_set = pin_set & self.router.blocked_grids
|
shared_set = pin_set & self.router.blocked_grids
|
||||||
if len(shared_set) > 0:
|
if len(shared_set) > 0:
|
||||||
debug.info(2, "Removing pins {}".format(shared_set))
|
debug.info(4, "Removing pins {}".format(shared_set))
|
||||||
pin_set.difference_update(shared_set)
|
pin_set.difference_update(shared_set)
|
||||||
shared_set = partial_set & self.router.blocked_grids
|
shared_set = partial_set & self.router.blocked_grids
|
||||||
if len(shared_set) > 0:
|
if len(shared_set) > 0:
|
||||||
debug.info(2, "Removing pins {}".format(shared_set))
|
debug.info(4, "Removing pins {}".format(shared_set))
|
||||||
partial_set.difference_update(shared_set)
|
partial_set.difference_update(shared_set)
|
||||||
shared_set = blockage_set & self.router.blocked_grids
|
shared_set = blockage_set & self.router.blocked_grids
|
||||||
if len(shared_set) > 0:
|
if len(shared_set) > 0:
|
||||||
debug.info(2, "Removing blocks {}".format(shared_set))
|
debug.info(4, "Removing blocks {}".format(shared_set))
|
||||||
blockage_set.difference_update(shared_set)
|
blockage_set.difference_update(shared_set)
|
||||||
|
|
||||||
# At least one of the groups must have some valid tracks
|
# At least one of the groups must have some valid tracks
|
||||||
|
|
@ -666,5 +666,5 @@ class pin_group:
|
||||||
# Remember the secondary grids for removing adjacent pins
|
# Remember the secondary grids for removing adjacent pins
|
||||||
self.secondary_grids = partial_set
|
self.secondary_grids = partial_set
|
||||||
|
|
||||||
debug.info(2, " pins {}".format(self.grids))
|
debug.info(4, " pins {}".format(self.grids))
|
||||||
debug.info(2, " secondary {}".format(self.secondary_grids))
|
debug.info(4, " secondary {}".format(self.secondary_grids))
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,6 @@ class router(router_tech):
|
||||||
adj_grids))
|
adj_grids))
|
||||||
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
||||||
|
|
||||||
|
|
||||||
debug.info(1, "Removed {} adjacent grids.".format(removed_grids))
|
debug.info(1, "Removed {} adjacent grids.".format(removed_grids))
|
||||||
|
|
||||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||||
|
|
@ -539,7 +538,7 @@ class router(router_tech):
|
||||||
sufficient_list.update([full_overlap])
|
sufficient_list.update([full_overlap])
|
||||||
if partial_overlap:
|
if partial_overlap:
|
||||||
insufficient_list.update([partial_overlap])
|
insufficient_list.update([partial_overlap])
|
||||||
debug.info(2,
|
debug.info(3,
|
||||||
"Converting [ {0} , {1} ] full={2}".format(x,
|
"Converting [ {0} , {1} ] full={2}".format(x,
|
||||||
y,
|
y,
|
||||||
full_overlap))
|
full_overlap))
|
||||||
|
|
@ -632,26 +631,26 @@ class router(router_tech):
|
||||||
pin.layer)
|
pin.layer)
|
||||||
|
|
||||||
overlap_length = pin.overlap_length(track_pin)
|
overlap_length = pin.overlap_length(track_pin)
|
||||||
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
|
debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord,
|
||||||
pin.rect,
|
pin.rect,
|
||||||
track_pin,
|
track_pin,
|
||||||
overlap_length))
|
overlap_length))
|
||||||
inflated_overlap_length = inflated_pin.overlap_length(track_pin)
|
inflated_overlap_length = inflated_pin.overlap_length(track_pin)
|
||||||
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
|
debug.info(4,"Check overlap: {0} {1} . {2} = {3}".format(coord,
|
||||||
inflated_pin.rect,
|
inflated_pin.rect,
|
||||||
track_pin,
|
track_pin,
|
||||||
inflated_overlap_length))
|
inflated_overlap_length))
|
||||||
|
|
||||||
# If it overlaps with the pin, it is sufficient
|
# If it overlaps with the pin, it is sufficient
|
||||||
if overlap_length == math.inf or overlap_length > 0:
|
if overlap_length == math.inf or overlap_length > 0:
|
||||||
debug.info(2," Overlap: {0} >? {1}".format(overlap_length, 0))
|
debug.info(4," Overlap: {0} >? {1}".format(overlap_length, 0))
|
||||||
return (coord, None)
|
return (coord, None)
|
||||||
# If it overlaps with the inflated pin, it is partial
|
# If it overlaps with the inflated pin, it is partial
|
||||||
elif inflated_overlap_length == math.inf or inflated_overlap_length > 0:
|
elif inflated_overlap_length == math.inf or inflated_overlap_length > 0:
|
||||||
debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0))
|
debug.info(4," Partial overlap: {0} >? {1}".format(inflated_overlap_length, 0))
|
||||||
return (None, coord)
|
return (None, coord)
|
||||||
else:
|
else:
|
||||||
debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0))
|
debug.info(4, " No overlap: {0} {1}".format(overlap_length, 0))
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
def convert_track_to_pin(self, track):
|
def convert_track_to_pin(self, track):
|
||||||
|
|
@ -846,7 +845,7 @@ class router(router_tech):
|
||||||
"Pin component index too large.")
|
"Pin component index too large.")
|
||||||
|
|
||||||
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(3,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_source(pin_in_tracks)
|
self.rg.add_source(pin_in_tracks)
|
||||||
|
|
||||||
def add_path_target(self, paths):
|
def add_path_target(self, paths):
|
||||||
|
|
@ -914,7 +913,7 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
path = self.prepare_path(path)
|
path = self.prepare_path(path)
|
||||||
|
|
||||||
debug.info(2, "Adding route: {}".format(str(path)))
|
debug.info(4, "Adding route: {}".format(str(path)))
|
||||||
# If it is only a square, add an enclosure to the track
|
# If it is only a square, add an enclosure to the track
|
||||||
if len(path) == 1:
|
if len(path) == 1:
|
||||||
self.add_single_enclosure(path[0][0])
|
self.add_single_enclosure(path[0][0])
|
||||||
|
|
@ -1007,8 +1006,7 @@ class router(router_tech):
|
||||||
# returns the path in tracks
|
# returns the path in tracks
|
||||||
(path, cost) = self.rg.route(detour_scale)
|
(path, cost) = self.rg.route(detour_scale)
|
||||||
if path:
|
if path:
|
||||||
debug.info(1, "Found path: cost={0} ".format(cost))
|
debug.info(2, "Found path: cost={0} {1}".format(cost, str(path)))
|
||||||
debug.info(1, str(path))
|
|
||||||
|
|
||||||
self.paths.append(path)
|
self.paths.append(path)
|
||||||
self.add_route(path)
|
self.add_route(path)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
04_pbitcell_test.py
|
04_pbitcell_test.py
|
||||||
04_precharge_pbitcell_test.py
|
04_precharge_pbitcell_test.py
|
||||||
04_replica_pbitcell_test.py
|
04_replica_pbitcell_test.py
|
||||||
04_single_level_column_mux_pbitcell_test.py
|
04_column_mux_pbitcell_test.py
|
||||||
05_bitcell_1rw_1r_array_test.py
|
05_bitcell_1rw_1r_array_test.py
|
||||||
05_bitcell_array_test.py
|
05_bitcell_array_test.py
|
||||||
05_dummy_array_test.py
|
05_dummy_array_test.py
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
06_hierarchical_predecode3x8_pbitcell_test.py
|
06_hierarchical_predecode3x8_pbitcell_test.py
|
||||||
06_hierarchical_predecode3x8_test.py
|
06_hierarchical_predecode3x8_test.py
|
||||||
06_hierarchical_predecode4x16_test.py
|
06_hierarchical_predecode4x16_test.py
|
||||||
07_single_level_column_mux_array_pbitcell_test.py
|
07_column_mux_array_pbitcell_test.py
|
||||||
08_wordline_driver_array_pbitcell_test.py
|
08_wordline_driver_array_pbitcell_test.py
|
||||||
08_wordline_driver_array_test.py
|
08_wordline_driver_array_test.py
|
||||||
09_sense_amp_array_test_pbitcell.py
|
09_sense_amp_array_test_pbitcell.py
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import os
|
||||||
from design_rules import *
|
from design_rules import *
|
||||||
from module_type import *
|
from module_type import *
|
||||||
from custom_cell_properties import cell_properties
|
from custom_cell_properties import cell_properties
|
||||||
|
from custom_layer_properties import layer_properties
|
||||||
|
|
||||||
"""
|
"""
|
||||||
File containing the process technology parameters for FreePDK 45nm.
|
File containing the process technology parameters for FreePDK 45nm.
|
||||||
|
|
@ -34,6 +35,11 @@ cell_properties.bitcell.mirror.x = True
|
||||||
cell_properties.bitcell.mirror.y = False
|
cell_properties.bitcell.mirror.y = False
|
||||||
cell_properties.bitcell_power_pin_directions = ("V", "V")
|
cell_properties.bitcell_power_pin_directions = ("V", "V")
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# Custom cell properties
|
||||||
|
###################################################
|
||||||
|
layer_properties = layer_properties()
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# GDS file info
|
# GDS file info
|
||||||
###################################################
|
###################################################
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import os
|
||||||
from design_rules import *
|
from design_rules import *
|
||||||
from module_type import *
|
from module_type import *
|
||||||
from custom_cell_properties import cell_properties
|
from custom_cell_properties import cell_properties
|
||||||
|
from custom_layer_properties import layer_properties
|
||||||
|
|
||||||
"""
|
"""
|
||||||
File containing the process technology parameters for SCMOS 4m, 0.35um
|
File containing the process technology parameters for SCMOS 4m, 0.35um
|
||||||
|
|
@ -32,6 +33,11 @@ cell_properties = cell_properties()
|
||||||
cell_properties.bitcell.mirror.x = True
|
cell_properties.bitcell.mirror.x = True
|
||||||
cell_properties.bitcell.mirror.y = False
|
cell_properties.bitcell.mirror.y = False
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# Custom cell properties
|
||||||
|
###################################################
|
||||||
|
layer_properties = layer_properties()
|
||||||
|
|
||||||
###################################################
|
###################################################
|
||||||
# GDS file info
|
# GDS file info
|
||||||
###################################################
|
###################################################
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue