Merge branch 'laptop_checkpoint' into dev

This commit is contained in:
mrg 2021-06-04 15:22:37 -07:00
commit cf61096936
20 changed files with 210 additions and 73 deletions

View File

@ -176,7 +176,7 @@ class cell_properties():
self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw"
self.names["row_cap_bitcell_1port"] = "row_cap_cell_1rw"
self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw"
self.use_strap = False
self._ptx = _ptx(model_is_subckt=False,
bin_spice_models=False)

View File

@ -48,7 +48,8 @@ class design(hierarchy_design):
self.add_pin_indices(prop.port_indices)
self.add_pin_names(prop.port_map)
self.add_pin_types(prop.port_types)
(width, height) = utils.get_libcell_size(self.cell_name,
GDS["unit"],
layer[prop.boundary_layer])

View File

@ -1257,22 +1257,24 @@ class layout():
height=ymax - ymin)
return rect
def copy_power_pins(self, inst, name, add_vias=True):
def copy_power_pins(self, inst, name, add_vias=True, new_name=""):
"""
This will copy a power pin if it is on the lowest power_grid layer.
If it is on M1, it will add a power via too.
"""
pins = inst.get_pins(name)
for pin in pins:
if new_name == "":
new_name = pin.name
if pin.layer == self.pwr_grid_layer:
self.add_layout_pin(name,
self.add_layout_pin(new_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
elif add_vias:
self.copy_power_pin(pin)
self.copy_power_pin(pin, new_name=new_name)
def add_io_pin(self, instance, pin_name, new_name, start_layer=None):
"""
@ -1318,13 +1320,15 @@ class layout():
width=width,
height=height)
def copy_power_pin(self, pin, loc=None, directions=None):
def copy_power_pin(self, pin, loc=None, directions=None, new_name=""):
"""
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
which vias are needed.
"""
if new_name == "":
new_name = pin.name
if not loc:
loc = pin.center()
@ -1338,7 +1342,7 @@ class layout():
height = None
if pin.layer == self.pwr_grid_layer:
self.add_layout_pin_rect_center(text=pin.name,
self.add_layout_pin_rect_center(text=new_name,
layer=self.pwr_grid_layer,
offset=loc,
width=width,
@ -1353,7 +1357,7 @@ class layout():
width = via.width
if not height:
height = via.height
self.add_layout_pin_rect_center(text=pin.name,
self.add_layout_pin_rect_center(text=new_name,
layer=self.pwr_grid_layer,
offset=loc,
width=width,

View File

@ -148,12 +148,15 @@ def get_gds_pins(pin_names, name, gds_filename, units):
cell[str(pin_name)] = []
pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list:
(lpp, boundary) = pin_shape
rect = [vector(boundary[0], boundary[1]),
vector(boundary[2], boundary[3])]
# this is a list because other cells/designs
# may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
if pin_shape != None:
(lpp, boundary) = pin_shape
rect = [vector(boundary[0], boundary[1]),
vector(boundary[2], boundary[3])]
# this is a list because other cells/designs
# may have must-connect pins
if isinstance(lpp[1], list):
lpp = (lpp[0], None)
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
_GDS_PINS_CACHE[k] = cell
return dict(cell)

View File

@ -3,7 +3,7 @@ from datetime import *
import numpy as np
import math
import debug
from tech import use_purpose
class VlsiLayout:
"""Class represent a hierarchical layout"""
@ -215,9 +215,13 @@ class VlsiLayout:
self.deduceHierarchy()
# self.traverseTheHierarchy()
self.populateCoordinateMap()
#only ones with text
for layerNumber in self.layerNumbersInUse:
self.processLabelPins((layerNumber, None))
#if layerNumber not in no_pin_shape:
if layerNumber in use_purpose:
self.processLabelPins((layerNumber, use_purpose[layerNumber]))
else:
self.processLabelPins((layerNumber, None))
def populateCoordinateMap(self):
def addToXyTree(startingStructureName = None,transformPath = None):
@ -903,6 +907,16 @@ def sameLPP(lpp1, lpp2):
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
if isinstance(lpp1[1], list):
for i in range(len(lpp1[1])):
if lpp1[0] == lpp2[0] and lpp1[1][i] == lpp2[1]:
return True
if isinstance(lpp2[1], list):
for i in range(len(lpp2[1])):
if lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1][i]:
return True
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]

View File

@ -238,8 +238,8 @@ def setup_bitcell():
OPTS.dummy_bitcell = "dummy_pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
else:
num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
OPTS.bitcell = "bitcell_{}port".format(num_ports)
OPTS.num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
OPTS.bitcell = "bitcell_{}port".format(OPTS.num_ports)
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
OPTS.replica_bitcell = "replica_" + OPTS.bitcell

View File

@ -366,18 +366,13 @@ class bank(design.design):
# A space for wells or jogging m2
self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
3 * self.m2_pitch)
3 * self.m2_pitch,
drc("nwell_to_nwell"))
def add_modules(self):
""" Add all the modules using the class loader """
self.port_address = []
for port in self.all_ports:
self.port_address.append(factory.create(module_type="port_address",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
port=port))
self.add_mod(self.port_address[port])
local_array_size = OPTS.local_array_size
@ -397,12 +392,26 @@ class bank(design.design):
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
if self.num_spare_cols == 0:
self.num_spare_cols = (self.bitcell_array.column_size % (self.word_size *self.words_per_row))
self.port_address = []
for port in self.all_ports:
self.port_address.append(factory.create(module_type="port_address",
cols=self.bitcell_array.column_size,
rows=self.bitcell_array.row_size,
port=port))
self.add_mod(self.port_address[port])
self.port_data = []
self.bit_offsets = self.get_column_offsets()
for port in self.all_ports:
temp_pre = factory.create(module_type="port_data",
sram_config=self.sram_config,
dimension_override=True,
cols=self.bitcell_array.column_size - self.num_spare_cols,
rows=self.bitcell_array.row_size,
num_spare_cols=self.num_spare_cols,
port=port,
bit_offsets=self.bit_offsets)
self.port_data.append(temp_pre)
@ -430,7 +439,9 @@ class bank(design.design):
temp.append("vdd")
temp.append("gnd")
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
temp.append('vpb')
temp.append('vnb')
self.connect_inst(temp)
def place_bitcell_array(self, offset):
@ -489,7 +500,7 @@ class bank(design.design):
mod=self.port_address[port])
temp = []
for bit in range(self.row_addr_size):
for bit in range(ceil(log(self.bitcell_array.row_size, 2))):
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
temp.append("wl_en{}".format(port))
wordline_names = self.bitcell_array.get_wordline_names(port)
@ -614,6 +625,10 @@ class bank(design.design):
self.copy_power_pins(inst, "vdd", add_vias=False)
self.copy_power_pins(inst, "gnd", add_vias=False)
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
for pin_name, supply_name in zip(['vpb','vnb'],['vdd','gnd']):
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
# If we use the pinvbuf as the decoder, we need to add power pins.
# Other decoders already have them.
if self.col_addr_size == 1:
@ -1062,7 +1077,6 @@ class bank(design.design):
to_layer="m2",
offset=control_pos)
def graph_exclude_precharge(self):
"""
Precharge adds a loop between bitlines, can be excluded to reduce complexity

View File

@ -12,6 +12,10 @@ from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import layer_properties as layer_props
from tech import layer_indices
from tech import layer_stacks
from tech import preferred_directions
from tech import drc
class hierarchical_predecode(design.design):
@ -29,7 +33,7 @@ class hierarchical_predecode(design.design):
self.cell_height = height
self.column_decoder = column_decoder
self.input_and_rail_pos = []
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
super().__init__(name)
@ -183,9 +187,9 @@ class hierarchical_predecode(design.design):
def route(self):
self.route_input_inverters()
self.route_output_inverters()
self.route_inputs_to_rails()
self.route_input_ands()
self.route_output_inverters()
self.route_inputs_to_rails()
self.route_output_ands()
self.route_vdd_gnd()
@ -274,8 +278,46 @@ class hierarchical_predecode(design.design):
# pins in the and gates.
inv_out_pos = inv_out_pin.rc()
y_offset = (inv_num + 1) * self.inv.height - self.output_layer_pitch
right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0)
rail_pos = vector(self.decode_rails[out_pin].cx(), y_offset)
# create via for dimensions
from_layer = self.output_layer
to_layer = self.bus_layer
cur_layer = from_layer
from_id = layer_indices[cur_layer]
to_id = layer_indices[to_layer]
if from_id < to_id: # grow the stack up
search_id = 0
next_id = 2
else: # grow the stack down
search_id = 2
next_id = 0
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
via = factory.create(module_type="contact",
layer_stack=curr_stack,
dimensions=[1, 1],
directions=self.bus_directions)
overlapping_pin_space = drc["{0}_to_{0}".format(self.output_layer)]
total_buffer_space = (overlapping_pin_space + via.height)
#FIXME: compute rail locations instead of just guessing and nudging
while(True):
drc_error = 0
for and_input in self.input_and_rail_pos:
if and_input.x == rail_pos.x:
if (abs(y_offset - and_input.y) < total_buffer_space) and (abs(y_offset - and_input.y) > via.height):
drc_error = 1
if drc_error == 0:
break
else:
y_offset += drc["grid"]
rail_pos.y = y_offset
right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0)
self.add_path(self.output_layer, [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
self.add_via_stack_center(from_layer=inv_out_pin.layer,
@ -316,6 +358,7 @@ class hierarchical_predecode(design.design):
to_layer=self.bus_layer,
offset=rail_pos,
directions=self.bus_directions)
self.input_and_rail_pos.append(rail_pos)
if gate_pin == "A":
direction = None
else:

View File

@ -11,6 +11,7 @@ from sram_factory import factory
from collections import namedtuple
from vector import vector
from globals import OPTS
from tech import cell_properties
from tech import layer_properties as layer_props
@ -20,26 +21,36 @@ class port_data(design.design):
Port 0 always has the RBL on the left while port 1 is on the right.
"""
def __init__(self, sram_config, port, bit_offsets=None, name=""):
def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False):
sram_config.set_local_config(self)
if dimension_override:
self.num_rows = rows
self.num_cols = cols
self.word_size = sram_config.word_size
self.port = port
if self.write_size is not None:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
if self.num_spare_cols is None:
if num_spare_cols:
self.num_spare_cols = num_spare_cols
elif self.num_spare_cols is None:
self.num_spare_cols = 0
if not bit_offsets:
bitcell = factory.create(module_type=OPTS.bitcell)
if(cell_properties.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version)
precharge_width = bitcell.width + strap.width
else:
precharge_width = bitcell.width
self.bit_offsets = []
for i in range(self.num_cols + self.num_spare_cols):
self.bit_offsets.append(i * bitcell.width)
self.bit_offsets.append(i * precharge_width)
else:
self.bit_offsets = bit_offsets
if name == "":
name = "port_data_{0}".format(self.port)
super().__init__(name)
@ -117,7 +128,6 @@ class port_data(design.design):
for bit in range(self.num_spare_cols):
self.add_pin("sparebl_{0}".format(bit), "INOUT")
self.add_pin("sparebr_{0}".format(bit), "INOUT")
if self.port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout_{}".format(bit), "OUTPUT")
@ -191,14 +201,19 @@ class port_data(design.design):
# and mirroring happens correctly
# Used for names/dimensions only
self.cell = factory.create(module_type=OPTS.bitcell)
cell = factory.create(module_type=OPTS.bitcell)
if(cell_properties.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version)
precharge_width = cell.width + strap.width
else:
precharge_width = cell.width
if self.port == 0:
# Append an offset on the left
precharge_bit_offsets = [self.bit_offsets[0] - self.cell.width] + self.bit_offsets
precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets
else:
# Append an offset on the right
precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + self.cell.width]
precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width]
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + self.num_spare_cols + 1,
offsets=precharge_bit_offsets,
@ -567,19 +582,32 @@ class port_data(design.design):
off = 1
else:
off = 0
if OPTS.num_ports > 1:
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
else:
self.connect_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
self.connect_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
elif layer_props.port_data.channel_route_bitlines:
self.channel_route_bitlines(inst1=inst1,

View File

@ -76,8 +76,8 @@ class precharge_array(design.design):
size=self.size,
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
self.add_mod(self.pc_cell)
self.cell = factory.create(module_type=OPTS.bitcell)
def add_layout_pins(self):

View File

@ -6,7 +6,7 @@
import debug
from bitcell_base_array import bitcell_base_array
from tech import drc, spice
from tech import drc, spice, cell_properties
from vector import vector
from globals import OPTS
from sram_factory import factory

View File

@ -8,6 +8,7 @@
import design
from vector import vector
from sram_factory import factory
from tech import cell_properties
import debug
from globals import OPTS
@ -41,7 +42,6 @@ class sense_amp_array(design.design):
self.en_layer = "m3"
else:
self.en_layer = "m1"
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -109,15 +109,22 @@ class sense_amp_array(design.design):
self.en_name, "vdd", "gnd"])
def place_sense_amp_array(self):
if self.bitcell.width > self.amp.width:
self.amp_spacing = self.bitcell.width
cell = factory.create(module_type=OPTS.bitcell)
if(cell_properties.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version)
precharge_width = cell.width + strap.width
else:
precharge_width = cell.width
if precharge_width > self.amp.width:
self.amp_spacing = precharge_width
else:
self.amp_spacing = self.amp.width
if not self.offsets:
self.offsets = []
for i in range(self.num_cols + self.num_spare_cols):
self.offsets.append(i * self.bitcell.width)
self.offsets.append(i * self.amp_spacing)
for i, xoffset in enumerate(self.offsets[0:self.num_cols:self.words_per_row]):
if self.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
@ -128,13 +135,12 @@ class sense_amp_array(design.design):
amp_position = vector(xoffset, 0)
self.local_insts[i].place(offset=amp_position, mirror=mirror)
# place spare sense amps (will share the same enable as regular sense amps)
for i, xoffset in enumerate(self.offsets[self.num_cols:]):
index = self.word_size + i
if self.bitcell.mirror.y and (index + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.amp_width
xoffset = xoffset + self.amp_spacing
else:
mirror = ""

View File

@ -72,7 +72,9 @@ class options(optparse.Values):
# This is the temp directory where all intermediate results are stored.
try:
# If user defined the temporary location in their environment, use it
openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
except:
openram_temp = "/tmp"

View File

@ -56,7 +56,13 @@ class column_mux(pgate.pgate):
self.place_ptx()
self.width = self.bitcell.width
cell = factory.create(module_type=OPTS.bitcell)
if(cell_props.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version)
precharge_width = cell.width + strap.width
else:
precharge_width = cell.width
self.width = precharge_width
self.height = self.nmos_upper.uy() + self.pin_height
self.connect_poly()
@ -217,10 +223,15 @@ class column_mux(pgate.pgate):
Add a well and implant over the whole cell. Also, add the
pwell contact (if it exists)
"""
if(cell_props.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version)
rbc_width = self.bitcell.width + strap.width
else:
rbc_width = self.bitcell.width
# Add it to the right, aligned in between the two tx
active_pos = vector(self.bitcell.width,
active_pos = vector(rbc_width,
self.nmos_upper.by() - 0.5 * self.poly_space)
self.add_via_center(layers=self.active_stack,
offset=active_pos,
implant_type="p",
@ -239,5 +250,5 @@ class column_mux(pgate.pgate):
if "pwell" in layer:
self.add_rect(layer="pwell",
offset=vector(0, 0),
width=self.bitcell.width,
width=rbc_width,
height=self.height)

View File

@ -30,7 +30,11 @@ class precharge(design.design):
self.beta = parameter["beta"]
self.ptx_width = self.beta * parameter["min_tx_size"]
self.ptx_mults = 1
self.width = self.bitcell.width
if(cell_props.use_strap == True and OPTS.num_ports == 1):
strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version)
self.width = self.bitcell.width + strap.width
else:
self.width = self.bitcell.width
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
self.bitcell_bl_pin =self.bitcell.get_pin(self.bitcell_bl)

View File

@ -472,6 +472,12 @@ class sram_base(design, verilog, lef):
self.bitcell = factory.create(module_type=OPTS.bitcell)
self.dff = factory.create(module_type="dff")
# Create the bank module (up to four are instantiated)
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
self.add_mod(self.bank)
self.num_spare_cols = self.bank.num_spare_cols
# Create the address and control flops (but not the clk)
self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.add_mod(self.row_addr_dff)
@ -493,10 +499,6 @@ class sram_base(design, verilog, lef):
self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols)
self.add_mod(self.spare_wen_dff)
# Create the bank module (up to four are instantiated)
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
self.add_mod(self.bank)
# Create bank decoder
if(self.num_banks > 1):
self.add_multi_bank_modules()

View File

@ -92,7 +92,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
f.write("set VDD vdd\n")
f.write("set GND gnd\n")
f.write("set SUB gnd\n")
f.write("gds polygon subcell true\n")
#f.write("gds polygon subcell true\n")
f.write("gds warning default\n")
# These two options are temporarily disabled until Tim fixes a bug in magic related
# to flattening channel routes and vias (hierarchy with no devices in it). Otherwise,

View File

@ -135,6 +135,8 @@ layer["m10"] = (29, 0)
layer["text"] = (239, 0)
layer["boundary"]= (239, 0)
use_purpose = {}
# Layer names for external PDKs
layer_names = {}
layer_names["active"] = "active"

View File

@ -63,6 +63,7 @@ layer["text"] = (63, 0)
layer["boundary"] = (63, 0)
layer["blockage"] = (83, 0)
use_purpose = {}
###################################################
##END GDS Layer Map
###################################################

View File

@ -119,6 +119,8 @@ layer["m4"] = (31, 0)
layer["text"] = (63, 0)
layer["boundary"] = (63, 0)
use_purpose = {}
# Layer names for external PDKs
layer_names = {}
layer_names["active"] = "active"