Merge branch 'dev' into custom_mod

This commit is contained in:
Jesse Cirimelli-Low 2020-04-01 15:35:33 -07:00
commit cdf0315a90
8 changed files with 106 additions and 93 deletions

View File

@ -9,6 +9,7 @@ import collections
import geometry import geometry
import gdsMill import gdsMill
import debug import debug
from math import sqrt
from tech import drc, GDS from tech import drc, GDS
from tech import layer as techlayer from tech import layer as techlayer
from tech import layer_stacks from tech import layer_stacks
@ -1193,11 +1194,9 @@ class layout():
"supply router." "supply router."
.format(name,inst.name,self.pwr_grid_layer)) .format(name,inst.name,self.pwr_grid_layer))
def add_power_pin(self, name, loc, size=[1, 1], vertical=False, start_layer="m1"): def add_power_pin(self, name, loc, size=[1, 1], vertical=False, start_layer="m1"):
""" """
Add a single power pin from the lowest power_grid layer down to M1 at Add a single power pin from the lowest power_grid layer down to M1 (or li) at
the given center location. The starting layer is specified to determine the given center location. The starting layer is specified to determine
which vias are needed. which vias are needed.
""" """
@ -1211,23 +1210,27 @@ class layout():
else: else:
direction = None direction = None
via = self.add_via_stack_center(from_layer=start_layer, via = self.add_via_stack_center(from_layer=start_layer,
to_layer=self.pwr_grid_layer, to_layer=self.pwr_grid_layer,
size=size, size=size,
offset=loc, offset=loc,
direction=direction) direction=direction)
if start_layer == self.pwr_grid_layer: if start_layer == self.pwr_grid_layer:
self.add_layout_pin_rect_center(text=name, self.add_layout_pin_rect_center(text=name,
layer=self.pwr_grid_layer, layer=self.pwr_grid_layer,
offset=loc) offset=loc)
else: else:
# Hack for min area
if OPTS.tech_name == "s8":
height = width = sqrt(drc["minarea_m3"])
else:
width = via.width
height = via.height
self.add_layout_pin_rect_center(text=name, self.add_layout_pin_rect_center(text=name,
layer=self.pwr_grid_layer, layer=self.pwr_grid_layer,
offset=loc, offset=loc,
width=via.width, width=width,
height=via.height) height=height)
def add_power_ring(self, bbox): def add_power_ring(self, bbox):
""" """

View File

@ -13,6 +13,7 @@ import debug
from globals import OPTS from globals import OPTS
import logical_effort import logical_effort
class sense_amp_array(design.design): class sense_amp_array(design.design):
""" """
Array of sense amplifiers to read the bitlines through the column mux. Array of sense amplifiers to read the bitlines through the column mux.
@ -69,7 +70,7 @@ class sense_amp_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self): def add_pins(self):
for i in range(0,self.word_size): for i in range(0, self.word_size):
self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT") self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT")
self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT") self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT")
self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT") self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT")
@ -88,7 +89,7 @@ class sense_amp_array(design.design):
def create_sense_amp_array(self): def create_sense_amp_array(self):
self.local_insts = [] self.local_insts = []
for i in range(0,self.word_size): for i in range(0, self.word_size):
name = "sa_d{0}".format(i) name = "sa_d{0}".format(i)
self.local_insts.append(self.add_inst(name=name, self.local_insts.append(self.add_inst(name=name,
@ -105,7 +106,7 @@ class sense_amp_array(design.design):
else: else:
amp_spacing = self.amp.width * self.words_per_row amp_spacing = self.amp.width * self.words_per_row
for i in range(0,self.word_size): for i in range(0, self.word_size):
xoffset = amp_spacing * i xoffset = amp_spacing * i
# align the xoffset to the grid of bitcells. This way we # align the xoffset to the grid of bitcells. This way we
@ -119,20 +120,19 @@ class sense_amp_array(design.design):
mirror = "" mirror = ""
amp_position = vector(xoffset, 0) amp_position = vector(xoffset, 0)
self.local_insts[i].place(offset=amp_position,mirror=mirror) self.local_insts[i].place(offset=amp_position, mirror=mirror)
def add_layout_pins(self): def add_layout_pins(self):
for i in range(len(self.local_insts)): for i in range(len(self.local_insts)):
inst = self.local_insts[i] inst = self.local_insts[i]
self.add_power_pin(name = "gnd", self.add_power_pin(name="gnd",
loc = inst.get_pin("gnd").center(), loc=inst.get_pin("gnd").center(),
start_layer="m2", start_layer="m2",
vertical=True) vertical=True)
self.add_power_pin(name = "vdd", self.add_power_pin(name="vdd",
loc = inst.get_pin("vdd").center(), loc=inst.get_pin("vdd").center(),
start_layer="m2", start_layer="m2",
vertical=True) vertical=True)
@ -141,31 +141,31 @@ class sense_amp_array(design.design):
dout_pin = inst.get_pin(inst.mod.dout_name) dout_pin = inst.get_pin(inst.mod.dout_name)
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer=bl_pin.layer,
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer=br_pin.layer,
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
height=br_pin.height()) height=br_pin.height())
self.add_layout_pin(text=self.data_name + "_{0}".format(i), self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer=dout_pin.layer,
offset=dout_pin.ll(), offset=dout_pin.ll(),
width=dout_pin.width(), width=dout_pin.width(),
height=dout_pin.height()) height=dout_pin.height())
def route_rails(self): def route_rails(self):
# add sclk rail across entire array # add sclk rail across entire array
sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0,1) sclk = self.amp.get_pin(self.amp.en_name)
sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0, 1)
self.add_layout_pin(text=self.en_name, self.add_layout_pin(text=self.en_name,
layer="m1", layer=sclk.layer,
offset=sclk_offset, offset=sclk_offset,
width=self.width, width=self.width,
height=drc("minwidth_m1")) height=drc("minwidth_" + sclk.layer))
def input_load(self): def input_load(self):
return self.amp.input_load() return self.amp.input_load()
@ -178,6 +178,6 @@ class sense_amp_array(design.design):
def get_drain_cin(self): def get_drain_cin(self):
"""Get the relative capacitance of the drain of the PMOS isolation TX""" """Get the relative capacitance of the drain of the PMOS isolation TX"""
from tech import parameter from tech import parameter
#Bitcell drain load being used to estimate PMOS drain load # Bitcell drain load being used to estimate PMOS drain load
drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])
return drain_load return drain_load

View File

@ -5,21 +5,20 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from math import log
import design import design
from tech import drc
import debug import debug
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
class write_driver_array(design.design): class write_driver_array(design.design):
""" """
Array of tristate drivers to write to the bitlines through the column mux. Array of tristate drivers to write to the bitlines through the column mux.
Dynamically generated write driver array of all bitlines. Dynamically generated write driver array of all bitlines.
""" """
def __init__(self, name, columns, word_size,write_size=None): def __init__(self, name, columns, word_size, write_size=None):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns)) self.add_comment("columns: {0}".format(columns))
@ -31,7 +30,7 @@ class write_driver_array(design.design):
self.words_per_row = int(columns / word_size) self.words_per_row = int(columns / word_size)
if self.write_size: if self.write_size:
self.num_wmasks = int(self.word_size/self.write_size) self.num_wmasks = int(self.word_size / self.write_size)
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -97,9 +96,9 @@ class write_driver_array(design.design):
self.driver_insts = {} self.driver_insts = {}
w = 0 w = 0
windex=0 windex=0
for i in range(0,self.columns,self.words_per_row): for i in range(0, self.columns, self.words_per_row):
name = "write_driver{}".format(i) name = "write_driver{}".format(i)
index = int(i/self.words_per_row) index = int(i / self.words_per_row)
self.driver_insts[index]=self.add_inst(name=name, self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver) mod=self.driver)
@ -119,15 +118,14 @@ class write_driver_array(design.design):
self.get_br_name() + "_{0}".format(index), self.get_br_name() + "_{0}".format(index),
self.en_name, "vdd", "gnd"]) self.en_name, "vdd", "gnd"])
def place_write_array(self): def place_write_array(self):
from tech import cell_properties from tech import cell_properties
if self.bitcell.width > self.driver.width: if self.bitcell.width > self.driver.width:
self.driver_spacing = self.bitcell.width self.driver_spacing = self.bitcell.width
else: else:
self.driver_spacing = self.driver.width self.driver_spacing = self.driver.width
for i in range(0,self.columns,self.words_per_row): for i in range(0, self.columns, self.words_per_row):
index = int(i/self.words_per_row) index = int(i / self.words_per_row)
xoffset = i * self.driver_spacing xoffset = i * self.driver_spacing
if cell_properties.bitcell.mirror.y and i % 2: if cell_properties.bitcell.mirror.y and i % 2:
@ -139,26 +137,25 @@ class write_driver_array(design.design):
base = vector(xoffset, 0) base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror) self.driver_insts[index].place(offset=base, mirror=mirror)
def add_layout_pins(self): def add_layout_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
inst = self.driver_insts[i] inst = self.driver_insts[i]
din_pin = inst.get_pin(inst.mod.din_name) din_pin = inst.get_pin(inst.mod.din_name)
self.add_layout_pin(text=self.data_name + "_{0}".format(i), self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer=din_pin.layer,
offset=din_pin.ll(), offset=din_pin.ll(),
width=din_pin.width(), width=din_pin.width(),
height=din_pin.height()) height=din_pin.height())
bl_pin = inst.get_pin(inst.mod.get_bl_names()) bl_pin = inst.get_pin(inst.mod.get_bl_names())
self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer=bl_pin.layer,
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
br_pin = inst.get_pin(inst.mod.get_br_names()) br_pin = inst.get_pin(inst.mod.get_br_names())
self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer=br_pin.layer,
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
height=br_pin.height()) height=br_pin.height())
@ -166,16 +163,16 @@ class write_driver_array(design.design):
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
pin_list = self.driver_insts[i].get_pins(n) pin_list = self.driver_insts[i].get_pins(n)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(name = n, self.add_power_pin(name=n,
loc = pin.center(), loc=pin.center(),
vertical=True, vertical=True,
start_layer = "m2") start_layer="m2")
if self.write_size: if self.write_size:
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
inst = self.driver_insts[bit*self.write_size] inst = self.driver_insts[bit * self.write_size]
en_pin = inst.get_pin(inst.mod.en_name) en_pin = inst.get_pin(inst.mod.en_name)
# Determine width of wmask modified en_pin with/without col mux # Determine width of wmask modified en_pin with/without col mux
wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing) wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing)
if (self.words_per_row == 1): if (self.words_per_row == 1):
en_gap = self.driver_spacing - en_pin.width() en_gap = self.driver_spacing - en_pin.width()
else: else:
@ -184,19 +181,16 @@ class write_driver_array(design.design):
self.add_layout_pin(text=self.en_name + "_{0}".format(bit), self.add_layout_pin(text=self.en_name + "_{0}".format(bit),
layer=en_pin.layer, layer=en_pin.layer,
offset=en_pin.ll(), offset=en_pin.ll(),
width=wmask_en_len-en_gap, width=wmask_en_len - en_gap,
height=en_pin.height()) height=en_pin.height())
else: else:
inst = self.driver_insts[0] inst = self.driver_insts[0]
self.add_layout_pin(text=self.en_name, self.add_layout_pin(text=self.en_name,
layer="m1", layer="m1",
offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1), offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
width=self.width) width=self.width)
def get_w_en_cin(self): def get_w_en_cin(self):
"""Get the relative capacitance of all the enable connections in the bank""" """Get the relative capacitance of all the enable connections in the bank"""
#The enable is connected to a nand2 for every row. # The enable is connected to a nand2 for every row.
return self.driver.get_w_en_cin() * len(self.driver_insts) return self.driver.get_w_en_cin() * len(self.driver_insts)

View File

@ -214,14 +214,16 @@ class pnand3(pgate.pgate):
"B", "B",
position="center") position="center")
self.inputC_yoffset = self.inputB_yoffset - m1_pitch # FIXME: constant hack
self.inputC_yoffset = self.inputB_yoffset - 1.1 * m1_pitch
self.route_input_gate(self.pmos3_inst, self.route_input_gate(self.pmos3_inst,
self.nmos3_inst, self.nmos3_inst,
self.inputC_yoffset, self.inputC_yoffset,
"C", "C",
position="center") position="center")
self.inputA_yoffset = self.inputB_yoffset + m1_pitch # FIXME: constant hack
self.inputA_yoffset = self.inputB_yoffset + 1.1 * m1_pitch
self.route_input_gate(self.pmos1_inst, self.route_input_gate(self.pmos1_inst,
self.nmos1_inst, self.nmos1_inst,
self.inputA_yoffset, self.inputA_yoffset,

View File

@ -96,17 +96,24 @@ class precharge(design.design):
height=layer_width) height=layer_width)
pmos_pin = self.upper_pmos2_inst.get_pin("S") pmos_pin = self.upper_pmos2_inst.get_pin("S")
# center of vdd rail # center of vdd rail
pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y)
self.add_path("m1", [pmos_pin.uc(), pmos_vdd_pos]) self.add_path("m1", [pmos_pin.uc(), pmos_vdd_pos])
# if enable is not on M1, the supply can be
if self.en_layer != "m1": if self.en_layer != "m1":
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=pmos_vdd_pos) offset=pmos_vdd_pos)
self.add_power_pin("vdd",
self.well_contact_pos,
vertical=True)
# Hack for li layers
# Add vdd pin above the transistor if OPTS.tech_name == "s8":
self.add_power_pin("vdd", self.well_contact_pos, vertical=True) self.add_via_center(layers=self.li_stack,
offset=self.well_contact_pos)
def create_ptx(self): def create_ptx(self):
""" """
@ -192,7 +199,6 @@ class precharge(design.design):
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
offset=offset) offset=offset)
# adds the en rail on metal1 # adds the en rail on metal1
self.add_layout_pin_segment_center(text="en_bar", self.add_layout_pin_segment_center(text="en_bar",
layer=self.en_layer, layer=self.en_layer,
@ -205,9 +211,11 @@ class precharge(design.design):
""" """
# adds the contact from active to metal1 # adds the contact from active to metal1
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) \ offset_height = self.upper_pmos1_inst.uy() + \
+ vector(0, self.upper_pmos1_inst.uy() + contact.active_contact.height / 2 \ 0.5 * contact.active_contact.height + \
+ self.nwell_extend_active) self.nwell_extend_active
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
vector(0, offset_height)
self.add_via_center(layers=self.active_stack, self.add_via_center(layers=self.active_stack,
offset=self.well_contact_pos, offset=self.well_contact_pos,
implant_type="n", implant_type="n",

View File

@ -22,6 +22,10 @@ class sense_amp_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# check sense amp array for single port # check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=1")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2) a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
self.local_check(a) self.local_check(a)

View File

@ -22,7 +22,6 @@ and include its appropriate license.
import os import os
import re import re
import time
import shutil import shutil
import debug import debug
from globals import OPTS from globals import OPTS
@ -67,26 +66,29 @@ def write_magic_script(cell_name, extract=False, final_verification=False):
else: else:
pre = "" pre = ""
if final_verification: if final_verification:
f.write(pre+"extract unique all\n".format(cell_name)) f.write(pre + "extract unique all\n".format(cell_name))
f.write(pre+"extract\n".format(cell_name)) # Hack to work around unit scales in SkyWater
#f.write(pre+"ext2spice hierarchy on\n") if OPTS.tech_name=="s8":
#f.write(pre+"ext2spice scale off\n") f.write(pre + "extract style ngspice(si)\n")
f.write(pre + "extract\n".format(cell_name))
# f.write(pre + "ext2spice hierarchy on\n")
# f.write(pre + "ext2spice scale off\n")
# lvs exists in 8.2.79, but be backword compatible for now # lvs exists in 8.2.79, but be backword compatible for now
#f.write(pre+"ext2spice lvs\n") # f.write(pre + "ext2spice lvs\n")
f.write(pre+"ext2spice hierarchy on\n") f.write(pre + "ext2spice hierarchy on\n")
f.write(pre+"ext2spice format ngspice\n") f.write(pre + "ext2spice format ngspice\n")
f.write(pre+"ext2spice cthresh infinite\n") f.write(pre + "ext2spice cthresh infinite\n")
f.write(pre+"ext2spice rthresh infinite\n") f.write(pre + "ext2spice rthresh infinite\n")
f.write(pre+"ext2spice renumber off\n") f.write(pre + "ext2spice renumber off\n")
f.write(pre+"ext2spice scale off\n") f.write(pre + "ext2spice scale off\n")
f.write(pre+"ext2spice blackbox on\n") f.write(pre + "ext2spice blackbox on\n")
f.write(pre+"ext2spice subcircuit top auto\n") f.write(pre + "ext2spice subcircuit top auto\n")
f.write(pre+"ext2spice global off\n") f.write(pre + "ext2spice global off\n")
# Can choose hspice, ngspice, or spice3, # Can choose hspice, ngspice, or spice3,
# but they all seem compatible enough. # but they all seem compatible enough.
#f.write(pre+"ext2spice format ngspice\n") #f.write(pre + "ext2spice format ngspice\n")
f.write(pre+"ext2spice {}\n".format(cell_name)) f.write(pre + "ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n") f.write("quit -noprompt\n")
f.write("EOF\n") f.write("EOF\n")