mirror of https://github.com/VLSIDA/OpenRAM.git
squash commits
This commit is contained in:
parent
5fd548582f
commit
cb7f117daa
|
|
@ -144,11 +144,11 @@ class _pgate:
|
|||
|
||||
|
||||
class bitcell(cell):
|
||||
def __init__(self, port_order, port_types, port_map=None, storage_nets=["Q", "Q_bar"], mirror=None, end_caps=False):
|
||||
def __init__(self, port_order, port_types, port_map=None, storage_nets=["Q", "Q_bar"], mirror=None, end_caps=False, has_corners=True):
|
||||
super().__init__(port_order, port_types, port_map)
|
||||
|
||||
self.end_caps = end_caps
|
||||
|
||||
self.has_corners = has_corners
|
||||
if not mirror:
|
||||
self.mirror = _mirror_axis(True, False)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ class bitcell_array(bitcell_base_array):
|
|||
core_block = [[0 for x in range(1)] for y in range(2)]
|
||||
core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True)
|
||||
core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
|
||||
print(r, c)
|
||||
print(core_block)
|
||||
#print(r, c)
|
||||
#print(core_block)
|
||||
|
||||
self.pattern = pattern(self, "bitcell_array", core_block, num_rows=self.row_size, num_cols=self.column_size,name_template="bit_r{0}_c{1}")
|
||||
self.pattern.connect_array()
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class bitcell_base(design):
|
|||
self.nets_match = self.do_nets_exist(prop.storage_nets)
|
||||
self.mirror = prop.mirror
|
||||
self.end_caps = prop.end_caps
|
||||
self.has_corners = prop.has_corners
|
||||
def get_stage_effort(self, load):
|
||||
parasitic_delay = 1
|
||||
# This accounts for bitline being drained
|
||||
|
|
|
|||
|
|
@ -121,13 +121,14 @@ class bitcell_base_array(design):
|
|||
def get_all_wordline_names(self, port=None):
|
||||
""" Return all the wordline names """
|
||||
temp = []
|
||||
temp.extend(self.get_rbl_wordline_names(0))
|
||||
if len(self.all_ports) > 1:
|
||||
temp.extend(self.get_rbl_wordline_names(1))
|
||||
if port == None:
|
||||
temp.extend(self.all_wordline_names)
|
||||
else:
|
||||
temp.extend(self.wordline_names[port])
|
||||
if len(self.all_ports) > 1:
|
||||
temp.extend(self.get_rbl_wordline_names(1))
|
||||
temp.extend(self.get_rbl_wordline_names(0))
|
||||
|
||||
return temp
|
||||
|
||||
def add_bitline_pins(self):
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
|
|||
rows=1,
|
||||
# dummy column + left replica column(s)
|
||||
column_offset=1,
|
||||
row_offset=self.row_size+ self.extra_rows,
|
||||
row_offset=self.row_size+ self.extra_rows + 1, #add 1 to account for bottom col_cap
|
||||
mirror=0,
|
||||
location="top",
|
||||
left_rbl=self.left_rbl,
|
||||
|
|
@ -162,10 +162,21 @@ class capped_replica_bitcell_array(bitcell_base_array):
|
|||
self.unused_wordline_names = self.replica_bitcell_array.unused_wordline_names
|
||||
self.replica_array_wordline_names_with_grounded_wls = ["gnd" if x in self.unused_wordline_names else x for x in self.replica_bitcell_array.wordline_pin_list]
|
||||
|
||||
# Left/right row caps cover the full array height. Pad with gnd so the
|
||||
# netlist list length matches the row cap (replica in the center); do
|
||||
# not use col cap wordline heuristics.
|
||||
|
||||
n_rowcap_wl = len(self.row_cap_left.get_wordline_names())
|
||||
n_rba_wl = len(self.replica_array_wordline_names_with_grounded_wls)
|
||||
|
||||
|
||||
self.wordline_pin_list = []
|
||||
self.wordline_pin_list.extend(["gnd"] * len(self.col_cap_top.get_wordline_names()))
|
||||
|
||||
if self.rbls:
|
||||
self.wordline_pin_list.extend(["gnd"] * len(self.rbls))
|
||||
self.wordline_pin_list.extend(self.replica_array_wordline_names_with_grounded_wls)
|
||||
self.wordline_pin_list.extend(["gnd"] * len(self.col_cap_bottom.get_wordline_names()))
|
||||
if self.rbls:
|
||||
self.wordline_pin_list.extend(["gnd"] * len(self.rbls))
|
||||
|
||||
self.add_pin_list(self.used_wordline_names, "INPUT")
|
||||
|
||||
|
|
@ -192,6 +203,10 @@ class capped_replica_bitcell_array(bitcell_base_array):
|
|||
self.dummy_col_insts.append(self.add_inst(name="dummy_col_left",
|
||||
mod=self.row_cap_left))
|
||||
self.connect_inst(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + self.wordline_pin_list + self.supplies)
|
||||
|
||||
#print(self.dummy_col_insts[0].mod.pins)
|
||||
#print(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + self.wordline_pin_list + self.supplies)
|
||||
|
||||
self.dummy_col_insts.append(self.add_inst(name="dummy_col_right",
|
||||
mod=self.row_cap_right))
|
||||
self.connect_inst(["dummy_right_" + bl for bl in self.row_cap_right.all_bitline_names] + self.wordline_pin_list + self.supplies)
|
||||
|
|
@ -282,10 +297,14 @@ class capped_replica_bitcell_array(bitcell_base_array):
|
|||
# Far left dummy col
|
||||
dummy_col_width = vector(self.dummy_col_insts[0].width, 0)
|
||||
offset = self.dummy_row_insts[0].ll() - dummy_col_width
|
||||
if self.dummy_col_insts[0].mod.cell.has_corners is False:
|
||||
offset += vector(0, dummy_row_height.y)
|
||||
self.dummy_col_insts[0].place(offset=offset)
|
||||
|
||||
# Far right dummy col
|
||||
offset = self.dummy_row_insts[0].lr()
|
||||
if self.dummy_col_insts[0].mod.cell.has_corners is False:
|
||||
offset += vector(0, dummy_row_height.y)
|
||||
self.dummy_col_insts[1].place(offset=offset)
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class col_cap_array(bitcell_base_array):
|
|||
Generate a dummy row/column for the replica array.
|
||||
"""
|
||||
def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name="",left_rbl=[],right_rbl=[]):
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
|
||||
self.mirror = mirror
|
||||
self.location = location
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ class dummy_array(bitcell_base_array):
|
|||
core_block = [[0 for x in range(1)] for y in range(2)]
|
||||
core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True)
|
||||
core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
print(r, c)
|
||||
print(core_block)
|
||||
#print(r, c)
|
||||
#print(core_block)
|
||||
|
||||
self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size, name_template="bit_r{0}_c{1}")
|
||||
self.pattern.connect_array()
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class pattern():
|
|||
y += inst.height
|
||||
if "Y" in inst.mirror:
|
||||
x += inst.width
|
||||
print('placing inst {} at {}'.format(inst, offset))
|
||||
#print('placing inst {} at {}'.format(inst, offset))
|
||||
inst.place((x, y), inst.mirror, inst.rotate)
|
||||
|
||||
def place_array(self):
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
""" Array and dummy/replica columns """
|
||||
# Bitcell array
|
||||
self.bitcell_array = factory.create(module_type="bitcell_array",
|
||||
column_offset=len(self.left_rbl),
|
||||
row_offset=len(self.left_rbl),
|
||||
column_offset=len(self.left_rbl)+ 1, #add 1 to account for left row_cap
|
||||
row_offset=len(self.left_rbl)+1, #add 1 to account for bottom col_cap
|
||||
cols=self.column_size,
|
||||
rows=self.row_size,
|
||||
left_rbl=self.left_rbl,
|
||||
|
|
@ -92,11 +92,11 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
if port in self.left_rbl:
|
||||
# These go top down starting from the bottom of the bitcell array.
|
||||
replica_bit = self.rbl[0] - port - 1
|
||||
column_offset = 0
|
||||
column_offset = 1
|
||||
elif port in self.right_rbl:
|
||||
# These go bottom up starting from the top of the bitcell array.
|
||||
replica_bit = self.rbl[0] + self.row_size + port - 1
|
||||
column_offset = len(self.left_rbl) + self.column_size
|
||||
column_offset = len(self.left_rbl) + self.column_size + 1
|
||||
else:
|
||||
continue
|
||||
|
||||
|
|
@ -120,8 +120,8 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
self.dummy_rows[port] = factory.create(module_type="dummy_array",
|
||||
cols=self.column_size,
|
||||
rows=1,
|
||||
row_offset=row_offset,
|
||||
column_offset=len(self.left_rbl))
|
||||
row_offset=row_offset+1, #add 1 to account for bottom col_cap
|
||||
column_offset=len(self.left_rbl)+1) #add 1 to account for left row_cap
|
||||
|
||||
def add_pins(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -96,14 +96,14 @@ class replica_column(bitcell_base_array):
|
|||
# All other cells are dummies
|
||||
if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end):
|
||||
if current_row % 2 == 0:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True)
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True)
|
||||
else:
|
||||
if current_row % 2 == 0:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True)
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True)
|
||||
|
||||
current_row += 1
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class row_cap_array(bitcell_base_array):
|
|||
Generate a dummy row/column for the replica array.
|
||||
"""
|
||||
def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name=""):
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
|
||||
self.mirror = mirror
|
||||
self.location = location
|
||||
self.row_offset = row_offset
|
||||
|
|
@ -76,7 +76,11 @@ class row_cap_array(bitcell_base_array):
|
|||
pattern.append_row_to_block(bit_block, [rowend_m])
|
||||
|
||||
#pattern.append_row_to_block(bit_block, [bottom_corner])
|
||||
self.pattern = pattern(self, "row_cap_array_" + self.location, bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="row_cap_array" + self.location + "_r{0}_c{1}")
|
||||
if self.cell.has_corners is False:
|
||||
num_rows = self.row_size - 2
|
||||
else:
|
||||
num_rows = self.row_size
|
||||
self.pattern = pattern(self, "row_cap_array_" + self.location, bit_block, num_rows=num_rows, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="row_cap_array" + self.location + "_r{0}_c{1}")
|
||||
self.pattern.connect_array_raw()
|
||||
|
||||
def get_bitcell_pins(self, row, col):
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ num_sim_threads = 1
|
|||
#analytical_delay = False
|
||||
import os
|
||||
exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read())
|
||||
#tech_file = "tech_custom_cell"
|
||||
tech_file = "tech_custom_cell"
|
||||
|
|
@ -17,8 +17,8 @@ class sky130_bitcell_base_array(bitcell_base_array):
|
|||
"""
|
||||
Abstract base class for bitcell-arrays -- bitcell, dummy, replica
|
||||
"""
|
||||
def __init__(self, name, rows, cols, column_offset):
|
||||
super().__init__(name, rows, cols, column_offset)
|
||||
def __init__(self, name, rows, cols, column_offset, row_offset):
|
||||
super().__init__(name, rows, cols, column_offset, row_offset)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
|
||||
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||
|
|
|
|||
|
|
@ -80,12 +80,12 @@ class sky130_replica_column(replica_column, sky130_bitcell_base_array):
|
|||
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
|
||||
# All other cells are dummies
|
||||
if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end):
|
||||
if current_row % 2 == 1:
|
||||
if current_row % 2 == 0:
|
||||
pattern.append_row_to_block(bit_block, replica_row_opt1)
|
||||
else:
|
||||
pattern.append_row_to_block(bit_block, replica_row_opt1a)
|
||||
else:
|
||||
if current_row % 2 == 1:
|
||||
if current_row % 2 == 0:
|
||||
pattern.append_row_to_block(bit_block, dummy_row_opt1)
|
||||
else:
|
||||
pattern.append_row_to_block(bit_block, dummy_row_opt1a)
|
||||
|
|
|
|||
|
|
@ -56,13 +56,15 @@ class sky130_row_cap_array(row_cap_array, sky130_bitcell_base_array):
|
|||
rowend = geometry.instance("row_cap_rowend", mod=self.rowend, is_bitcell=True, mirror="MX")
|
||||
rowenda = geometry.instance("row_cap_rowenda", mod=self.rowenda, is_bitcell=True)
|
||||
|
||||
pattern.append_row_to_block(bit_block, [top_corner])
|
||||
pattern.append_row_to_block(bit_block, [bottom_corner])
|
||||
for row in range(1, self.row_size-1):
|
||||
if row % 2 == 1:
|
||||
pattern.append_row_to_block(bit_block, [rowend])
|
||||
else:
|
||||
pattern.append_row_to_block(bit_block, [rowenda])
|
||||
pattern.append_row_to_block(bit_block, [bottom_corner])
|
||||
|
||||
else:
|
||||
pattern.append_row_to_block(bit_block, [rowend])
|
||||
|
||||
pattern.append_row_to_block(bit_block, [top_corner])
|
||||
self.pattern = pattern(self, "row_cap_array_" + self.location, bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="row_cap_array" + self.location + "_r{0}_c{1}")
|
||||
self.pattern.connect_array_raw()
|
||||
|
||||
|
|
@ -77,8 +79,6 @@ class sky130_row_cap_array(row_cap_array, sky130_bitcell_base_array):
|
|||
bitcell_pins.append("vdd") # vdd
|
||||
bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
|
||||
|
||||
#bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
|
||||
|
||||
return bitcell_pins
|
||||
|
||||
def get_strap_pins(self, row, col):
|
||||
|
|
@ -94,7 +94,6 @@ class sky130_row_cap_array(row_cap_array, sky130_bitcell_base_array):
|
|||
def create_all_wordline_names(self, row_size=None, start_row=0):
|
||||
if row_size == None:
|
||||
row_size = self.row_size
|
||||
row_size = row_size - 2
|
||||
for row in range(start_row, row_size):
|
||||
for port in self.all_ports:
|
||||
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ sys.path.append("{}/{}".format(dir_path,'tech_configs'))
|
|||
|
||||
if not hasattr(OPTS, 'tech_file'):
|
||||
OPTS.tech_file = 'tech_cypress_cell'
|
||||
#TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING EXECUTING
|
||||
#TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING
|
||||
exec('from {} import *'.format(OPTS.tech_file))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,857 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
import os
|
||||
from openram import drc as d
|
||||
|
||||
"""
|
||||
File containing the process technology parameters for Skywater 130nm.
|
||||
"""
|
||||
|
||||
###################################################
|
||||
# Custom modules
|
||||
###################################################
|
||||
|
||||
# This uses the default classes to instantiate module from
|
||||
# '$OPENRAM_HOME/compiler/modules'.
|
||||
# Using tech_modules['cellname'] you can override each class by providing a custom
|
||||
# implementation in '$OPENRAM_TECHDIR/modules/'
|
||||
# For example: tech_modules["contact"] = "contact_freepdk45"
|
||||
tech_modules = d.module_type()
|
||||
|
||||
|
||||
# These modules have been hand designed and provided in this repository.
|
||||
tech_modules["nand2_dec"] = "nand2_dec"
|
||||
tech_modules["nand3_dec"] = "nand3_dec"
|
||||
tech_modules["nand4_dec"] = "nand4_dec"
|
||||
|
||||
# Override default OpenRAM modules to sky130 modules
|
||||
# These are for single port and dual port as a list,
|
||||
# or for both if there is no list,
|
||||
# or only applicable to one if there is no list.
|
||||
|
||||
#tech_modules["bitcell_1port"] = "sky130_bitcell"
|
||||
#tech_modules["replica_bitcell_1port"] = "sky130_replica_bitcell"
|
||||
#tech_modules["dummy_bitcell_1port"] = "sky130_dummy_bitcell"
|
||||
|
||||
tech_modules["replica_bitcell_2port"] = "replica_bitcell_2port"
|
||||
tech_modules["dummy_bitcell_2port"] = "dummy_bitcell_2port"
|
||||
tech_modules["bitcell_2port"] = "bitcell_2port"
|
||||
|
||||
tech_modules["bitcell_array"] = ["bitcell_array", "bitcell_array"]
|
||||
tech_modules["replica_bitcell_array"] = ["replica_bitcell_array", "replica_bitcell_array"]
|
||||
tech_modules["capped_replica_bitcell_array"] = ["capped_replica_bitcell_array", "capped_replica_bitcell_array"]
|
||||
tech_modules["dummy_array"] = ["dummy_array", "dummy_array"]
|
||||
|
||||
tech_modules["replica_column"] = ["replica_column", "replica_column"]
|
||||
|
||||
tech_modules["col_cap_array"] = ["col_cap_array", "col_cap_array"]
|
||||
tech_modules["col_cap"] = ["col_cap_bitcell_1port", "col_cap_bitcell_2port"]
|
||||
tech_modules["corner"] = ["sky130_corner", None]
|
||||
tech_modules["internal"] = ["sky130_internal", None]
|
||||
tech_modules["row_cap_array"] = ["sky130_row_cap_array", "row_cap_array"]
|
||||
tech_modules["row_cap"] = ["sky130_row_cap", "row_cap_bitcell_2port"]
|
||||
|
||||
# These modules are auto-generated from the nand decoders above and are not
|
||||
# found in this.
|
||||
tech_modules["buf_dec"] = "pbuf_dec"
|
||||
tech_modules["inv_dec"] = "pinv_dec"
|
||||
tech_modules["and2_dec"] = "and2_dec"
|
||||
tech_modules["and3_dec"] = "and3_dec"
|
||||
tech_modules["and4_dec"] = "and4_dec"
|
||||
|
||||
###################################################
|
||||
# Custom cell properties
|
||||
###################################################
|
||||
cell_properties = d.cell_properties()
|
||||
|
||||
cell_properties.power_name = 'VPWR'
|
||||
cell_properties.ground_name = 'VGND'
|
||||
|
||||
cell_properties.bitcell_power_pin_directions = ("V", "V")
|
||||
|
||||
cell_properties.bitcell_1port.mirror.x = True
|
||||
cell_properties.bitcell_1port.mirror.y = True
|
||||
cell_properties.bitcell_1port.end_caps = False
|
||||
cell_properties.bitcell_1port.has_corners = True
|
||||
|
||||
cell_properties.bitcell_1port.boundary_layer = "boundary"
|
||||
cell_properties.bitcell_1port.port_order = ['bl', 'br', 'wl', 'vdd', 'gnd']
|
||||
cell_properties.bitcell_1port.port_types = ["INPUT", "INPUT", "GROUND", "POWER", "OUTPUT"]
|
||||
cell_properties.bitcell_1port.port_map = {'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'gnd': 'VGND',
|
||||
'vdd': 'VPWR',
|
||||
'wl': 'WL'}
|
||||
|
||||
|
||||
|
||||
|
||||
cell_properties.bitcell_1port.wl_layer = "m2"
|
||||
cell_properties.bitcell_1port.bl_layer = "m1"
|
||||
cell_properties.bitcell_1port.vdd_layer = "m1"
|
||||
cell_properties.bitcell_1port.vdd_dir = "V"
|
||||
cell_properties.bitcell_1port.gnd_layer = "m1"
|
||||
cell_properties.bitcell_1port.gnd_dir = "V"
|
||||
|
||||
cell_properties.bitcell_2port.mirror.x = True
|
||||
cell_properties.bitcell_2port.mirror.y = True
|
||||
cell_properties.bitcell_2port.end_caps = True
|
||||
cell_properties.bitcell_2port.has_corners = True
|
||||
cell_properties.bitcell_2port.port_order = ['bl0', 'br0', 'bl1', 'br1', 'wl0', 'wl1', 'vdd', 'gnd']
|
||||
cell_properties.bitcell_2port.port_map = {'bl0': 'BL0',
|
||||
'br0': 'BR0',
|
||||
'bl1': 'BL1',
|
||||
'br1': 'BR1',
|
||||
'wl0': 'WL0',
|
||||
'wl1': 'WL1',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.bitcell_1port.wl_layer = "m2"
|
||||
cell_properties.bitcell_1port.vdd_layer = "m1"
|
||||
cell_properties.bitcell_1port.vdd_dir = "V"
|
||||
cell_properties.bitcell_1port.gnd_layer = "m1"
|
||||
cell_properties.bitcell_1port.gnd_dir = "V"
|
||||
cell_properties.bitcell_2port.wl_layer = "m2"
|
||||
cell_properties.bitcell_2port.vdd_layer = "m1"
|
||||
cell_properties.bitcell_2port.vdd_dir = "H"
|
||||
cell_properties.bitcell_2port.gnd_layer = "m2"
|
||||
cell_properties.bitcell_2port.gnd_dir = "H"
|
||||
|
||||
cell_properties.col_cap_1port_bitcell = d.cell(['bl', 'br', 'vdd', 'gnd',],
|
||||
['INPUT', 'INPUT','POWER', 'GROUND', ],
|
||||
{'bl': 'bl',
|
||||
'br': 'br',
|
||||
'vdd': 'vdd',
|
||||
'gnd': 'gnd',})
|
||||
cell_properties.col_cap_1port_bitcell.boundary_layer = "boundary"
|
||||
|
||||
cell_properties.col_cap_1port_strap_power = d.cell(['vdd', 'vpb', 'vnb'],
|
||||
['POWER', 'BIAS', 'BIAS'],
|
||||
{'vnb': 'VNB',
|
||||
'vpb': 'VPB',
|
||||
'vdd': 'VPWR'})
|
||||
cell_properties.col_cap_1port_strap_power.boundary_layer = "boundary"
|
||||
|
||||
cell_properties.col_cap_1port_strap_ground = d.cell(['gnd', 'vpb', 'vnb'],
|
||||
['GROUND', 'BIAS', 'BIAS'],
|
||||
{'vnb': 'VNB',
|
||||
'vpb': 'VPB',
|
||||
'gnd': 'VGND'})
|
||||
cell_properties.col_cap_1port_strap_ground.boundary_layer = "boundary"
|
||||
|
||||
cell_properties.row_cap_1port_cell = d.cell(['vdd', 'wl'],
|
||||
['POWER', 'INPUT'],
|
||||
{'wl': 'WL',
|
||||
'vdd': 'VPWR'})
|
||||
cell_properties.row_cap_1port_cell.boundary_layer = "boundary"
|
||||
|
||||
cell_properties.col_cap_2port.port_order = ['bl0', 'br0', 'bl1', 'br1', 'vdd']
|
||||
cell_properties.col_cap_2port.port_map = {'bl0': 'BL0',
|
||||
'br0': 'BR0',
|
||||
'bl1': 'BL1',
|
||||
'br1': 'BR1',
|
||||
'vdd': 'VDD'}
|
||||
|
||||
cell_properties.row_cap_2port.port_order = ['wl0', 'wl1', 'gnd']
|
||||
cell_properties.row_cap_2port.port_map = {'wl0': 'WL0',
|
||||
'wl1': 'WL1',
|
||||
'gnd': 'GND'}
|
||||
|
||||
|
||||
cell_properties.ptx.bin_spice_models = True
|
||||
cell_properties.ptx.model_is_subckt = True
|
||||
|
||||
cell_properties.pgate.add_implants = True
|
||||
|
||||
cell_properties.use_strap = False
|
||||
cell_properties.strap_module = "internal"
|
||||
cell_properties.strap_version = "wlstrap"
|
||||
|
||||
cell_properties.dff.port_order = ['D', 'Q', 'clk', 'vdd', 'gnd']
|
||||
cell_properties.dff.port_map = {'D': 'D',
|
||||
'Q': 'Q',
|
||||
'clk': 'CLK',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand2_dec.port_order = ['A', 'B', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand2_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand3_dec.port_order = ['A', 'B', 'C', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand3_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'C': 'C',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand4_dec.port_order = ['A', 'B', 'C', 'D', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand4_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'C': 'C',
|
||||
'D': 'D',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.sense_amp.port_order = ['bl', 'br', 'dout', 'en', 'vdd', 'gnd']
|
||||
cell_properties.sense_amp.port_map = {'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'dout': 'DOUT',
|
||||
'en': 'EN',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.write_driver.port_order = ['din', 'bl', 'br', 'en', 'vdd', 'gnd']
|
||||
cell_properties.write_driver.port_map = {'din': 'DIN',
|
||||
'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'en': 'EN',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
|
||||
# You can override the GDS for custom cell using the following:
|
||||
# If it is a list, the first is single port and the second is dual port.
|
||||
# If it is string, it is used for both single and dual port.
|
||||
cell_properties.names["dff"] = "sky130_fd_bd_sram__openram_dff"
|
||||
cell_properties.names["nand2_dec"] = ["sky130_fd_bd_sram__openram_dp_nand2_dec", "sky130_fd_bd_sram__openram_dp_nand2_dec"]
|
||||
cell_properties.names["nand3_dec"] = ["sky130_fd_bd_sram__openram_dp_nand3_dec", "sky130_fd_bd_sram__openram_dp_nand3_dec"]
|
||||
cell_properties.names["nand4_dec"] = ["sky130_fd_bd_sram__openram_dp_nand4_dec", "sky130_fd_bd_sram__openram_dp_nand4_dec"]
|
||||
|
||||
cell_properties.names["bitcell_1port"] = "sky130_custom_cell"
|
||||
cell_properties.names["replica_bitcell_1port"] = "sky130_custom_replica"
|
||||
cell_properties.names["dummy_bitcell_1port"] = "sky130_custom_dummy"
|
||||
|
||||
cell_properties.names["bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell"
|
||||
cell_properties.names["dummy_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_dummy"
|
||||
cell_properties.names["replica_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_replica"
|
||||
cell_properties.names["col_cap_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_cap_col"
|
||||
cell_properties.names["row_cap_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_cap_row"
|
||||
cell_properties.names["sense_amp"] = "sky130_fd_bd_sram__openram_sense_amp"
|
||||
cell_properties.names["write_driver"] = "sky130_fd_bd_sram__openram_write_driver"
|
||||
|
||||
array_row_multiple = 2
|
||||
array_col_multiple = 2
|
||||
|
||||
###################################################
|
||||
# Custom layer properties
|
||||
###################################################
|
||||
layer_properties = d.layer_properties()
|
||||
layer_properties.hierarchical_decoder.bus_layer = "m1"
|
||||
layer_properties.hierarchical_decoder.bus_directions = "nonpref"
|
||||
layer_properties.hierarchical_decoder.input_layer = "li"
|
||||
layer_properties.hierarchical_decoder.output_layer = "m2"
|
||||
layer_properties.hierarchical_decoder.vertical_supply = True
|
||||
|
||||
layer_properties.hierarchical_predecode.bus_layer = "m1"
|
||||
layer_properties.hierarchical_predecode.bus_directions = "nonpref"
|
||||
# This is added to allow the column decoder connections on m2
|
||||
layer_properties.hierarchical_predecode.bus_pitch_factor = 1.2
|
||||
layer_properties.hierarchical_predecode.bus_space_factor = 1.5
|
||||
layer_properties.hierarchical_predecode.input_layer = "li"
|
||||
layer_properties.hierarchical_predecode.output_layer = "m2"
|
||||
layer_properties.hierarchical_predecode.vertical_supply = True
|
||||
layer_properties.hierarchical_predecode.force_horizontal_input_contact = True
|
||||
|
||||
layer_properties.bank.stack = "m2_stack"
|
||||
layer_properties.bank.pitch = "m3_pitch"
|
||||
|
||||
layer_properties.column_mux_array.select_layer = "m3"
|
||||
layer_properties.column_mux_array.bitline_layer = "m1"
|
||||
|
||||
layer_properties.port_address.supply_offset = True
|
||||
|
||||
layer_properties.port_data.enable_layer = "m1"
|
||||
layer_properties.port_data.channel_route_bitlines = False
|
||||
|
||||
layer_properties.replica_column.even_rows = False
|
||||
|
||||
layer_properties.wordline_driver.vertical_supply = True
|
||||
|
||||
layer_properties.global_wordline_layer = "m5"
|
||||
|
||||
|
||||
###################################################
|
||||
# Discrete tx bins
|
||||
###################################################
|
||||
# enforce that tx sizes are within 25% of requested size after fingering.
|
||||
accuracy_requirement = 0.75
|
||||
nmos_bins = {
|
||||
0.15 : [0.36, 0.39, 0.42, 0.52, 0.54, 0.55, 0.58, 0.6, 0.61, 0.64, 0.65, 0.74, 0.84, 1.0, 1.26, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
0.18 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
0.25 : [0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
0.5 : [0.42, 0.55, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
1.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
2.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
4.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
8.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
20.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0]
|
||||
}
|
||||
|
||||
pmos_bins = {
|
||||
0.15 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12, 1.26, 1.65, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
1.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
2.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
4.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
8.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
0.17 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12],
|
||||
0.18 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12, 1.26, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
0.25 : [1.0, 3.0, 5.0, 7.0],
|
||||
0.5 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
20.0 : [0.42]
|
||||
}
|
||||
###################################################
|
||||
# GDS file info
|
||||
###################################################
|
||||
GDS = {}
|
||||
# gds units
|
||||
# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first
|
||||
# is the size of a database unit in user units. The second is the size
|
||||
# of a database unit in meters. For example, if your library was
|
||||
# created with the default units (user unit = 1 um and 1000 database
|
||||
# units per user unit), then the first number would be 0.001 and the
|
||||
# second number would be 10-9. Typically, the first number is less than
|
||||
# 1, since you use more than 1 database unit per user unit. To
|
||||
# calculate the size of a user unit in meters, divide the second number
|
||||
# by the first."
|
||||
GDS["unit"] = (0.001, 1e-9)
|
||||
#GDS["unit"]=(0.001, 1e-6)
|
||||
|
||||
###################################################
|
||||
# Interconnect stacks
|
||||
###################################################
|
||||
|
||||
poly_stack = ("poly", "contact", "li")
|
||||
active_stack = ("active", "contact", "li")
|
||||
li_stack = ("li", "mcon", "m1")
|
||||
m1_stack = ("m1", "via1", "m2")
|
||||
m2_stack = ("m2", "via2", "m3")
|
||||
m3_stack = ("m3", "via3", "m4")
|
||||
m4_stack = ("m4", "via4", "m5")
|
||||
|
||||
lef_rom_interconnect = ["m1", "m2", "m3", "m4"]
|
||||
|
||||
layer_indices = {"poly": 0,
|
||||
"active": 0,
|
||||
"nwell": 0,
|
||||
"li": 1,
|
||||
"m1": 2,
|
||||
"m2": 3,
|
||||
"m3": 4,
|
||||
"m4": 5,
|
||||
"m5": 6}
|
||||
|
||||
# The FEOL stacks get us up to m1
|
||||
feol_stacks = [poly_stack,
|
||||
active_stack,
|
||||
li_stack]
|
||||
|
||||
# The BEOL stacks are m1 and up
|
||||
beol_stacks = [m1_stack,
|
||||
m2_stack,
|
||||
m3_stack,
|
||||
m4_stack]
|
||||
|
||||
layer_stacks = feol_stacks + beol_stacks
|
||||
|
||||
preferred_directions = {"poly": "V",
|
||||
"active": "V",
|
||||
"li": "V",
|
||||
"m1": "H",
|
||||
"m2": "V",
|
||||
"m3": "H",
|
||||
"m4": "V",
|
||||
"m5": "H"}
|
||||
|
||||
###################################################
|
||||
# GDS Layer Map
|
||||
###################################################
|
||||
|
||||
|
||||
layer = {}
|
||||
layer["active"] = (65, 20) # diff
|
||||
layer["activep"] = (65, 20) # diff
|
||||
layer["tap"] = (65, 44) # tap
|
||||
layer["pwellp"] = (122,16)
|
||||
layer["nwell"] = (64, 20) # nwell
|
||||
layer["dnwell"] = (64,18)
|
||||
layer["nimplant"]= (93, 44) # nsdm
|
||||
layer["pimplant"]= (94, 20) # psdm
|
||||
layer["vtl"] = (125, 44) # lvtn
|
||||
layer["vth"] = (78, 44) # hvtp (pmos only)
|
||||
layer["thkox"] = (8, 0)
|
||||
layer["poly"] = (66, 20)
|
||||
layer["contact"] = (66, 44) # licon1
|
||||
layer["npc"] = (95, 20) # npc (nitride cut)
|
||||
layer["li"] = (67, 20) # active li1
|
||||
layer["mcon"] = (67, 44) # mcon
|
||||
layer["m1"] = (68, 20) # met1
|
||||
layer["m1p"] = (68, 5) # met1 pin
|
||||
layer["via1"] = (68, 44) # via1
|
||||
layer["m2"] = (69, 20) # met2
|
||||
layer["m2p"] = (69, 5) # met2 pin
|
||||
layer["via2"] = (69, 44) # via2
|
||||
layer["m3"] = (70, 20) # met3
|
||||
layer["m3p"] = (70, 5) # met3 pin
|
||||
layer["via3"] = (70, 44) # via3
|
||||
layer["m4"] = (71, 20) # met4
|
||||
layer["m4p"] = (71, 5) # met4 pin
|
||||
layer["via4"] = (71, 44) # via4
|
||||
layer["m5"] = (72, 20) # met5
|
||||
layer["m5p"] = (72, 5) # met5 pin
|
||||
layer["boundary"]= (235, 4)
|
||||
# specific boundary type to define standard cell regions for DRC
|
||||
layer["stdc"] = (81, 4)
|
||||
layer["mem"] = (81, 2)
|
||||
# Not an official sky130 layer, but useful for router debug infos
|
||||
layer["text"]= (234, 5)
|
||||
# Excpected value according to sky130A tech file
|
||||
# If calibre is enabled, these will be swapped below
|
||||
#pin_purpose = 5
|
||||
label_purpose = 5
|
||||
#label_purpose = 16
|
||||
#pin_purpose = 16
|
||||
#label_purpose = 5
|
||||
|
||||
# pin_read purposes
|
||||
special_purposes = {layer["nwell"][0]: [layer["nwell"][1], 5, 59, 16]}
|
||||
#layer_override = {"VNB\x00": ["pwell",122]}
|
||||
layer_override = {"vnb": layer["pwellp"], "VNB": layer["pwellp"]}
|
||||
layer_override_name = {"vnb": "pwellp", "VNB": "pwellp"}
|
||||
layer_override_purpose = {122: (64, 59)}
|
||||
# Layer names for external PDKs
|
||||
layer_names = {}
|
||||
layer_names["active"] = "diff"
|
||||
layer_names["activep"] = "diff"
|
||||
layer_names["tap"] = "tap"
|
||||
layer_names["pwellp"] = "pwellp"
|
||||
layer_names["nwell"] = "nwell"
|
||||
layer_names["dnwell"] = "dnwell"
|
||||
layer_names["nimplant"]= "nsdm"
|
||||
layer_names["pimplant"]= "psdm"
|
||||
layer_names["vtl"] = "lvtn"
|
||||
layer_names["vth"] = "hvtp"
|
||||
layer_names["thkox"] = "thkox"
|
||||
layer_names["poly"] = "poly"
|
||||
layer_names["contact"] = "licon1"
|
||||
layer_names["li"] = "li1"
|
||||
layer_names["mcon"] = "mcon"
|
||||
layer_names["m1"] = "met1"
|
||||
layer_names["m1p"] = "met1"
|
||||
layer_names["via1"] = "via"
|
||||
layer_names["m2"] = "met2"
|
||||
layer_names["m2p"] = "met2"
|
||||
layer_names["via2"] = "via2"
|
||||
layer_names["m3"] = "met3"
|
||||
layer_names["m3p"] = "met3"
|
||||
layer_names["via3"] = "via3"
|
||||
layer_names["m4"] = "met4"
|
||||
layer_names["m4p"] = "met4"
|
||||
layer_names["via4"] = "via4"
|
||||
layer_names["m5p"] = "met5"
|
||||
layer_names["boundary"]= "boundary"
|
||||
layer_names["stdc"] = "areaid.standardc"
|
||||
layer_names["mem"] = "areaid.core"
|
||||
layer_names["text"] = "text"
|
||||
|
||||
|
||||
###################################################
|
||||
# DRC/LVS Rules Setup
|
||||
###################################################
|
||||
|
||||
# technology parameter
|
||||
parameter={}
|
||||
# difftap.2b
|
||||
parameter["min_tx_size"] = 0.150
|
||||
parameter["beta"] = 3
|
||||
|
||||
parameter["6T_inv_nmos_size"] = 0.205
|
||||
parameter["6T_inv_pmos_size"] = 0.09
|
||||
parameter["6T_access_size"] = 0.135
|
||||
|
||||
drc = d.design_rules("sky130")
|
||||
|
||||
# grid size
|
||||
drc["grid"] = 0.005
|
||||
|
||||
#DRC/LVS test set_up
|
||||
# Switching between calibre and magic can be useful for development,
|
||||
# it eventually should be deleted.
|
||||
NDA_PDK_ROOT = os.environ.get("NDA_PDK_ROOT", False)
|
||||
use_calibre = bool(NDA_PDK_ROOT)
|
||||
use_calibre = False
|
||||
use_klayout = False
|
||||
if use_calibre:
|
||||
# Correct order according to s8
|
||||
pin_purpose = 16
|
||||
label_purpose = 5
|
||||
|
||||
drc["drc_rules"] = NDA_PDK_ROOT + "/DRC/Calibre/s8_drcRules"
|
||||
drc["lvs_rules"] = NDA_PDK_ROOT + "/LVS/Calibre/lvs_s8_opts"
|
||||
drc["xrc_rules"] = NDA_PDK_ROOT + "/PEX/xRC/extLvsRules_s8_5lm"
|
||||
drc["layer_map"] = NDA_PDK_ROOT + "/VirtuosoOA/libs/technology_library/s8phirs_10r.layermap"
|
||||
|
||||
# minwidth_tx with contact (no dog bone transistors)
|
||||
# difftap.2b
|
||||
drc["minwidth_tx"] = 0.360
|
||||
drc["minlength_channel"] = 0.150
|
||||
|
||||
drc["pwell_to_nwell"] = 0
|
||||
# nwell.1 Minimum width of nwell/pwell
|
||||
drc.add_layer("nwell",
|
||||
width=0.840,
|
||||
spacing=1.270)
|
||||
|
||||
# poly.1a Minimum width of poly
|
||||
# poly.2 Minimum spacing of poly AND active
|
||||
drc.add_layer("poly",
|
||||
width=0.150,
|
||||
spacing=0.210)
|
||||
# poly.8
|
||||
drc["poly_extend_active"] = 0.13
|
||||
# Not a rule
|
||||
drc["poly_to_contact"] = 0
|
||||
# poly.7 Minimum enclosure of active around gate
|
||||
drc["active_enclose_gate"] = 0.075
|
||||
# poly.4 Minimum spacing of field poly to active
|
||||
drc["poly_to_active"] = 0.075
|
||||
# poly.2 Minimum spacing of field poly
|
||||
drc["poly_to_field_poly"] = 0.210
|
||||
|
||||
# difftap.1 Minimum width of active
|
||||
# difftap.3 Minimum spacing of active
|
||||
drc.add_layer("active",
|
||||
width=0.150,
|
||||
spacing=0.270)
|
||||
# difftap.8
|
||||
drc.add_enclosure("nwell",
|
||||
layer="active",
|
||||
enclosure=0.18,
|
||||
extension=0.18)
|
||||
|
||||
# nsd/psd.5a
|
||||
drc.add_enclosure("implant",
|
||||
layer="active",
|
||||
enclosure=0.125)
|
||||
|
||||
# Same as active enclosure?
|
||||
drc["implant_to_contact"] = 0.070
|
||||
# nsd/psd.1 nsd/psd.2
|
||||
drc.add_layer("implant",
|
||||
width=0.380,
|
||||
spacing=0.380,
|
||||
area=0.265)
|
||||
|
||||
# licon.1, licon.2
|
||||
drc.add_layer("contact",
|
||||
width=0.170,
|
||||
spacing=0.170)
|
||||
# licon.5c (0.06 extension), (licon.7 for extension)
|
||||
drc.add_enclosure("active",
|
||||
layer="contact",
|
||||
enclosure=0.040,
|
||||
extension=0.060)
|
||||
# licon.7
|
||||
drc["tap_extend_contact"] = 0.120
|
||||
|
||||
# licon.8 Minimum enclosure of poly around contact
|
||||
drc.add_enclosure("poly",
|
||||
layer="contact",
|
||||
enclosure=0.08,
|
||||
extension=0.08)
|
||||
# licon.11a
|
||||
drc["active_contact_to_gate"] = 0.050
|
||||
# npc.4 > licon.14 0.19 > licon.11a
|
||||
drc["poly_contact_to_gate"] = 0.270
|
||||
# licon.15
|
||||
drc["npc_enclose_poly"] = 0.1
|
||||
|
||||
# li.1, li.3
|
||||
drc.add_layer("li",
|
||||
width=0.170,
|
||||
spacing=0.170)
|
||||
|
||||
# licon.5
|
||||
drc.add_enclosure("li",
|
||||
layer="contact",
|
||||
enclosure=0,
|
||||
extension=0.080)
|
||||
|
||||
drc.add_enclosure("li",
|
||||
layer="mcon",
|
||||
enclosure=0,
|
||||
extension=0.080)
|
||||
# mcon.1, mcon.2
|
||||
drc.add_layer("mcon",
|
||||
width=0.170,
|
||||
spacing=0.210)
|
||||
|
||||
# m1.1 Minimum width of metal1
|
||||
# m1.2 Minimum spacing of metal1
|
||||
# m1.6 Minimum area of metal1
|
||||
drc.add_layer("m1",
|
||||
width=0.140,
|
||||
spacing=0.140,
|
||||
area=0.083)
|
||||
# m1.4 Minimum enclosure of metal1
|
||||
# m1.5 Minimum enclosure around contact on two opposite sides
|
||||
drc.add_enclosure("m1",
|
||||
layer="mcon",
|
||||
enclosure=0.030,
|
||||
extension=0.060)
|
||||
# via.4a Minimum enclosure around via1
|
||||
# via.5a Minimum enclosure around via1 on two opposite sides
|
||||
drc.add_enclosure("m1",
|
||||
layer="via1",
|
||||
enclosure=0.055,
|
||||
extension=0.085)
|
||||
|
||||
# via.1a Minimum width of via1
|
||||
# via.2 Minimum spacing of via1
|
||||
drc.add_layer("via1",
|
||||
width=0.150,
|
||||
spacing=0.170)
|
||||
|
||||
# m2.1 Minimum width of intermediate metal
|
||||
# m2.2 Minimum spacing of intermediate metal
|
||||
# m2.6 Minimum area of metal2
|
||||
drc.add_layer("m2",
|
||||
width=0.140,
|
||||
spacing=0.140,
|
||||
area=0.0676)
|
||||
# m2.4 Minimum enclosure around via1
|
||||
# m2.5 Minimum enclosure around via1 on two opposite sides
|
||||
drc.add_enclosure("m2",
|
||||
layer="via1",
|
||||
enclosure=0.055,
|
||||
extension=0.085)
|
||||
# via2.4 Minimum enclosure around via2
|
||||
# via2.5 Minimum enclosure around via2 on two opposite sides
|
||||
drc.add_enclosure("m2",
|
||||
layer="via2",
|
||||
enclosure=0.040,
|
||||
extension=0.085)
|
||||
|
||||
# via2.1a Minimum width of Via2
|
||||
# via2.2 Minimum spacing of Via2
|
||||
drc.add_layer("via2",
|
||||
width=0.200,
|
||||
spacing=0.200)
|
||||
|
||||
# m3.1 Minimum width of metal3
|
||||
# m3.2 Minimum spacing of metal3
|
||||
# m3.6 Minimum area of metal3
|
||||
drc.add_layer("m3",
|
||||
width=0.300,
|
||||
spacing=0.300,
|
||||
area=0.240)
|
||||
# m3.4 Minimum enclosure around via2
|
||||
drc.add_enclosure("m3",
|
||||
layer="via2",
|
||||
enclosure=0.065)
|
||||
# via3.4 Minimum enclosure around via3
|
||||
# via3.5 Minimum enclosure around via3 on two opposite sides
|
||||
drc.add_enclosure("m3",
|
||||
layer="via3",
|
||||
enclosure=0.060,
|
||||
extension=0.090)
|
||||
|
||||
# via3.1 Minimum width of Via3
|
||||
# via3.2 Minimum spacing of Via3
|
||||
drc.add_layer("via3",
|
||||
width=0.200,
|
||||
spacing=0.200)
|
||||
|
||||
# m4.1 Minimum width of metal4
|
||||
# m4.2 Minimum spacing of metal4
|
||||
# m4.7 Minimum area of metal4
|
||||
drc.add_layer("m4",
|
||||
width=0.300,
|
||||
spacing=0.300,
|
||||
area=0.240)
|
||||
# m4.3 Minimum enclosure around via3
|
||||
drc.add_enclosure("m4",
|
||||
layer="via3",
|
||||
enclosure=0.065)
|
||||
# FIXME: Wrong rule m4.3 Minimum enclosure around via3
|
||||
drc.add_enclosure("m4",
|
||||
layer="via4",
|
||||
enclosure=0.060)
|
||||
|
||||
|
||||
# via4.1 Minimum width of Via4
|
||||
# via4.2 Minimum spacing of Via4
|
||||
drc.add_layer("via4",
|
||||
width=0.800,
|
||||
spacing=0.800)
|
||||
|
||||
# FIXME: Wrong rules
|
||||
# m5.1 Minimum width of metal5
|
||||
# m5.2 Minimum spacing of metal5
|
||||
# m5.7 Minimum area of metal5
|
||||
drc.add_layer("m5",
|
||||
width=1.600,
|
||||
spacing=1.600,
|
||||
area=4.000)
|
||||
# m5.3 Minimum enclosure around via4
|
||||
drc.add_enclosure("m5",
|
||||
layer="via4",
|
||||
enclosure=0.310)
|
||||
|
||||
|
||||
|
||||
# Metal 5-10 are ommitted
|
||||
|
||||
###################################################
|
||||
# Spice Simulation Parameters
|
||||
###################################################
|
||||
|
||||
# spice info
|
||||
spice = {}
|
||||
spice["nmos"] = "sky130_fd_pr__nfet_01v8"
|
||||
spice["pmos"] = "sky130_fd_pr__pfet_01v8"
|
||||
spice["power"]="vccd1"
|
||||
spice["ground"]="vssd1"
|
||||
|
||||
# whether or not the device model is actually a subckt
|
||||
spice["device_prefix"] = "X"
|
||||
|
||||
spice["fet_libraries"] = { "TT": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "tt"]],
|
||||
"SS": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "ss"]],
|
||||
"FF": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "ff"]],
|
||||
"SF": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "sf"]],
|
||||
"FS": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "fs"]] }
|
||||
|
||||
# spice stimulus related variables
|
||||
spice["feasible_period"] = 10 # estimated feasible period in ns
|
||||
spice["supply_voltages"] = [1.7, 1.8, 1.9] # Supply voltage corners in [Volts]
|
||||
spice["nom_supply_voltage"] = 1.8 # Nominal supply voltage in [Volts]
|
||||
spice["rise_time"] = 0.005 # rise time in [Nano-seconds]
|
||||
spice["fall_time"] = 0.005 # fall time in [Nano-seconds]
|
||||
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
||||
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
|
||||
|
||||
# analytical delay parameters
|
||||
spice["nom_threshold"] = 0.49 # Typical Threshold voltage in Volts
|
||||
spice["wire_unit_r"] = 0.125 # Unit wire resistance in ohms/square
|
||||
spice["wire_unit_c"] = 0.134 # Unit wire capacitance ff/um^2
|
||||
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
|
||||
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff
|
||||
spice["dff_setup"] = 102.5391 # DFF setup time in ps
|
||||
spice["dff_hold"] = -56 # DFF hold time in ps
|
||||
spice["dff_in_cap"] = 6.89 # Input capacitance (D) [Femto-farad]
|
||||
spice["dff_out_cap"] = 6.89 # Output capacitance (Q) [Femto-farad]
|
||||
|
||||
# analytical power parameters, many values are temporary
|
||||
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
|
||||
spice["inv_leakage"] = 1 # Leakage power of inverter in nW
|
||||
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
|
||||
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
|
||||
spice["nand4_leakage"] = 1 # Leakage power of 4-input nand in nW
|
||||
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
|
||||
spice["dff_leakage"] = 1 # Leakage power of flop in nW
|
||||
|
||||
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
|
||||
|
||||
# Parameters related to sense amp enable timing and delay chain/RBL sizing
|
||||
parameter["le_tau"] = 2.25 # In pico-seconds.
|
||||
parameter["cap_relative_per_ff"] = 7.5 # Units of Relative Capacitance/ Femto-Farad
|
||||
parameter["dff_clk_cin"] = 30.6 # relative capacitance
|
||||
parameter["6tcell_wl_cin"] = 3 # relative capacitance
|
||||
parameter["min_inv_para_delay"] = 2.4 # Tau delay units
|
||||
parameter["sa_en_pmos_size"] = 0.72 # micro-meters
|
||||
parameter["sa_en_nmos_size"] = 0.27 # micro-meters
|
||||
parameter["sa_inv_pmos_size"] = 0.54 # micro-meters
|
||||
parameter["sa_inv_nmos_size"] = 0.27 # micro-meters
|
||||
parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance
|
||||
|
||||
###################################################
|
||||
# Technology Tool Preferences
|
||||
###################################################
|
||||
|
||||
if use_calibre:
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
elif use_klayout:
|
||||
drc_name = "klayout"
|
||||
lvs_name = "klayout"
|
||||
pex_name = "klayout"
|
||||
else:
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
||||
# This is used by uniqify to not rename the library cells
|
||||
library_prefix_name = "sky130_fd_bd_sram__"
|
||||
# List of cells to skip running DRC/LVS on directly
|
||||
# This will look for a maglef file and copy it over the mag file
|
||||
# before DRC after extraction
|
||||
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_ce
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_ce
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_cell
|
||||
# gds flatglob sky130_fd_bd_sram__sram_sp_cell_fom_serifs
|
||||
|
||||
flatglob = ["*_?mos_m*",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_fom_serifs",
|
||||
|
||||
"sky130_fd_bd_sram__sram_sp_cell",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_cell",
|
||||
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1_ce",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica_ce",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p_ce"]
|
||||
|
||||
blackbox_cells = ["sky130_fd_bd_sram__openram_dp_cell",
|
||||
"sky130_fd_bd_sram__openram_dp_cell_dummy",
|
||||
"sky130_fd_bd_sram__openram_dp_cell_replica",
|
||||
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_noblcon",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_noblcon",
|
||||
"sky130_fd_bd_sram__openram_sp_colend_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_colenda_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1a",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_dummy",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_dummy",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_colend",
|
||||
"sky130_fd_bd_sram__sram_sp_colend_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colend_p_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda_p_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_rowend",
|
||||
"sky130_fd_bd_sram__sram_sp_rowenda",
|
||||
"sky130_fd_bd_sram__openram_sp_rowend_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_rowenda_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_corner",
|
||||
"sky130_fd_bd_sram__sram_sp_cornera",
|
||||
"sky130_fd_bd_sram__sram_sp_cornerb",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrapa",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p"]
|
||||
|
|
@ -0,0 +1,848 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
import os
|
||||
from openram import drc as d
|
||||
|
||||
"""
|
||||
File containing the process technology parameters for Skywater 130nm.
|
||||
"""
|
||||
|
||||
###################################################
|
||||
# Custom modules
|
||||
###################################################
|
||||
|
||||
# This uses the default classes to instantiate module from
|
||||
# '$OPENRAM_HOME/compiler/modules'.
|
||||
# Using tech_modules['cellname'] you can override each class by providing a custom
|
||||
# implementation in '$OPENRAM_TECHDIR/modules/'
|
||||
# For example: tech_modules["contact"] = "contact_freepdk45"
|
||||
tech_modules = d.module_type()
|
||||
|
||||
# These modules have been hand designed and provided in this repository.
|
||||
tech_modules["nand2_dec"] = "nand2_dec"
|
||||
tech_modules["nand3_dec"] = "nand3_dec"
|
||||
tech_modules["nand4_dec"] = "nand4_dec"
|
||||
|
||||
# Override default OpenRAM modules to sky130 modules
|
||||
# These are for single port and dual port as a list,
|
||||
# or for both if there is no list,
|
||||
# or only applicable to one if there is no list.
|
||||
tech_modules["bitcell_1port"] = "sky130_bitcell"
|
||||
tech_modules["replica_bitcell_1port"] = "sky130_replica_bitcell"
|
||||
tech_modules["dummy_bitcell_1port"] = "sky130_dummy_bitcell"
|
||||
|
||||
tech_modules["replica_bitcell_2port"] = "replica_bitcell_2port"
|
||||
tech_modules["dummy_bitcell_2port"] = "dummy_bitcell_2port"
|
||||
tech_modules["bitcell_2port"] = "bitcell_2port"
|
||||
|
||||
tech_modules["bitcell_array"] = ["sky130_bitcell_array", "bitcell_array"]
|
||||
tech_modules["replica_bitcell_array"] = ["sky130_replica_bitcell_array", "replica_bitcell_array"]
|
||||
tech_modules["capped_replica_bitcell_array"] = ["sky130_capped_replica_bitcell_array", "capped_replica_bitcell_array"]
|
||||
tech_modules["dummy_array"] = ["sky130_dummy_array", "dummy_array"]
|
||||
|
||||
tech_modules["replica_column"] = ["sky130_replica_column", "replica_column"]
|
||||
|
||||
tech_modules["col_cap_array"] = ["sky130_col_cap_array", "col_cap_array"]
|
||||
tech_modules["col_cap"] = ["sky130_col_cap", "col_cap_bitcell_2port"]
|
||||
tech_modules["corner"] = ["sky130_corner", None]
|
||||
tech_modules["internal"] = ["sky130_internal", None]
|
||||
tech_modules["row_cap_array"] = ["sky130_row_cap_array", "row_cap_array"]
|
||||
tech_modules["row_cap"] = ["sky130_row_cap", "row_cap_bitcell_2port"]
|
||||
|
||||
# These modules are auto-generated from the nand decoders above and are not
|
||||
# found in this.
|
||||
tech_modules["buf_dec"] = "pbuf_dec"
|
||||
tech_modules["inv_dec"] = "pinv_dec"
|
||||
tech_modules["and2_dec"] = "and2_dec"
|
||||
tech_modules["and3_dec"] = "and3_dec"
|
||||
tech_modules["and4_dec"] = "and4_dec"
|
||||
|
||||
###################################################
|
||||
# Custom cell properties
|
||||
###################################################
|
||||
cell_properties = d.cell_properties()
|
||||
|
||||
cell_properties.bitcell_power_pin_directions = ("H", "H")
|
||||
|
||||
cell_properties.bitcell_1port.mirror.x = True
|
||||
cell_properties.bitcell_1port.mirror.y = True
|
||||
cell_properties.bitcell_1port.end_caps = True
|
||||
cell_properties.bitcell_1port.has_corners = True
|
||||
cell_properties.bitcell_1port.boundary_layer = "mem"
|
||||
cell_properties.bitcell_1port.port_order = ['bl', 'br', 'gnd', 'vdd', 'vpb', 'vnb', 'wl']
|
||||
cell_properties.bitcell_1port.port_types = ["OUTPUT", "OUTPUT", "GROUND", "POWER", "BIAS", "BIAS", "INPUT"]
|
||||
cell_properties.bitcell_1port.port_map = {'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'wl': 'WL',
|
||||
'vdd': 'VPWR',
|
||||
'vnb': 'VNB',
|
||||
'vpb': 'VPB',
|
||||
'gnd': 'VGND'}
|
||||
|
||||
cell_properties.bitcell_1port.wl_layer = "m2"
|
||||
cell_properties.bitcell_1port.bl_layer = "m1"
|
||||
cell_properties.bitcell_1port.vdd_layer = "m1"
|
||||
cell_properties.bitcell_1port.vdd_dir = "V"
|
||||
cell_properties.bitcell_1port.gnd_layer = "m2"
|
||||
cell_properties.bitcell_1port.gnd_dir = "H"
|
||||
|
||||
cell_properties.bitcell_2port.mirror.x = True
|
||||
cell_properties.bitcell_2port.mirror.y = True
|
||||
cell_properties.bitcell_2port.end_caps = True
|
||||
cell_properties.bitcell_2port.has_corners = True
|
||||
cell_properties.bitcell_2port.port_order = ['bl0', 'br0', 'bl1', 'br1', 'wl0', 'wl1', 'vdd', 'gnd']
|
||||
cell_properties.bitcell_2port.port_map = {'bl0': 'BL0',
|
||||
'br0': 'BR0',
|
||||
'bl1': 'BL1',
|
||||
'br1': 'BR1',
|
||||
'wl0': 'WL0',
|
||||
'wl1': 'WL1',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
cell_properties.bitcell_1port.wl_layer = "m2"
|
||||
cell_properties.bitcell_1port.vdd_layer = "m2"
|
||||
cell_properties.bitcell_1port.vdd_dir = "H"
|
||||
cell_properties.bitcell_1port.gnd_layer = "m2"
|
||||
cell_properties.bitcell_1port.gnd_dir = "H"
|
||||
cell_properties.bitcell_2port.wl_layer = "m2"
|
||||
cell_properties.bitcell_2port.vdd_layer = "m1"
|
||||
cell_properties.bitcell_2port.vdd_dir = "H"
|
||||
cell_properties.bitcell_2port.gnd_layer = "m2"
|
||||
cell_properties.bitcell_2port.gnd_dir = "H"
|
||||
|
||||
cell_properties.col_cap_1port_bitcell = d.cell(['bl', 'br', 'vdd', 'gnd', 'vpb', 'vnb', 'gate'],
|
||||
['INPUT', 'INPUT','POWER', 'GROUND', 'BIAS', 'BIAS', 'INPUT'],
|
||||
{'bl': 'bl',
|
||||
'br': 'br',
|
||||
'vdd': 'vdd',
|
||||
'gnd': 'gnd',
|
||||
'vnb': 'vnb',
|
||||
'vpb': 'vpb',
|
||||
'gate': 'gate'})
|
||||
cell_properties.col_cap_1port_bitcell.boundary_layer = "mem"
|
||||
|
||||
cell_properties.col_cap_1port_strap_power = d.cell(['vdd', 'vpb', 'vnb'],
|
||||
['POWER', 'BIAS', 'BIAS'],
|
||||
{'vnb': 'VNB',
|
||||
'vpb': 'VPB',
|
||||
'vdd': 'VPWR'})
|
||||
cell_properties.col_cap_1port_strap_power.boundary_layer = "mem"
|
||||
|
||||
cell_properties.col_cap_1port_strap_ground = d.cell(['gnd', 'vpb', 'vnb'],
|
||||
['GROUND', 'BIAS', 'BIAS'],
|
||||
{'vnb': 'VNB',
|
||||
'vpb': 'VPB',
|
||||
'gnd': 'VGND'})
|
||||
cell_properties.col_cap_1port_strap_ground.boundary_layer = "mem"
|
||||
|
||||
cell_properties.row_cap_1port_cell = d.cell(['vdd', 'wl'],
|
||||
['POWER', 'INPUT'],
|
||||
{'wl': 'WL',
|
||||
'vdd': 'VPWR'})
|
||||
cell_properties.row_cap_1port_cell.boundary_layer = "mem"
|
||||
|
||||
cell_properties.col_cap_2port.port_order = ['bl0', 'br0', 'bl1', 'br1', 'vdd']
|
||||
cell_properties.col_cap_2port.port_map = {'bl0': 'BL0',
|
||||
'br0': 'BR0',
|
||||
'bl1': 'BL1',
|
||||
'br1': 'BR1',
|
||||
'vdd': 'VDD'}
|
||||
|
||||
cell_properties.row_cap_2port.port_order = ['wl0', 'wl1', 'gnd']
|
||||
cell_properties.row_cap_2port.port_map = {'wl0': 'WL0',
|
||||
'wl1': 'WL1',
|
||||
'gnd': 'GND'}
|
||||
|
||||
|
||||
cell_properties.ptx.bin_spice_models = True
|
||||
cell_properties.ptx.model_is_subckt = True
|
||||
|
||||
cell_properties.pgate.add_implants = True
|
||||
|
||||
cell_properties.use_strap = True
|
||||
cell_properties.strap_module = "internal"
|
||||
cell_properties.strap_version = "wlstrap"
|
||||
|
||||
cell_properties.dff.port_order = ['D', 'Q', 'clk', 'vdd', 'gnd']
|
||||
cell_properties.dff.port_map = {'D': 'D',
|
||||
'Q': 'Q',
|
||||
'clk': 'CLK',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand2_dec.port_order = ['A', 'B', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand2_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand3_dec.port_order = ['A', 'B', 'C', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand3_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'C': 'C',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.nand4_dec.port_order = ['A', 'B', 'C', 'D', 'Z', 'vdd', 'gnd']
|
||||
cell_properties.nand4_dec.port_map = {'A': 'A',
|
||||
'B': 'B',
|
||||
'C': 'C',
|
||||
'D': 'D',
|
||||
'Z': 'Z',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.sense_amp.port_order = ['bl', 'br', 'dout', 'en', 'vdd', 'gnd']
|
||||
cell_properties.sense_amp.port_map = {'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'dout': 'DOUT',
|
||||
'en': 'EN',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
cell_properties.write_driver.port_order = ['din', 'bl', 'br', 'en', 'vdd', 'gnd']
|
||||
cell_properties.write_driver.port_map = {'din': 'DIN',
|
||||
'bl': 'BL',
|
||||
'br': 'BR',
|
||||
'en': 'EN',
|
||||
'vdd': 'VDD',
|
||||
'gnd': 'GND'}
|
||||
|
||||
|
||||
# You can override the GDS for custom cell using the following:
|
||||
# If it is a list, the first is single port and the second is dual port.
|
||||
# If it is string, it is used for both single and dual port.
|
||||
cell_properties.names["dff"] = "sky130_fd_bd_sram__openram_dff"
|
||||
cell_properties.names["nand2_dec"] = ["sky130_fd_bd_sram__openram_sp_nand2_dec", "sky130_fd_bd_sram__openram_dp_nand2_dec"]
|
||||
cell_properties.names["nand3_dec"] = ["sky130_fd_bd_sram__openram_sp_nand3_dec", "sky130_fd_bd_sram__openram_dp_nand3_dec"]
|
||||
cell_properties.names["nand4_dec"] = ["sky130_fd_bd_sram__openram_sp_nand4_dec", "sky130_fd_bd_sram__openram_dp_nand4_dec"]
|
||||
|
||||
cell_properties.names["bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell"
|
||||
cell_properties.names["dummy_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_dummy"
|
||||
cell_properties.names["replica_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_replica"
|
||||
cell_properties.names["col_cap_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_cap_col"
|
||||
cell_properties.names["row_cap_bitcell_2port"] = "sky130_fd_bd_sram__openram_dp_cell_cap_row"
|
||||
cell_properties.names["sense_amp"] = "sky130_fd_bd_sram__openram_sense_amp"
|
||||
cell_properties.names["write_driver"] = "sky130_fd_bd_sram__openram_write_driver"
|
||||
|
||||
array_row_multiple = 2
|
||||
array_col_multiple = 2
|
||||
|
||||
###################################################
|
||||
# Custom layer properties
|
||||
###################################################
|
||||
layer_properties = d.layer_properties()
|
||||
layer_properties.hierarchical_decoder.bus_layer = "m1"
|
||||
layer_properties.hierarchical_decoder.bus_directions = "nonpref"
|
||||
layer_properties.hierarchical_decoder.input_layer = "li"
|
||||
layer_properties.hierarchical_decoder.output_layer = "m2"
|
||||
layer_properties.hierarchical_decoder.vertical_supply = True
|
||||
|
||||
layer_properties.hierarchical_predecode.bus_layer = "m1"
|
||||
layer_properties.hierarchical_predecode.bus_directions = "nonpref"
|
||||
# This is added to allow the column decoder connections on m2
|
||||
layer_properties.hierarchical_predecode.bus_pitch_factor = 1.2
|
||||
layer_properties.hierarchical_predecode.bus_space_factor = 1.5
|
||||
layer_properties.hierarchical_predecode.input_layer = "li"
|
||||
layer_properties.hierarchical_predecode.output_layer = "m2"
|
||||
layer_properties.hierarchical_predecode.vertical_supply = True
|
||||
layer_properties.hierarchical_predecode.force_horizontal_input_contact = True
|
||||
|
||||
layer_properties.bank.stack = "m2_stack"
|
||||
layer_properties.bank.pitch = "m3_pitch"
|
||||
|
||||
layer_properties.column_mux_array.select_layer = "m3"
|
||||
layer_properties.column_mux_array.bitline_layer = "m1"
|
||||
|
||||
layer_properties.port_address.supply_offset = True
|
||||
|
||||
layer_properties.port_data.enable_layer = "m1"
|
||||
layer_properties.port_data.channel_route_bitlines = False
|
||||
|
||||
layer_properties.replica_column.even_rows = True
|
||||
|
||||
layer_properties.wordline_driver.vertical_supply = True
|
||||
|
||||
layer_properties.global_wordline_layer = "m5"
|
||||
|
||||
|
||||
###################################################
|
||||
# Discrete tx bins
|
||||
###################################################
|
||||
# enforce that tx sizes are within 25% of requested size after fingering.
|
||||
accuracy_requirement = 0.75
|
||||
nmos_bins = {
|
||||
0.15 : [0.36, 0.39, 0.42, 0.52, 0.54, 0.55, 0.58, 0.6, 0.61, 0.64, 0.65, 0.74, 0.84, 1.0, 1.26, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
0.18 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
0.25 : [0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
0.5 : [0.42, 0.55, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
1.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
2.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
4.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
8.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0],
|
||||
20.0 : [0.42, 0.65, 1.0, 3.0, 5.0, 7.0]
|
||||
}
|
||||
|
||||
pmos_bins = {
|
||||
0.15 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12, 1.26, 1.65, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
1.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
2.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
4.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
8.0 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
0.17 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12],
|
||||
0.18 : [0.42, 0.55, 0.64, 0.84, 1.0, 1.12, 1.26, 1.68, 2.0, 3.0, 5.0, 7.0],
|
||||
0.25 : [1.0, 3.0, 5.0, 7.0],
|
||||
0.5 : [0.42, 0.55, 1.0, 3.0, 5.0, 7.0],
|
||||
20.0 : [0.42]
|
||||
}
|
||||
###################################################
|
||||
# GDS file info
|
||||
###################################################
|
||||
GDS = {}
|
||||
# gds units
|
||||
# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first
|
||||
# is the size of a database unit in user units. The second is the size
|
||||
# of a database unit in meters. For example, if your library was
|
||||
# created with the default units (user unit = 1 um and 1000 database
|
||||
# units per user unit), then the first number would be 0.001 and the
|
||||
# second number would be 10-9. Typically, the first number is less than
|
||||
# 1, since you use more than 1 database unit per user unit. To
|
||||
# calculate the size of a user unit in meters, divide the second number
|
||||
# by the first."
|
||||
GDS["unit"] = (0.001, 1e-9)
|
||||
#GDS["unit"]=(0.001, 1e-6)
|
||||
|
||||
###################################################
|
||||
# Interconnect stacks
|
||||
###################################################
|
||||
|
||||
poly_stack = ("poly", "contact", "li")
|
||||
active_stack = ("active", "contact", "li")
|
||||
li_stack = ("li", "mcon", "m1")
|
||||
m1_stack = ("m1", "via1", "m2")
|
||||
m2_stack = ("m2", "via2", "m3")
|
||||
m3_stack = ("m3", "via3", "m4")
|
||||
m4_stack = ("m4", "via4", "m5")
|
||||
|
||||
lef_rom_interconnect = ["m1", "m2", "m3", "m4"]
|
||||
|
||||
layer_indices = {"poly": 0,
|
||||
"active": 0,
|
||||
"nwell": 0,
|
||||
"li": 1,
|
||||
"m1": 2,
|
||||
"m2": 3,
|
||||
"m3": 4,
|
||||
"m4": 5,
|
||||
"m5": 6}
|
||||
|
||||
# The FEOL stacks get us up to m1
|
||||
feol_stacks = [poly_stack,
|
||||
active_stack,
|
||||
li_stack]
|
||||
|
||||
# The BEOL stacks are m1 and up
|
||||
beol_stacks = [m1_stack,
|
||||
m2_stack,
|
||||
m3_stack,
|
||||
m4_stack]
|
||||
|
||||
layer_stacks = feol_stacks + beol_stacks
|
||||
|
||||
preferred_directions = {"poly": "V",
|
||||
"active": "V",
|
||||
"li": "V",
|
||||
"m1": "H",
|
||||
"m2": "V",
|
||||
"m3": "H",
|
||||
"m4": "V",
|
||||
"m5": "H"}
|
||||
|
||||
###################################################
|
||||
# GDS Layer Map
|
||||
###################################################
|
||||
|
||||
|
||||
layer = {}
|
||||
layer["active"] = (65, 20) # diff
|
||||
layer["activep"] = (65, 20) # diff
|
||||
layer["tap"] = (65, 44) # tap
|
||||
layer["pwellp"] = (122,16)
|
||||
layer["nwell"] = (64, 20) # nwell
|
||||
layer["dnwell"] = (64,18)
|
||||
layer["nimplant"]= (93, 44) # nsdm
|
||||
layer["pimplant"]= (94, 20) # psdm
|
||||
layer["vtl"] = (125, 44) # lvtn
|
||||
layer["vth"] = (78, 44) # hvtp (pmos only)
|
||||
layer["thkox"] = (8, 0)
|
||||
layer["poly"] = (66, 20)
|
||||
layer["contact"] = (66, 44) # licon1
|
||||
layer["npc"] = (95, 20) # npc (nitride cut)
|
||||
layer["li"] = (67, 20) # active li1
|
||||
layer["mcon"] = (67, 44) # mcon
|
||||
layer["m1"] = (68, 20) # met1
|
||||
layer["m1p"] = (68, 5) # met1 pin
|
||||
layer["via1"] = (68, 44) # via1
|
||||
layer["m2"] = (69, 20) # met2
|
||||
layer["m2p"] = (69, 5) # met2 pin
|
||||
layer["via2"] = (69, 44) # via2
|
||||
layer["m3"] = (70, 20) # met3
|
||||
layer["m3p"] = (70, 5) # met3 pin
|
||||
layer["via3"] = (70, 44) # via3
|
||||
layer["m4"] = (71, 20) # met4
|
||||
layer["m4p"] = (71, 5) # met4 pin
|
||||
layer["via4"] = (71, 44) # via4
|
||||
layer["m5"] = (72, 20) # met5
|
||||
layer["m5p"] = (72, 5) # met5 pin
|
||||
layer["boundary"]= (235, 4)
|
||||
# specific boundary type to define standard cell regions for DRC
|
||||
layer["stdc"] = (81, 4)
|
||||
layer["mem"] = (81, 2)
|
||||
# Not an official sky130 layer, but useful for router debug infos
|
||||
layer["text"]= (234, 5)
|
||||
# Excpected value according to sky130A tech file
|
||||
# If calibre is enabled, these will be swapped below
|
||||
#pin_purpose = 5
|
||||
label_purpose = 5
|
||||
#label_purpose = 16
|
||||
#pin_purpose = 16
|
||||
#label_purpose = 5
|
||||
|
||||
# pin_read purposes
|
||||
special_purposes = {layer["nwell"][0]: [layer["nwell"][1], 5, 59, 16]}
|
||||
#layer_override = {"VNB\x00": ["pwell",122]}
|
||||
layer_override = {"vnb": layer["pwellp"], "VNB": layer["pwellp"]}
|
||||
layer_override_name = {"vnb": "pwellp", "VNB": "pwellp"}
|
||||
layer_override_purpose = {122: (64, 59)}
|
||||
# Layer names for external PDKs
|
||||
layer_names = {}
|
||||
layer_names["active"] = "diff"
|
||||
layer_names["activep"] = "diff"
|
||||
layer_names["tap"] = "tap"
|
||||
layer_names["pwellp"] = "pwellp"
|
||||
layer_names["nwell"] = "nwell"
|
||||
layer_names["dnwell"] = "dnwell"
|
||||
layer_names["nimplant"]= "nsdm"
|
||||
layer_names["pimplant"]= "psdm"
|
||||
layer_names["vtl"] = "lvtn"
|
||||
layer_names["vth"] = "hvtp"
|
||||
layer_names["thkox"] = "thkox"
|
||||
layer_names["poly"] = "poly"
|
||||
layer_names["contact"] = "licon1"
|
||||
layer_names["li"] = "li1"
|
||||
layer_names["mcon"] = "mcon"
|
||||
layer_names["m1"] = "met1"
|
||||
layer_names["m1p"] = "met1"
|
||||
layer_names["via1"] = "via"
|
||||
layer_names["m2"] = "met2"
|
||||
layer_names["m2p"] = "met2"
|
||||
layer_names["via2"] = "via2"
|
||||
layer_names["m3"] = "met3"
|
||||
layer_names["m3p"] = "met3"
|
||||
layer_names["via3"] = "via3"
|
||||
layer_names["m4"] = "met4"
|
||||
layer_names["m4p"] = "met4"
|
||||
layer_names["via4"] = "via4"
|
||||
layer_names["m5p"] = "met5"
|
||||
layer_names["boundary"]= "boundary"
|
||||
layer_names["stdc"] = "areaid.standardc"
|
||||
layer_names["mem"] = "areaid.core"
|
||||
layer_names["text"] = "text"
|
||||
|
||||
|
||||
###################################################
|
||||
# DRC/LVS Rules Setup
|
||||
###################################################
|
||||
|
||||
# technology parameter
|
||||
parameter={}
|
||||
# difftap.2b
|
||||
parameter["min_tx_size"] = 0.150
|
||||
parameter["beta"] = 3
|
||||
|
||||
parameter["6T_inv_nmos_size"] = 0.205
|
||||
parameter["6T_inv_pmos_size"] = 0.09
|
||||
parameter["6T_access_size"] = 0.135
|
||||
|
||||
drc = d.design_rules("sky130")
|
||||
|
||||
# grid size
|
||||
drc["grid"] = 0.005
|
||||
|
||||
#DRC/LVS test set_up
|
||||
# Switching between calibre and magic can be useful for development,
|
||||
# it eventually should be deleted.
|
||||
NDA_PDK_ROOT = os.environ.get("NDA_PDK_ROOT", False)
|
||||
use_calibre = bool(NDA_PDK_ROOT)
|
||||
use_calibre = False
|
||||
use_klayout = False
|
||||
if use_calibre:
|
||||
# Correct order according to s8
|
||||
pin_purpose = 16
|
||||
label_purpose = 5
|
||||
|
||||
drc["drc_rules"] = NDA_PDK_ROOT + "/DRC/Calibre/s8_drcRules"
|
||||
drc["lvs_rules"] = NDA_PDK_ROOT + "/LVS/Calibre/lvs_s8_opts"
|
||||
drc["xrc_rules"] = NDA_PDK_ROOT + "/PEX/xRC/extLvsRules_s8_5lm"
|
||||
drc["layer_map"] = NDA_PDK_ROOT + "/VirtuosoOA/libs/technology_library/s8phirs_10r.layermap"
|
||||
|
||||
# minwidth_tx with contact (no dog bone transistors)
|
||||
# difftap.2b
|
||||
drc["minwidth_tx"] = 0.360
|
||||
drc["minlength_channel"] = 0.150
|
||||
|
||||
drc["pwell_to_nwell"] = 0
|
||||
# nwell.1 Minimum width of nwell/pwell
|
||||
drc.add_layer("nwell",
|
||||
width=0.840,
|
||||
spacing=1.270)
|
||||
|
||||
# poly.1a Minimum width of poly
|
||||
# poly.2 Minimum spacing of poly AND active
|
||||
drc.add_layer("poly",
|
||||
width=0.150,
|
||||
spacing=0.210)
|
||||
# poly.8
|
||||
drc["poly_extend_active"] = 0.13
|
||||
# Not a rule
|
||||
drc["poly_to_contact"] = 0
|
||||
# poly.7 Minimum enclosure of active around gate
|
||||
drc["active_enclose_gate"] = 0.075
|
||||
# poly.4 Minimum spacing of field poly to active
|
||||
drc["poly_to_active"] = 0.075
|
||||
# poly.2 Minimum spacing of field poly
|
||||
drc["poly_to_field_poly"] = 0.210
|
||||
|
||||
# difftap.1 Minimum width of active
|
||||
# difftap.3 Minimum spacing of active
|
||||
drc.add_layer("active",
|
||||
width=0.150,
|
||||
spacing=0.270)
|
||||
# difftap.8
|
||||
drc.add_enclosure("nwell",
|
||||
layer="active",
|
||||
enclosure=0.18,
|
||||
extension=0.18)
|
||||
|
||||
# nsd/psd.5a
|
||||
drc.add_enclosure("implant",
|
||||
layer="active",
|
||||
enclosure=0.125)
|
||||
|
||||
# Same as active enclosure?
|
||||
drc["implant_to_contact"] = 0.070
|
||||
# nsd/psd.1 nsd/psd.2
|
||||
drc.add_layer("implant",
|
||||
width=0.380,
|
||||
spacing=0.380,
|
||||
area=0.265)
|
||||
|
||||
# licon.1, licon.2
|
||||
drc.add_layer("contact",
|
||||
width=0.170,
|
||||
spacing=0.170)
|
||||
# licon.5c (0.06 extension), (licon.7 for extension)
|
||||
drc.add_enclosure("active",
|
||||
layer="contact",
|
||||
enclosure=0.040,
|
||||
extension=0.060)
|
||||
# licon.7
|
||||
drc["tap_extend_contact"] = 0.120
|
||||
|
||||
# licon.8 Minimum enclosure of poly around contact
|
||||
drc.add_enclosure("poly",
|
||||
layer="contact",
|
||||
enclosure=0.08,
|
||||
extension=0.08)
|
||||
# licon.11a
|
||||
drc["active_contact_to_gate"] = 0.050
|
||||
# npc.4 > licon.14 0.19 > licon.11a
|
||||
drc["poly_contact_to_gate"] = 0.270
|
||||
# licon.15
|
||||
drc["npc_enclose_poly"] = 0.1
|
||||
|
||||
# li.1, li.3
|
||||
drc.add_layer("li",
|
||||
width=0.170,
|
||||
spacing=0.170)
|
||||
|
||||
# licon.5
|
||||
drc.add_enclosure("li",
|
||||
layer="contact",
|
||||
enclosure=0,
|
||||
extension=0.080)
|
||||
|
||||
drc.add_enclosure("li",
|
||||
layer="mcon",
|
||||
enclosure=0,
|
||||
extension=0.080)
|
||||
# mcon.1, mcon.2
|
||||
drc.add_layer("mcon",
|
||||
width=0.170,
|
||||
spacing=0.210)
|
||||
|
||||
# m1.1 Minimum width of metal1
|
||||
# m1.2 Minimum spacing of metal1
|
||||
# m1.6 Minimum area of metal1
|
||||
drc.add_layer("m1",
|
||||
width=0.140,
|
||||
spacing=0.140,
|
||||
area=0.083)
|
||||
# m1.4 Minimum enclosure of metal1
|
||||
# m1.5 Minimum enclosure around contact on two opposite sides
|
||||
drc.add_enclosure("m1",
|
||||
layer="mcon",
|
||||
enclosure=0.030,
|
||||
extension=0.060)
|
||||
# via.4a Minimum enclosure around via1
|
||||
# via.5a Minimum enclosure around via1 on two opposite sides
|
||||
drc.add_enclosure("m1",
|
||||
layer="via1",
|
||||
enclosure=0.055,
|
||||
extension=0.085)
|
||||
|
||||
# via.1a Minimum width of via1
|
||||
# via.2 Minimum spacing of via1
|
||||
drc.add_layer("via1",
|
||||
width=0.150,
|
||||
spacing=0.170)
|
||||
|
||||
# m2.1 Minimum width of intermediate metal
|
||||
# m2.2 Minimum spacing of intermediate metal
|
||||
# m2.6 Minimum area of metal2
|
||||
drc.add_layer("m2",
|
||||
width=0.140,
|
||||
spacing=0.140,
|
||||
area=0.0676)
|
||||
# m2.4 Minimum enclosure around via1
|
||||
# m2.5 Minimum enclosure around via1 on two opposite sides
|
||||
drc.add_enclosure("m2",
|
||||
layer="via1",
|
||||
enclosure=0.055,
|
||||
extension=0.085)
|
||||
# via2.4 Minimum enclosure around via2
|
||||
# via2.5 Minimum enclosure around via2 on two opposite sides
|
||||
drc.add_enclosure("m2",
|
||||
layer="via2",
|
||||
enclosure=0.040,
|
||||
extension=0.085)
|
||||
|
||||
# via2.1a Minimum width of Via2
|
||||
# via2.2 Minimum spacing of Via2
|
||||
drc.add_layer("via2",
|
||||
width=0.200,
|
||||
spacing=0.200)
|
||||
|
||||
# m3.1 Minimum width of metal3
|
||||
# m3.2 Minimum spacing of metal3
|
||||
# m3.6 Minimum area of metal3
|
||||
drc.add_layer("m3",
|
||||
width=0.300,
|
||||
spacing=0.300,
|
||||
area=0.240)
|
||||
# m3.4 Minimum enclosure around via2
|
||||
drc.add_enclosure("m3",
|
||||
layer="via2",
|
||||
enclosure=0.065)
|
||||
# via3.4 Minimum enclosure around via3
|
||||
# via3.5 Minimum enclosure around via3 on two opposite sides
|
||||
drc.add_enclosure("m3",
|
||||
layer="via3",
|
||||
enclosure=0.060,
|
||||
extension=0.090)
|
||||
|
||||
# via3.1 Minimum width of Via3
|
||||
# via3.2 Minimum spacing of Via3
|
||||
drc.add_layer("via3",
|
||||
width=0.200,
|
||||
spacing=0.200)
|
||||
|
||||
# m4.1 Minimum width of metal4
|
||||
# m4.2 Minimum spacing of metal4
|
||||
# m4.7 Minimum area of metal4
|
||||
drc.add_layer("m4",
|
||||
width=0.300,
|
||||
spacing=0.300,
|
||||
area=0.240)
|
||||
# m4.3 Minimum enclosure around via3
|
||||
drc.add_enclosure("m4",
|
||||
layer="via3",
|
||||
enclosure=0.065)
|
||||
# FIXME: Wrong rule m4.3 Minimum enclosure around via3
|
||||
drc.add_enclosure("m4",
|
||||
layer="via4",
|
||||
enclosure=0.060)
|
||||
|
||||
|
||||
# via4.1 Minimum width of Via4
|
||||
# via4.2 Minimum spacing of Via4
|
||||
drc.add_layer("via4",
|
||||
width=0.800,
|
||||
spacing=0.800)
|
||||
|
||||
# FIXME: Wrong rules
|
||||
# m5.1 Minimum width of metal5
|
||||
# m5.2 Minimum spacing of metal5
|
||||
# m5.7 Minimum area of metal5
|
||||
drc.add_layer("m5",
|
||||
width=1.600,
|
||||
spacing=1.600,
|
||||
area=4.000)
|
||||
# m5.3 Minimum enclosure around via4
|
||||
drc.add_enclosure("m5",
|
||||
layer="via4",
|
||||
enclosure=0.310)
|
||||
|
||||
|
||||
|
||||
# Metal 5-10 are ommitted
|
||||
|
||||
###################################################
|
||||
# Spice Simulation Parameters
|
||||
###################################################
|
||||
|
||||
# spice info
|
||||
spice = {}
|
||||
spice["nmos"] = "sky130_fd_pr__nfet_01v8"
|
||||
spice["pmos"] = "sky130_fd_pr__pfet_01v8"
|
||||
spice["power"]="vccd1"
|
||||
spice["ground"]="vssd1"
|
||||
|
||||
# whether or not the device model is actually a subckt
|
||||
spice["device_prefix"] = "X"
|
||||
|
||||
spice["fet_libraries"] = { "TT": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "tt"]],
|
||||
"SS": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "ss"]],
|
||||
"FF": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "ff"]],
|
||||
"SF": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "sf"]],
|
||||
"FS": [[os.environ.get("SPICE_MODEL_DIR") + "/sky130.lib.spice", "fs"]] }
|
||||
|
||||
# spice stimulus related variables
|
||||
spice["feasible_period"] = 10 # estimated feasible period in ns
|
||||
spice["supply_voltages"] = [1.7, 1.8, 1.9] # Supply voltage corners in [Volts]
|
||||
spice["nom_supply_voltage"] = 1.8 # Nominal supply voltage in [Volts]
|
||||
spice["rise_time"] = 0.005 # rise time in [Nano-seconds]
|
||||
spice["fall_time"] = 0.005 # fall time in [Nano-seconds]
|
||||
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
|
||||
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
|
||||
|
||||
# analytical delay parameters
|
||||
spice["nom_threshold"] = 0.49 # Typical Threshold voltage in Volts
|
||||
spice["wire_unit_r"] = 0.125 # Unit wire resistance in ohms/square
|
||||
spice["wire_unit_c"] = 0.134 # Unit wire capacitance ff/um^2
|
||||
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
|
||||
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff
|
||||
spice["dff_setup"] = 102.5391 # DFF setup time in ps
|
||||
spice["dff_hold"] = -56 # DFF hold time in ps
|
||||
spice["dff_in_cap"] = 6.89 # Input capacitance (D) [Femto-farad]
|
||||
spice["dff_out_cap"] = 6.89 # Output capacitance (Q) [Femto-farad]
|
||||
|
||||
# analytical power parameters, many values are temporary
|
||||
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
|
||||
spice["inv_leakage"] = 1 # Leakage power of inverter in nW
|
||||
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
|
||||
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
|
||||
spice["nand4_leakage"] = 1 # Leakage power of 4-input nand in nW
|
||||
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
|
||||
spice["dff_leakage"] = 1 # Leakage power of flop in nW
|
||||
|
||||
spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
|
||||
|
||||
# Parameters related to sense amp enable timing and delay chain/RBL sizing
|
||||
parameter["le_tau"] = 2.25 # In pico-seconds.
|
||||
parameter["cap_relative_per_ff"] = 7.5 # Units of Relative Capacitance/ Femto-Farad
|
||||
parameter["dff_clk_cin"] = 30.6 # relative capacitance
|
||||
parameter["6tcell_wl_cin"] = 3 # relative capacitance
|
||||
parameter["min_inv_para_delay"] = 2.4 # Tau delay units
|
||||
parameter["sa_en_pmos_size"] = 0.72 # micro-meters
|
||||
parameter["sa_en_nmos_size"] = 0.27 # micro-meters
|
||||
parameter["sa_inv_pmos_size"] = 0.54 # micro-meters
|
||||
parameter["sa_inv_nmos_size"] = 0.27 # micro-meters
|
||||
parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance
|
||||
|
||||
###################################################
|
||||
# Technology Tool Preferences
|
||||
###################################################
|
||||
|
||||
if use_calibre:
|
||||
drc_name = "calibre"
|
||||
lvs_name = "calibre"
|
||||
pex_name = "calibre"
|
||||
elif use_klayout:
|
||||
drc_name = "klayout"
|
||||
lvs_name = "klayout"
|
||||
pex_name = "klayout"
|
||||
else:
|
||||
drc_name = "magic"
|
||||
lvs_name = "netgen"
|
||||
pex_name = "magic"
|
||||
|
||||
|
||||
# This is used by uniqify to not rename the library cells
|
||||
library_prefix_name = "sky130_fd_bd_sram__"
|
||||
# List of cells to skip running DRC/LVS on directly
|
||||
# This will look for a maglef file and copy it over the mag file
|
||||
# before DRC after extraction
|
||||
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_ce
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_ce
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell
|
||||
# gds flatglob sky130_fd_bd_sram__openram_sp_cell_opt1a_cell
|
||||
# gds flatglob sky130_fd_bd_sram__sram_sp_cell_fom_serifs
|
||||
|
||||
flatglob = ["*_?mos_m*",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_fom_serifs",
|
||||
|
||||
"sky130_fd_bd_sram__sram_sp_cell",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica_cell",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_cell",
|
||||
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1_ce",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica_ce",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p_ce"]
|
||||
|
||||
blackbox_cells = ["sky130_fd_bd_sram__openram_dp_cell",
|
||||
"sky130_fd_bd_sram__openram_dp_cell_dummy",
|
||||
"sky130_fd_bd_sram__openram_dp_cell_replica",
|
||||
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_noblcon",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_noblcon",
|
||||
"sky130_fd_bd_sram__openram_sp_colend_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_colenda_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1a",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_dummy",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_dummy",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_cell_opt1",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_cell_opt1a_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_colend",
|
||||
"sky130_fd_bd_sram__sram_sp_colend_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colend_p_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_colenda_p_cent",
|
||||
"sky130_fd_bd_sram__sram_sp_rowend",
|
||||
"sky130_fd_bd_sram__sram_sp_rowenda",
|
||||
"sky130_fd_bd_sram__openram_sp_rowend_replica",
|
||||
"sky130_fd_bd_sram__openram_sp_rowenda_replica",
|
||||
"sky130_fd_bd_sram__sram_sp_corner",
|
||||
"sky130_fd_bd_sram__sram_sp_cornera",
|
||||
"sky130_fd_bd_sram__sram_sp_cornerb",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrapa",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p_ce",
|
||||
"sky130_fd_bd_sram__sram_sp_wlstrap_p"]
|
||||
Loading…
Reference in New Issue