mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'laptop_checkpoint' into dev
This commit is contained in:
commit
cf61096936
|
|
@ -176,7 +176,7 @@ class cell_properties():
|
||||||
self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw"
|
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_1port"] = "row_cap_cell_1rw"
|
||||||
self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw"
|
self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw"
|
||||||
|
self.use_strap = False
|
||||||
self._ptx = _ptx(model_is_subckt=False,
|
self._ptx = _ptx(model_is_subckt=False,
|
||||||
bin_spice_models=False)
|
bin_spice_models=False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ class design(hierarchy_design):
|
||||||
self.add_pin_names(prop.port_map)
|
self.add_pin_names(prop.port_map)
|
||||||
self.add_pin_types(prop.port_types)
|
self.add_pin_types(prop.port_types)
|
||||||
|
|
||||||
|
|
||||||
(width, height) = utils.get_libcell_size(self.cell_name,
|
(width, height) = utils.get_libcell_size(self.cell_name,
|
||||||
GDS["unit"],
|
GDS["unit"],
|
||||||
layer[prop.boundary_layer])
|
layer[prop.boundary_layer])
|
||||||
|
|
|
||||||
|
|
@ -1257,22 +1257,24 @@ class layout():
|
||||||
height=ymax - ymin)
|
height=ymax - ymin)
|
||||||
return rect
|
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.
|
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.
|
If it is on M1, it will add a power via too.
|
||||||
"""
|
"""
|
||||||
pins = inst.get_pins(name)
|
pins = inst.get_pins(name)
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
|
if new_name == "":
|
||||||
|
new_name = pin.name
|
||||||
if pin.layer == self.pwr_grid_layer:
|
if pin.layer == self.pwr_grid_layer:
|
||||||
self.add_layout_pin(name,
|
self.add_layout_pin(new_name,
|
||||||
pin.layer,
|
pin.layer,
|
||||||
pin.ll(),
|
pin.ll(),
|
||||||
pin.width(),
|
pin.width(),
|
||||||
pin.height())
|
pin.height())
|
||||||
|
|
||||||
elif add_vias:
|
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):
|
def add_io_pin(self, instance, pin_name, new_name, start_layer=None):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1318,13 +1320,15 @@ class layout():
|
||||||
width=width,
|
width=width,
|
||||||
height=height)
|
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
|
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.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if new_name == "":
|
||||||
|
new_name = pin.name
|
||||||
if not loc:
|
if not loc:
|
||||||
loc = pin.center()
|
loc = pin.center()
|
||||||
|
|
||||||
|
|
@ -1338,7 +1342,7 @@ class layout():
|
||||||
height = None
|
height = None
|
||||||
|
|
||||||
if pin.layer == self.pwr_grid_layer:
|
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,
|
layer=self.pwr_grid_layer,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
width=width,
|
width=width,
|
||||||
|
|
@ -1353,7 +1357,7 @@ class layout():
|
||||||
width = via.width
|
width = via.width
|
||||||
if not height:
|
if not height:
|
||||||
height = via.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,
|
layer=self.pwr_grid_layer,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
width=width,
|
width=width,
|
||||||
|
|
|
||||||
|
|
@ -148,11 +148,14 @@ def get_gds_pins(pin_names, name, gds_filename, units):
|
||||||
cell[str(pin_name)] = []
|
cell[str(pin_name)] = []
|
||||||
pin_list = cell_vlsi.getPinShape(str(pin_name))
|
pin_list = cell_vlsi.getPinShape(str(pin_name))
|
||||||
for pin_shape in pin_list:
|
for pin_shape in pin_list:
|
||||||
|
if pin_shape != None:
|
||||||
(lpp, boundary) = pin_shape
|
(lpp, boundary) = pin_shape
|
||||||
rect = [vector(boundary[0], boundary[1]),
|
rect = [vector(boundary[0], boundary[1]),
|
||||||
vector(boundary[2], boundary[3])]
|
vector(boundary[2], boundary[3])]
|
||||||
# this is a list because other cells/designs
|
# this is a list because other cells/designs
|
||||||
# may have must-connect pins
|
# may have must-connect pins
|
||||||
|
if isinstance(lpp[1], list):
|
||||||
|
lpp = (lpp[0], None)
|
||||||
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
|
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
|
||||||
|
|
||||||
_GDS_PINS_CACHE[k] = cell
|
_GDS_PINS_CACHE[k] = cell
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from datetime import *
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import math
|
import math
|
||||||
import debug
|
import debug
|
||||||
|
from tech import use_purpose
|
||||||
|
|
||||||
class VlsiLayout:
|
class VlsiLayout:
|
||||||
"""Class represent a hierarchical layout"""
|
"""Class represent a hierarchical layout"""
|
||||||
|
|
@ -215,8 +215,12 @@ class VlsiLayout:
|
||||||
self.deduceHierarchy()
|
self.deduceHierarchy()
|
||||||
# self.traverseTheHierarchy()
|
# self.traverseTheHierarchy()
|
||||||
self.populateCoordinateMap()
|
self.populateCoordinateMap()
|
||||||
|
#only ones with text
|
||||||
for layerNumber in self.layerNumbersInUse:
|
for layerNumber in self.layerNumbersInUse:
|
||||||
|
#if layerNumber not in no_pin_shape:
|
||||||
|
if layerNumber in use_purpose:
|
||||||
|
self.processLabelPins((layerNumber, use_purpose[layerNumber]))
|
||||||
|
else:
|
||||||
self.processLabelPins((layerNumber, None))
|
self.processLabelPins((layerNumber, None))
|
||||||
|
|
||||||
def populateCoordinateMap(self):
|
def populateCoordinateMap(self):
|
||||||
|
|
@ -903,6 +907,16 @@ def sameLPP(lpp1, lpp2):
|
||||||
if lpp1[1] == None or lpp2[1] == None:
|
if lpp1[1] == None or lpp2[1] == None:
|
||||||
return lpp1[0] == lpp2[0]
|
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]
|
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,8 +238,8 @@ def setup_bitcell():
|
||||||
OPTS.dummy_bitcell = "dummy_pbitcell"
|
OPTS.dummy_bitcell = "dummy_pbitcell"
|
||||||
OPTS.replica_bitcell = "replica_pbitcell"
|
OPTS.replica_bitcell = "replica_pbitcell"
|
||||||
else:
|
else:
|
||||||
num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
OPTS.num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||||
OPTS.bitcell = "bitcell_{}port".format(num_ports)
|
OPTS.bitcell = "bitcell_{}port".format(OPTS.num_ports)
|
||||||
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
|
OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell
|
||||||
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
|
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -366,18 +366,13 @@ class bank(design.design):
|
||||||
|
|
||||||
# A space for wells or jogging m2
|
# A space for wells or jogging m2
|
||||||
self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
|
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):
|
def add_modules(self):
|
||||||
""" Add all the modules using the class loader """
|
""" 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
|
local_array_size = OPTS.local_array_size
|
||||||
|
|
||||||
|
|
@ -397,12 +392,26 @@ class bank(design.design):
|
||||||
cols=self.num_cols + self.num_spare_cols,
|
cols=self.num_cols + self.num_spare_cols,
|
||||||
rows=self.num_rows)
|
rows=self.num_rows)
|
||||||
self.add_mod(self.bitcell_array)
|
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.port_data = []
|
||||||
self.bit_offsets = self.get_column_offsets()
|
self.bit_offsets = self.get_column_offsets()
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
temp_pre = factory.create(module_type="port_data",
|
temp_pre = factory.create(module_type="port_data",
|
||||||
sram_config=self.sram_config,
|
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,
|
port=port,
|
||||||
bit_offsets=self.bit_offsets)
|
bit_offsets=self.bit_offsets)
|
||||||
self.port_data.append(temp_pre)
|
self.port_data.append(temp_pre)
|
||||||
|
|
@ -430,7 +439,9 @@ class bank(design.design):
|
||||||
|
|
||||||
temp.append("vdd")
|
temp.append("vdd")
|
||||||
temp.append("gnd")
|
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)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def place_bitcell_array(self, offset):
|
def place_bitcell_array(self, offset):
|
||||||
|
|
@ -489,7 +500,7 @@ class bank(design.design):
|
||||||
mod=self.port_address[port])
|
mod=self.port_address[port])
|
||||||
|
|
||||||
temp = []
|
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("addr{0}_{1}".format(port, bit + self.col_addr_size))
|
||||||
temp.append("wl_en{}".format(port))
|
temp.append("wl_en{}".format(port))
|
||||||
wordline_names = self.bitcell_array.get_wordline_names(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, "vdd", add_vias=False)
|
||||||
self.copy_power_pins(inst, "gnd", 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.
|
# If we use the pinvbuf as the decoder, we need to add power pins.
|
||||||
# Other decoders already have them.
|
# Other decoders already have them.
|
||||||
if self.col_addr_size == 1:
|
if self.col_addr_size == 1:
|
||||||
|
|
@ -1062,7 +1077,6 @@ class bank(design.design):
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=control_pos)
|
offset=control_pos)
|
||||||
|
|
||||||
|
|
||||||
def graph_exclude_precharge(self):
|
def graph_exclude_precharge(self):
|
||||||
"""
|
"""
|
||||||
Precharge adds a loop between bitlines, can be excluded to reduce complexity
|
Precharge adds a loop between bitlines, can be excluded to reduce complexity
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@ from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from tech import layer_properties as layer_props
|
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):
|
class hierarchical_predecode(design.design):
|
||||||
|
|
@ -29,7 +33,7 @@ class hierarchical_predecode(design.design):
|
||||||
self.cell_height = height
|
self.cell_height = height
|
||||||
|
|
||||||
self.column_decoder = column_decoder
|
self.column_decoder = column_decoder
|
||||||
|
self.input_and_rail_pos = []
|
||||||
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
|
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
|
|
||||||
|
|
@ -183,9 +187,9 @@ class hierarchical_predecode(design.design):
|
||||||
def route(self):
|
def route(self):
|
||||||
|
|
||||||
self.route_input_inverters()
|
self.route_input_inverters()
|
||||||
|
self.route_input_ands()
|
||||||
self.route_output_inverters()
|
self.route_output_inverters()
|
||||||
self.route_inputs_to_rails()
|
self.route_inputs_to_rails()
|
||||||
self.route_input_ands()
|
|
||||||
self.route_output_ands()
|
self.route_output_ands()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
|
|
||||||
|
|
@ -274,8 +278,46 @@ class hierarchical_predecode(design.design):
|
||||||
# pins in the and gates.
|
# pins in the and gates.
|
||||||
inv_out_pos = inv_out_pin.rc()
|
inv_out_pos = inv_out_pin.rc()
|
||||||
y_offset = (inv_num + 1) * self.inv.height - self.output_layer_pitch
|
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)
|
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_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,
|
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,
|
to_layer=self.bus_layer,
|
||||||
offset=rail_pos,
|
offset=rail_pos,
|
||||||
directions=self.bus_directions)
|
directions=self.bus_directions)
|
||||||
|
self.input_and_rail_pos.append(rail_pos)
|
||||||
if gate_pin == "A":
|
if gate_pin == "A":
|
||||||
direction = None
|
direction = None
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from sram_factory import factory
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from tech import cell_properties
|
||||||
from tech import layer_properties as layer_props
|
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.
|
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)
|
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
|
self.port = port
|
||||||
if self.write_size is not None:
|
if self.write_size is not None:
|
||||||
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
||||||
else:
|
else:
|
||||||
self.num_wmasks = 0
|
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
|
self.num_spare_cols = 0
|
||||||
|
|
||||||
if not bit_offsets:
|
if not bit_offsets:
|
||||||
bitcell = factory.create(module_type=OPTS.bitcell)
|
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 = []
|
self.bit_offsets = []
|
||||||
for i in range(self.num_cols + self.num_spare_cols):
|
for i in range(self.num_cols + self.num_spare_cols):
|
||||||
self.bit_offsets.append(i * bitcell.width)
|
self.bit_offsets.append(i * precharge_width)
|
||||||
else:
|
else:
|
||||||
self.bit_offsets = bit_offsets
|
self.bit_offsets = bit_offsets
|
||||||
|
|
||||||
if name == "":
|
if name == "":
|
||||||
name = "port_data_{0}".format(self.port)
|
name = "port_data_{0}".format(self.port)
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
|
|
@ -117,7 +128,6 @@ class port_data(design.design):
|
||||||
for bit in range(self.num_spare_cols):
|
for bit in range(self.num_spare_cols):
|
||||||
self.add_pin("sparebl_{0}".format(bit), "INOUT")
|
self.add_pin("sparebl_{0}".format(bit), "INOUT")
|
||||||
self.add_pin("sparebr_{0}".format(bit), "INOUT")
|
self.add_pin("sparebr_{0}".format(bit), "INOUT")
|
||||||
|
|
||||||
if self.port in self.read_ports:
|
if self.port in self.read_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
self.add_pin("dout_{}".format(bit), "OUTPUT")
|
self.add_pin("dout_{}".format(bit), "OUTPUT")
|
||||||
|
|
@ -191,14 +201,19 @@ class port_data(design.design):
|
||||||
# and mirroring happens correctly
|
# and mirroring happens correctly
|
||||||
|
|
||||||
# Used for names/dimensions only
|
# Used for names/dimensions only
|
||||||
self.cell = factory.create(module_type=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:
|
if self.port == 0:
|
||||||
# Append an offset on the left
|
# 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:
|
else:
|
||||||
# Append an offset on the right
|
# 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",
|
self.precharge_array = factory.create(module_type="precharge_array",
|
||||||
columns=self.num_cols + self.num_spare_cols + 1,
|
columns=self.num_cols + self.num_spare_cols + 1,
|
||||||
offsets=precharge_bit_offsets,
|
offsets=precharge_bit_offsets,
|
||||||
|
|
@ -567,7 +582,7 @@ class port_data(design.design):
|
||||||
off = 1
|
off = 1
|
||||||
else:
|
else:
|
||||||
off = 0
|
off = 0
|
||||||
|
if OPTS.num_ports > 1:
|
||||||
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
|
||||||
inst1_bls_template="{inst}_out_{bit}",
|
inst1_bls_template="{inst}_out_{bit}",
|
||||||
inst2=inst2,
|
inst2=inst2,
|
||||||
|
|
@ -580,6 +595,19 @@ class port_data(design.design):
|
||||||
num_bits=self.num_spare_cols,
|
num_bits=self.num_spare_cols,
|
||||||
inst1_start_bit=self.num_cols + off,
|
inst1_start_bit=self.num_cols + off,
|
||||||
inst2_start_bit=self.word_size)
|
inst2_start_bit=self.word_size)
|
||||||
|
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.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:
|
elif layer_props.port_data.channel_route_bitlines:
|
||||||
self.channel_route_bitlines(inst1=inst1,
|
self.channel_route_bitlines(inst1=inst1,
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ class precharge_array(design.design):
|
||||||
size=self.size,
|
size=self.size,
|
||||||
bitcell_bl=self.bitcell_bl,
|
bitcell_bl=self.bitcell_bl,
|
||||||
bitcell_br=self.bitcell_br)
|
bitcell_br=self.bitcell_br)
|
||||||
self.add_mod(self.pc_cell)
|
|
||||||
|
|
||||||
|
self.add_mod(self.pc_cell)
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import debug
|
import debug
|
||||||
from bitcell_base_array import bitcell_base_array
|
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 vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
import design
|
import design
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
from tech import cell_properties
|
||||||
import debug
|
import debug
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
|
||||||
|
|
@ -41,7 +42,6 @@ class sense_amp_array(design.design):
|
||||||
self.en_layer = "m3"
|
self.en_layer = "m3"
|
||||||
else:
|
else:
|
||||||
self.en_layer = "m1"
|
self.en_layer = "m1"
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
@ -109,15 +109,22 @@ class sense_amp_array(design.design):
|
||||||
self.en_name, "vdd", "gnd"])
|
self.en_name, "vdd", "gnd"])
|
||||||
|
|
||||||
def place_sense_amp_array(self):
|
def place_sense_amp_array(self):
|
||||||
if self.bitcell.width > self.amp.width:
|
cell = factory.create(module_type=OPTS.bitcell)
|
||||||
self.amp_spacing = self.bitcell.width
|
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:
|
else:
|
||||||
self.amp_spacing = self.amp.width
|
self.amp_spacing = self.amp.width
|
||||||
|
|
||||||
if not self.offsets:
|
if not self.offsets:
|
||||||
self.offsets = []
|
self.offsets = []
|
||||||
for i in range(self.num_cols + self.num_spare_cols):
|
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]):
|
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:
|
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)
|
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)
|
||||||
|
|
||||||
# place spare sense amps (will share the same enable as regular sense amps)
|
# place spare sense amps (will share the same enable as regular sense amps)
|
||||||
for i, xoffset in enumerate(self.offsets[self.num_cols:]):
|
for i, xoffset in enumerate(self.offsets[self.num_cols:]):
|
||||||
index = self.word_size + i
|
index = self.word_size + i
|
||||||
if self.bitcell.mirror.y and (index + self.column_offset) % 2:
|
if self.bitcell.mirror.y and (index + self.column_offset) % 2:
|
||||||
mirror = "MY"
|
mirror = "MY"
|
||||||
xoffset = xoffset + self.amp_width
|
xoffset = xoffset + self.amp_spacing
|
||||||
else:
|
else:
|
||||||
mirror = ""
|
mirror = ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,9 @@ class options(optparse.Values):
|
||||||
# This is the temp directory where all intermediate results are stored.
|
# This is the temp directory where all intermediate results are stored.
|
||||||
try:
|
try:
|
||||||
# If user defined the temporary location in their environment, use it
|
# If user defined the temporary location in their environment, use it
|
||||||
|
|
||||||
openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
|
openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
|
||||||
|
|
||||||
except:
|
except:
|
||||||
openram_temp = "/tmp"
|
openram_temp = "/tmp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,13 @@ class column_mux(pgate.pgate):
|
||||||
|
|
||||||
self.place_ptx()
|
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.height = self.nmos_upper.uy() + self.pin_height
|
||||||
|
|
||||||
self.connect_poly()
|
self.connect_poly()
|
||||||
|
|
@ -217,10 +223,15 @@ class column_mux(pgate.pgate):
|
||||||
Add a well and implant over the whole cell. Also, add the
|
Add a well and implant over the whole cell. Also, add the
|
||||||
pwell contact (if it exists)
|
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
|
# 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.nmos_upper.by() - 0.5 * self.poly_space)
|
||||||
|
|
||||||
self.add_via_center(layers=self.active_stack,
|
self.add_via_center(layers=self.active_stack,
|
||||||
offset=active_pos,
|
offset=active_pos,
|
||||||
implant_type="p",
|
implant_type="p",
|
||||||
|
|
@ -239,5 +250,5 @@ class column_mux(pgate.pgate):
|
||||||
if "pwell" in layer:
|
if "pwell" in layer:
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=vector(0, 0),
|
offset=vector(0, 0),
|
||||||
width=self.bitcell.width,
|
width=rbc_width,
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ class precharge(design.design):
|
||||||
self.beta = parameter["beta"]
|
self.beta = parameter["beta"]
|
||||||
self.ptx_width = self.beta * parameter["min_tx_size"]
|
self.ptx_width = self.beta * parameter["min_tx_size"]
|
||||||
self.ptx_mults = 1
|
self.ptx_mults = 1
|
||||||
|
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.width = self.bitcell.width
|
||||||
self.bitcell_bl = bitcell_bl
|
self.bitcell_bl = bitcell_bl
|
||||||
self.bitcell_br = bitcell_br
|
self.bitcell_br = bitcell_br
|
||||||
|
|
|
||||||
|
|
@ -472,6 +472,12 @@ class sram_base(design, verilog, lef):
|
||||||
self.bitcell = factory.create(module_type=OPTS.bitcell)
|
self.bitcell = factory.create(module_type=OPTS.bitcell)
|
||||||
self.dff = factory.create(module_type="dff")
|
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)
|
# 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.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)
|
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.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)
|
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
|
# Create bank decoder
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.add_multi_bank_modules()
|
self.add_multi_bank_modules()
|
||||||
|
|
|
||||||
|
|
@ -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 VDD vdd\n")
|
||||||
f.write("set GND gnd\n")
|
f.write("set GND gnd\n")
|
||||||
f.write("set SUB 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")
|
f.write("gds warning default\n")
|
||||||
# These two options are temporarily disabled until Tim fixes a bug in magic related
|
# 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,
|
# to flattening channel routes and vias (hierarchy with no devices in it). Otherwise,
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,8 @@ layer["m10"] = (29, 0)
|
||||||
layer["text"] = (239, 0)
|
layer["text"] = (239, 0)
|
||||||
layer["boundary"]= (239, 0)
|
layer["boundary"]= (239, 0)
|
||||||
|
|
||||||
|
use_purpose = {}
|
||||||
|
|
||||||
# Layer names for external PDKs
|
# Layer names for external PDKs
|
||||||
layer_names = {}
|
layer_names = {}
|
||||||
layer_names["active"] = "active"
|
layer_names["active"] = "active"
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ layer["text"] = (63, 0)
|
||||||
layer["boundary"] = (63, 0)
|
layer["boundary"] = (63, 0)
|
||||||
layer["blockage"] = (83, 0)
|
layer["blockage"] = (83, 0)
|
||||||
|
|
||||||
|
use_purpose = {}
|
||||||
###################################################
|
###################################################
|
||||||
##END GDS Layer Map
|
##END GDS Layer Map
|
||||||
###################################################
|
###################################################
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,8 @@ layer["m4"] = (31, 0)
|
||||||
layer["text"] = (63, 0)
|
layer["text"] = (63, 0)
|
||||||
layer["boundary"] = (63, 0)
|
layer["boundary"] = (63, 0)
|
||||||
|
|
||||||
|
use_purpose = {}
|
||||||
|
|
||||||
# Layer names for external PDKs
|
# Layer names for external PDKs
|
||||||
layer_names = {}
|
layer_names = {}
|
||||||
layer_names["active"] = "active"
|
layer_names["active"] = "active"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue