mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' of github.com:VLSIDA/PrivateRAM into dev
This commit is contained in:
commit
17504a7da3
|
|
@ -12,6 +12,8 @@ import debug
|
|||
from vector import vector
|
||||
import tech
|
||||
import math
|
||||
import copy
|
||||
import numpy as np
|
||||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
|
||||
|
|
@ -269,6 +271,134 @@ class instance(geometry):
|
|||
p.transform(self.offset, self.mirror, self.rotate)
|
||||
new_pins.append(p)
|
||||
return new_pins
|
||||
|
||||
def calculate_transform(self, node):
|
||||
#set up the rotation matrix
|
||||
angle = math.radians(float(node.rotate))
|
||||
mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0],
|
||||
[math.sin(angle),math.cos(angle),0.0],
|
||||
[0.0,0.0,1.0]])
|
||||
|
||||
#set up translation matrix
|
||||
translateX = float(node.offset[0])
|
||||
translateY = float(node.offset[1])
|
||||
mTranslate = np.array([[1.0,0.0,translateX],
|
||||
[0.0,1.0,translateY],
|
||||
[0.0,0.0,1.0]])
|
||||
|
||||
#set up the scale matrix (handles mirror X)
|
||||
scaleX = 1.0
|
||||
if(node.mirror == 'MX'):
|
||||
scaleY = -1.0
|
||||
else:
|
||||
scaleY = 1.0
|
||||
mScale = np.array([[scaleX,0.0,0.0],
|
||||
[0.0,scaleY,0.0],
|
||||
[0.0,0.0,1.0]])
|
||||
|
||||
return (mRotate, mScale, mTranslate)
|
||||
|
||||
def apply_transform(self, mtransforms, uVector, vVector, origin):
|
||||
origin = np.dot(mtransforms[0], origin) #rotate
|
||||
uVector = np.dot(mtransforms[0], uVector) #rotate
|
||||
vVector = np.dot(mtransforms[0], vVector) #rotate
|
||||
origin = np.dot(mtransforms[1], origin) #scale
|
||||
uVector = np.dot(mtransforms[1], uVector) #scale
|
||||
vVector = np.dot(mtransforms[1], vVector) #scale
|
||||
origin = np.dot(mtransforms[2], origin)
|
||||
|
||||
return(uVector, vVector, origin)
|
||||
|
||||
def apply_path_transform(self, path):
|
||||
uVector = np.array([[1.0],[0.0],[0.0]])
|
||||
vVector = np.array([[0.0],[1.0],[0.0]])
|
||||
origin = np.array([[0.0],[0.0],[1.0]])
|
||||
|
||||
while(path):
|
||||
instance = path.pop(-1)
|
||||
mtransforms = self.calculate_transform(instance)
|
||||
(uVector, vVector, origin) = self.apply_transform(mtransforms, uVector, vVector, origin)
|
||||
|
||||
return (uVector, vVector, origin)
|
||||
|
||||
def reverse_transformation_bitcell(self, cell_name):
|
||||
path = [] # path currently follwed in bitcell search
|
||||
cell_paths = [] # saved paths to bitcells
|
||||
origin_offsets = [] # cell to bank offset
|
||||
Q_offsets = [] # Q to cell offet
|
||||
Q_bar_offsets = [] # Q_bar to cell offset
|
||||
bl_offsets = [] # bl to cell offset
|
||||
br_offsets = [] # br to cell offset
|
||||
bl_meta = [] # bl offset metadata (row,col,name)
|
||||
br_meta = [] #br offset metadata (row,col,name)
|
||||
|
||||
def walk_subtree(node):
|
||||
path.append(node)
|
||||
|
||||
if node.mod.name == cell_name:
|
||||
cell_paths.append(copy.copy(path))
|
||||
|
||||
inst_name = path[-1].name
|
||||
|
||||
# get the row and col names from the path
|
||||
row = int(path[-1].name.split('_')[-2][1:])
|
||||
col = int(path[-1].name.split('_')[-1][1:])
|
||||
|
||||
cell_bl_meta = []
|
||||
cell_br_meta = []
|
||||
|
||||
normalized_storage_nets = node.mod.get_normalized_storage_nets_offset()
|
||||
(normalized_bl_offsets, normalized_br_offsets, bl_names, br_names) = node.mod.get_normalized_bitline_offset()
|
||||
|
||||
for offset in range(len(normalized_bl_offsets)):
|
||||
for port in range(len(bl_names)):
|
||||
cell_bl_meta.append([bl_names[offset], row, col, port])
|
||||
|
||||
for offset in range(len(normalized_br_offsets)):
|
||||
for port in range(len(br_names)):
|
||||
cell_br_meta.append([br_names[offset], row, col, port])
|
||||
|
||||
Q_x = normalized_storage_nets[0][0]
|
||||
Q_y = normalized_storage_nets[0][1]
|
||||
|
||||
Q_bar_x = normalized_storage_nets[1][0]
|
||||
Q_bar_y = normalized_storage_nets[1][1]
|
||||
|
||||
if node.mirror == 'MX':
|
||||
Q_y = -1 * Q_y
|
||||
Q_bar_y = -1 * Q_bar_y
|
||||
|
||||
for pair in range(len(normalized_bl_offsets)):
|
||||
normalized_bl_offsets[pair] = (normalized_bl_offsets[pair][0],
|
||||
-1 * normalized_bl_offsets[pair][1])
|
||||
|
||||
for pair in range(len(normalized_br_offsets)):
|
||||
normalized_br_offsets[pair] = (normalized_br_offsets[pair][0],
|
||||
-1 * normalized_br_offsets[pair][1])
|
||||
|
||||
|
||||
Q_offsets.append([Q_x, Q_y])
|
||||
Q_bar_offsets.append([Q_bar_x, Q_bar_y])
|
||||
|
||||
|
||||
bl_offsets.append(normalized_bl_offsets)
|
||||
br_offsets.append(normalized_br_offsets)
|
||||
|
||||
bl_meta.append(cell_bl_meta)
|
||||
br_meta.append(cell_br_meta)
|
||||
|
||||
elif node.mod.insts is not []:
|
||||
for instance in node.mod.insts:
|
||||
walk_subtree(instance)
|
||||
path.pop(-1)
|
||||
|
||||
walk_subtree(self)
|
||||
for path in cell_paths:
|
||||
vector_spaces = self.apply_path_transform(path)
|
||||
origin = vector_spaces[2]
|
||||
origin_offsets.append([origin[0], origin[1]])
|
||||
|
||||
return(origin_offsets, Q_offsets, Q_bar_offsets, bl_offsets, br_offsets, bl_meta, br_meta)
|
||||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
|
|
|
|||
|
|
@ -1324,6 +1324,8 @@ class layout():
|
|||
pdf.drawLayout()
|
||||
pdf.writeToFile(pdf_name)
|
||||
|
||||
|
||||
|
||||
def print_attr(self):
|
||||
"""Prints a list of attributes for the current layout object"""
|
||||
debug.info(0,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class bitcell(bitcell_base.bitcell_base):
|
|||
props.bitcell.cell_6t.pin.vdd,
|
||||
props.bitcell.cell_6t.pin.gnd]
|
||||
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
|
||||
storage_nets = ['Q', 'Qbar']
|
||||
storage_nets = ['Q', 'Q_bar']
|
||||
|
||||
(width, height) = utils.get_libcell_size("cell_6t",
|
||||
GDS["unit"],
|
||||
|
|
@ -51,7 +51,7 @@ class bitcell(bitcell_base.bitcell_base):
|
|||
self.add_pin_types(self.type_list)
|
||||
self.nets_match = self.do_nets_exist(self.storage_nets)
|
||||
|
||||
debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells")
|
||||
# debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells")
|
||||
|
||||
def get_all_wl_names(self):
|
||||
""" Creates a list of all wordline pin names """
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
import debug
|
||||
import design
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
from tech import parameter, drc
|
||||
from tech import parameter, drc, layer
|
||||
|
||||
|
||||
class bitcell_base(design.design):
|
||||
|
|
@ -78,7 +79,85 @@ class bitcell_base(design.design):
|
|||
fmt_str = "Storage nodes={} not found in spice file."
|
||||
debug.info(1, fmt_str.format(self.storage_nets))
|
||||
return None
|
||||
|
||||
|
||||
def get_storage_net_offset(self):
|
||||
"""
|
||||
Gets the location of the storage net labels to add top level
|
||||
labels for pex simulation.
|
||||
"""
|
||||
# If we generated the bitcell, we already know where Q and Q_bar are
|
||||
if OPTS.bitcell is not "pbitcell":
|
||||
self.storage_net_offsets = []
|
||||
for i in range(len(self.get_storage_net_names())):
|
||||
for text in self.gds.getTexts(layer["m1"]):
|
||||
if self.storage_nets[i] == text.textString.rstrip('\x00'):
|
||||
self.storage_net_offsets.append(text.coordinates[0])
|
||||
|
||||
for i in range(len(self.storage_net_offsets)):
|
||||
self.storage_net_offsets[i] = tuple([self.gds.info["units"][0] * x for x in self.storage_net_offsets[i]])
|
||||
|
||||
|
||||
return(self.storage_net_offsets)
|
||||
|
||||
def get_bitline_offset(self):
|
||||
|
||||
bl_names = self.get_all_bl_names()
|
||||
br_names = self.get_all_br_names()
|
||||
|
||||
found_bl = []
|
||||
found_br = []
|
||||
|
||||
self.bl_offsets = []
|
||||
self.br_offsets = []
|
||||
|
||||
for i in range(len(bl_names)):
|
||||
for text in self.gds.getTexts(layer["m2"]):
|
||||
if not bl_names[i] in found_bl:
|
||||
if bl_names[i] == text.textString.rstrip('\x00'):
|
||||
self.bl_offsets.append(text.coordinates[0])
|
||||
found_bl.append(bl_names[i])
|
||||
|
||||
continue
|
||||
|
||||
for i in range(len(br_names)):
|
||||
for text in self.gds.getTexts(layer["m2"]):
|
||||
if not br_names[i] in found_br:
|
||||
if br_names[i] == text.textString.rstrip('\x00'):
|
||||
self.br_offsets.append(text.coordinates[0])
|
||||
found_br.append(br_names[i])
|
||||
continue
|
||||
|
||||
for i in range(len(self.bl_offsets)):
|
||||
self.bl_offsets[i] = tuple([self.gds.info["units"][0] * x for x in self.bl_offsets[i]])
|
||||
|
||||
for i in range(len(self.br_offsets)):
|
||||
self.br_offsets[i] = tuple([self.gds.info["units"][0] * x for x in self.br_offsets[i]])
|
||||
|
||||
return(self.bl_offsets, self.br_offsets, found_bl, found_br)
|
||||
|
||||
def get_normalized_storage_nets_offset(self):
|
||||
"""
|
||||
Convert storage net offset to be relative to the bottom left corner
|
||||
of the bitcell. This is useful for making sense of offsets outside
|
||||
of the bitcell.
|
||||
"""
|
||||
if OPTS.bitcell is not "pbitcell":
|
||||
normalized_storage_net_offset = self.get_storage_net_offset()
|
||||
|
||||
else:
|
||||
net_offset = self.get_storage_net_offset()
|
||||
Q_x = net_offset[0][0] - self.leftmost_xpos
|
||||
Q_y = net_offset[0][1] - self.botmost_ypos
|
||||
Q_bar_x = net_offset[1][0] - self.leftmost_xpos
|
||||
Q_bar_y = net_offset[1][1] - self.botmost_ypos
|
||||
|
||||
normalized_storage_net_offset = [[Q_x,Q_y],[Q_bar_x,Q_bar_y]]
|
||||
|
||||
return normalized_storage_net_offset
|
||||
|
||||
def get_normalized_bitline_offset(self):
|
||||
return self.get_bitline_offset()
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
By default, bitcells won't be part of the graph.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
|
||||
self.replica_bitcell = replica_bitcell
|
||||
self.dummy_bitcell = dummy_bitcell
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
self.Q_bar = "Q_bar"
|
||||
self.Q = "Q"
|
||||
self.storage_nets = [self.Q, self.Q_bar]
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
""" Determine size of transistors and add ptx modules """
|
||||
# if there are any read/write ports,
|
||||
|
|
@ -352,6 +352,11 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
self.right_building_edge = right_inverter_xpos \
|
||||
+ self.inverter_nmos.active_width
|
||||
|
||||
def add_pex_labels(self, left_inverter_offset, right_inverter_offset):
|
||||
self.add_label("Q", "metal1", left_inverter_offset)
|
||||
self.add_label("Q_bar", "metal1", right_inverter_offset)
|
||||
self.storage_net_offsets = [left_inverter_offset, right_inverter_offset]
|
||||
|
||||
def route_storage(self):
|
||||
""" Routes inputs and outputs of inverters to cross couple them """
|
||||
# connect input (gate) of inverters
|
||||
|
|
@ -396,6 +401,16 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
gate_offset_left = vector(self.inverter_nmos_left.get_pin("G").rc().x,
|
||||
contact_offset_right.y)
|
||||
self.add_path("poly", [contact_offset_right, gate_offset_left])
|
||||
if OPTS.use_pex:
|
||||
# add labels to cross couple inverter for extracted simulation
|
||||
contact_offset_left_output = vector(self.inverter_nmos_left.get_pin("D").rc().x \
|
||||
+ 0.5 * contact.poly.height,
|
||||
self.cross_couple_upper_ypos)
|
||||
|
||||
contact_offset_right_output = vector(self.inverter_nmos_right.get_pin("S").lc().x \
|
||||
- 0.5*contact.poly.height,
|
||||
self.cross_couple_lower_ypos)
|
||||
self.add_pex_labels(contact_offset_left_output, contact_offset_right_output)
|
||||
|
||||
def route_rails(self):
|
||||
""" Adds gnd and vdd rails and connects them to the inverters """
|
||||
|
|
|
|||
|
|
@ -136,19 +136,18 @@ class delay(simulation):
|
|||
"""
|
||||
|
||||
self.bitline_volt_meas = []
|
||||
|
||||
self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO",
|
||||
self.bl_name))
|
||||
self.bl_name))
|
||||
self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO
|
||||
self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO",
|
||||
self.br_name))
|
||||
self.br_name))
|
||||
self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO
|
||||
|
||||
self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE",
|
||||
self.bl_name))
|
||||
self.bl_name))
|
||||
self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE
|
||||
self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE",
|
||||
self.br_name))
|
||||
self.br_name))
|
||||
self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE
|
||||
return self.bitline_volt_meas
|
||||
|
||||
|
|
@ -181,8 +180,12 @@ class delay(simulation):
|
|||
self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name),
|
||||
meas.targ_name_no_port))
|
||||
self.dout_volt_meas[-1].meta_str = meas.meta_str
|
||||
|
||||
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name+"{}", "FALL", "RISE", measure_scale=1e9)
|
||||
|
||||
if not OPTS.use_pex:
|
||||
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name+"{}", "FALL", "RISE", measure_scale=1e9)
|
||||
else:
|
||||
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9)
|
||||
|
||||
self.sen_meas.meta_str = sram_op.READ_ZERO
|
||||
self.sen_meas.meta_add_delay = True
|
||||
|
||||
|
|
@ -228,8 +231,13 @@ class delay(simulation):
|
|||
storage_names = cell_inst.mod.get_storage_net_names()
|
||||
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
||||
"supported for characterization. Storage nets={}").format(storage_names))
|
||||
q_name = cell_name+'.'+str(storage_names[0])
|
||||
qbar_name = cell_name+'.'+str(storage_names[1])
|
||||
if not OPTS.use_pex:
|
||||
q_name = cell_name+'.'+str(storage_names[0])
|
||||
qbar_name = cell_name+'.'+str(storage_names[1])
|
||||
else:
|
||||
bank_num = self.sram.get_bank_num(self.sram.name, bit_row, bit_col)
|
||||
q_name = "bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col)
|
||||
qbar_name = "bitcell_Q_bar_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col)
|
||||
|
||||
# Bit measures, measurements times to be defined later. The measurement names must be unique
|
||||
# but they is enforced externally. {} added to names to differentiate between ports allow the
|
||||
|
|
@ -271,37 +279,50 @@ class delay(simulation):
|
|||
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
||||
|
||||
port = self.read_ports[0]
|
||||
self.graph.get_all_paths('{}{}'.format("clk", port),
|
||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||
|
||||
sen_with_port = self.get_sen_name(self.graph.all_paths)
|
||||
if sen_with_port.endswith(str(port)):
|
||||
self.sen_name = sen_with_port[:-len(str(port))]
|
||||
else:
|
||||
self.sen_name = sen_with_port
|
||||
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
|
||||
if not OPTS.use_pex:
|
||||
self.graph.get_all_paths('{}{}'.format("clk", port),
|
||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||
|
||||
debug.info(2,"s_en name = {}".format(self.sen_name))
|
||||
|
||||
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
|
||||
port_pos = -1-len(str(self.probe_data))-len(str(port))
|
||||
|
||||
if bl_name_port.endswith(str(port)+"_"+str(self.probe_data)):
|
||||
self.bl_name = bl_name_port[:port_pos] +"{}"+ bl_name_port[port_pos+len(str(port)):]
|
||||
elif not bl_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0
|
||||
self.bl_name = bl_name_port
|
||||
else:
|
||||
self.bl_name = bl_name_port
|
||||
debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.")
|
||||
sen_with_port = self.get_sen_name(self.graph.all_paths)
|
||||
if sen_with_port.endswith(str(port)):
|
||||
self.sen_name = sen_with_port[:-len(str(port))]
|
||||
else:
|
||||
self.sen_name = sen_with_port
|
||||
debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.")
|
||||
|
||||
debug.info(2,"s_en name = {}".format(self.sen_name))
|
||||
|
||||
if br_name_port.endswith(str(port)+"_"+str(self.probe_data)):
|
||||
self.br_name = br_name_port[:port_pos] +"{}"+ br_name_port[port_pos+len(str(port)):]
|
||||
elif not br_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0
|
||||
self.br_name = br_name_port
|
||||
bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port)
|
||||
port_pos = -1-len(str(self.probe_data))-len(str(port))
|
||||
|
||||
if bl_name_port.endswith(str(port)+"_"+str(self.probe_data)):
|
||||
self.bl_name = bl_name_port[:port_pos] +"{}"+ bl_name_port[port_pos+len(str(port)):]
|
||||
elif not bl_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0
|
||||
self.bl_name = bl_name_port
|
||||
else:
|
||||
self.bl_name = bl_name_port
|
||||
debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.")
|
||||
|
||||
if br_name_port.endswith(str(port)+"_"+str(self.probe_data)):
|
||||
self.br_name = br_name_port[:port_pos] +"{}"+ br_name_port[port_pos+len(str(port)):]
|
||||
elif not br_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0
|
||||
self.br_name = br_name_port
|
||||
else:
|
||||
self.br_name = br_name_port
|
||||
debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.")
|
||||
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
||||
else:
|
||||
self.br_name = br_name_port
|
||||
debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.")
|
||||
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
||||
self.graph.get_all_paths('{}{}'.format("clk", port),
|
||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||
|
||||
self.sen_name = self.get_sen_name(self.graph.all_paths)
|
||||
debug.info(2,"s_en name = {}".format(self.sen_name))
|
||||
|
||||
|
||||
self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size-1)
|
||||
self.br_name = "br{0}_{1}".format(port, OPTS.word_size-1)
|
||||
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
||||
|
||||
|
||||
def get_sen_name(self, paths, assumed_port=None):
|
||||
"""
|
||||
|
|
@ -315,7 +336,8 @@ class delay(simulation):
|
|||
debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
|
||||
enable_name = sa_mods[0].get_enable_name()
|
||||
sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
|
||||
|
||||
if OPTS.use_pex:
|
||||
sen_name = sen_name.split('.')[-1]
|
||||
return sen_name
|
||||
|
||||
def get_bl_name(self, paths, port):
|
||||
|
|
@ -331,7 +353,9 @@ class delay(simulation):
|
|||
exclude_set = self.get_bl_name_search_exclusions()
|
||||
for int_net in [cell_bl, cell_br]:
|
||||
bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
|
||||
|
||||
if OPTS.use_pex:
|
||||
for i in range(len(bl_names)):
|
||||
bl_names[i] = bl_names[i].split('.')[-1]
|
||||
return bl_names[0], bl_names[1]
|
||||
|
||||
|
||||
|
|
@ -422,8 +446,13 @@ class delay(simulation):
|
|||
|
||||
# instantiate the sram
|
||||
self.sf.write("\n* Instantiation of the SRAM\n")
|
||||
self.stim.inst_model(pins=self.pins,
|
||||
model_name=self.sram.name)
|
||||
if not OPTS.use_pex:
|
||||
self.stim.inst_model(pins=self.pins,
|
||||
model_name=self.sram.name)
|
||||
else:
|
||||
self.stim.inst_sram_pex(pins=self.pins,
|
||||
model_name=self.sram.name)
|
||||
|
||||
self.sf.write("\n* SRAM output loads\n")
|
||||
for port in self.read_ports:
|
||||
for i in range(self.word_size):
|
||||
|
|
|
|||
|
|
@ -56,7 +56,30 @@ class stimuli():
|
|||
for pin in pins:
|
||||
self.sf.write("{0} ".format(pin))
|
||||
self.sf.write("{0}\n".format(model_name))
|
||||
|
||||
def inst_sram_pex(self, pins, model_name):
|
||||
self.sf.write("X{0} ".format(model_name))
|
||||
for pin in pins:
|
||||
self.sf.write("{0} ".format(pin))
|
||||
for bank in range(OPTS.num_banks):
|
||||
row = int(OPTS.num_words / OPTS.words_per_row) - 1
|
||||
col = int(OPTS.word_size * OPTS.words_per_row) - 1
|
||||
self.sf.write("bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col))
|
||||
self.sf.write("bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col))
|
||||
# can't add all bitcells to top level due to ngspice max port count of 1005
|
||||
# for row in range(int(OPTS.num_words / OPTS.words_per_row)):
|
||||
# for col in range(int(OPTS.word_size * OPTS.words_per_row)):
|
||||
# self.sf.write("bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col))
|
||||
# self.sf.write("bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col))
|
||||
for bank in range(OPTS.num_banks):
|
||||
for col in range(OPTS.word_size * OPTS.words_per_row):
|
||||
for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports):
|
||||
self.sf.write("bl{0}_{1} ".format(port, col))
|
||||
self.sf.write("br{0}_{1} ".format(port, col))
|
||||
|
||||
|
||||
self.sf.write("s_en{0} ".format(bank))
|
||||
self.sf.write("{0}\n".format(model_name))
|
||||
|
||||
def create_inverter(self, size=1, beta=2.5):
|
||||
""" Generates inverter for the top level signals (only for sim purposes) """
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ class bank(design.design):
|
|||
self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1)
|
||||
self.bank_array_ur = self.bitcell_array_inst.ur()
|
||||
self.bank_array_ul = self.bitcell_array_inst.ul()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
|
|
@ -1050,7 +1049,7 @@ class bank(design.design):
|
|||
inp_is_rise)
|
||||
|
||||
return stage_effort_list
|
||||
|
||||
|
||||
def get_wl_en_cin(self):
|
||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||
# wl_en only used in the wordline driver.
|
||||
|
|
|
|||
|
|
@ -869,7 +869,6 @@ class control_logic(design.design):
|
|||
offset=pin.ll(),
|
||||
height=pin.height(),
|
||||
width=pin.width())
|
||||
|
||||
def get_delays_to_wl(self):
|
||||
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
|
||||
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
|
||||
|
|
|
|||
|
|
@ -643,5 +643,8 @@ class sram_1bank(sram_base):
|
|||
"""Gets the spice name of the target bitcell."""
|
||||
# Sanity check in case it was forgotten
|
||||
if inst_name.find('x') != 0:
|
||||
inst_name = 'x' + inst_name
|
||||
return self.bank_inst.mod.get_cell_name(inst_name + '.x' + self.bank_inst.name, row, col)
|
||||
inst_name = 'x'+inst_name
|
||||
return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col)
|
||||
|
||||
def get_bank_num(self, inst_name, row, col):
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ from design import design
|
|||
from verilog import verilog
|
||||
from lef import lef
|
||||
from sram_factory import factory
|
||||
from tech import drc
|
||||
import numpy as np
|
||||
import logical_effort
|
||||
|
||||
|
||||
class sram_base(design, verilog, lef):
|
||||
|
|
@ -84,8 +87,71 @@ class sram_base(design, verilog, lef):
|
|||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
|
||||
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
self.add_pin("vdd","POWER")
|
||||
self.add_pin("gnd","GROUND")
|
||||
|
||||
def add_global_pex_labels(self):
|
||||
"""
|
||||
Add pex labels at the sram level for spice analysis
|
||||
"""
|
||||
|
||||
# add pex labels for bitcells
|
||||
for bank_num in range(len(self.bank_insts)):
|
||||
bank = self.bank_insts[bank_num]
|
||||
pex_data = bank.reverse_transformation_bitcell(bank.mod.bitcell.name)
|
||||
|
||||
bank_offset = pex_data[0] # offset bank relative to sram
|
||||
Q_offset = pex_data[1] # offset of storage relative to bank
|
||||
Q_bar_offset = pex_data[2] # offset of storage relative to bank
|
||||
bl_offsets = pex_data[3]
|
||||
br_offsets = pex_data[4]
|
||||
bl_meta = pex_data[5]
|
||||
br_meta = pex_data[6]
|
||||
|
||||
bl = []
|
||||
br = []
|
||||
|
||||
storage_layer_name = "m1"
|
||||
bitline_layer_name = "m2"
|
||||
|
||||
for cell in range(len(bank_offset)):
|
||||
Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]]
|
||||
Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]]
|
||||
OPTS.words_per_row = self.words_per_row
|
||||
self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q)
|
||||
self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar)
|
||||
|
||||
for cell in range(len(bl_offsets)):
|
||||
col = bl_meta[cell][0][2]
|
||||
for bitline in range(len(bl_offsets[cell])):
|
||||
bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]]
|
||||
bl.append([bitline_location, bl_meta[cell][bitline][3], col])
|
||||
|
||||
for cell in range(len(br_offsets)):
|
||||
col = br_meta[cell][0][2]
|
||||
for bitline in range(len(br_offsets[cell])):
|
||||
bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]]
|
||||
br.append([bitline_location, br_meta[cell][bitline][3], col])
|
||||
|
||||
for i in range(len(bl)):
|
||||
self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0])
|
||||
|
||||
for i in range(len(br)):
|
||||
self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0])
|
||||
|
||||
# add pex labels for control logic
|
||||
for i in range (len(self.control_logic_insts)):
|
||||
instance = self.control_logic_insts[i]
|
||||
control_logic_offset = instance.offset
|
||||
for output in instance.mod.output_list:
|
||||
pin = instance.mod.get_pin(output)
|
||||
pin.transform([0,0], instance.mirror, instance.rotate)
|
||||
offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]]
|
||||
self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
""" Netlist creation """
|
||||
|
|
@ -124,6 +190,8 @@ class sram_base(design, verilog, lef):
|
|||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
self.height = highest_coord[1]
|
||||
if OPTS.use_pex:
|
||||
self.add_global_pex_labels()
|
||||
self.add_boundary(ll=vector(0, 0),
|
||||
ur=vector(self.width, self.height))
|
||||
|
||||
|
|
|
|||
|
|
@ -109,21 +109,21 @@ def write_magic_script(cell_name, extract=False, final_verification=False):
|
|||
# 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
|
||||
# f.write(pre + "ext2spice lvs\n")
|
||||
f.write(pre + "ext2spice hierarchy on\n")
|
||||
f.write(pre + "ext2spice format ngspice\n")
|
||||
f.write(pre + "ext2spice cthresh infinite\n")
|
||||
f.write(pre + "ext2spice rthresh infinite\n")
|
||||
f.write(pre + "ext2spice renumber off\n")
|
||||
f.write(pre + "ext2spice scale off\n")
|
||||
f.write(pre + "ext2spice blackbox on\n")
|
||||
f.write(pre + "ext2spice subcircuit top auto\n")
|
||||
f.write(pre + "ext2spice global off\n")
|
||||
#f.write(pre+"ext2spice lvs\n")
|
||||
f.write(pre+"ext2spice hierarchy on\n")
|
||||
f.write(pre+"ext2spice format ngspice\n")
|
||||
f.write(pre+"ext2spice cthresh infinite\n")
|
||||
f.write(pre+"ext2spice rthresh infinite\n")
|
||||
f.write(pre+"ext2spice renumber off\n")
|
||||
f.write(pre+"ext2spice scale off\n")
|
||||
f.write(pre+"ext2spice blackbox on\n")
|
||||
f.write(pre+"ext2spice subcircuit top on\n")
|
||||
f.write(pre+"ext2spice global off\n")
|
||||
|
||||
# Can choose hspice, ngspice, or spice3,
|
||||
# but they all seem compatible enough.
|
||||
#f.write(pre + "ext2spice format ngspice\n")
|
||||
f.write(pre + "ext2spice {}\n".format(cell_name))
|
||||
f.write(pre+"ext2spice format ngspice\n")
|
||||
f.write(pre+"ext2spice {}\n".format(cell_name))
|
||||
f.write("quit -noprompt\n")
|
||||
f.write("EOF\n")
|
||||
|
||||
|
|
@ -413,13 +413,13 @@ def write_script_pex_rule(gds_name,cell_name,output):
|
|||
else:
|
||||
pre = ""
|
||||
f.write(pre+"extract\n".format(cell_name))
|
||||
#f.write(pre+"ext2spice hierarchy on\n")
|
||||
#f.write(pre+"ext2spice format ngspice\n")
|
||||
#f.write(pre+"ext2spice renumber off\n")
|
||||
#f.write(pre+"ext2spice scale off\n")
|
||||
#f.write(pre+"ext2spice blackbox on\n")
|
||||
f.write(pre+"ext2spice hierarchy off\n")
|
||||
f.write(pre+"ext2spice format ngspice\n")
|
||||
f.write(pre+"ext2spice renumber off\n")
|
||||
f.write(pre+"ext2spice scale off\n")
|
||||
f.write(pre+"ext2spice blackbox on\n")
|
||||
f.write(pre+"ext2spice subcircuit top on\n")
|
||||
#f.write(pre+"ext2spice global off\n")
|
||||
f.write(pre+"ext2spice global off\n")
|
||||
f.write(pre+"ext2spice {}\n".format(cell_name))
|
||||
f.write("quit -noprompt\n")
|
||||
f.write("eof\n")
|
||||
|
|
@ -442,31 +442,49 @@ def correct_port(name, output_file_name, ref_file_name):
|
|||
pex_file = open(output_file_name, "r")
|
||||
contents = pex_file.read()
|
||||
# locate the start of circuit definition line
|
||||
match = re.search(".subckt " + str(name) + ".*", contents)
|
||||
match = re.search(r'^\.subckt+[^M]*', contents, re.MULTILINE)
|
||||
match_index_start = match.start()
|
||||
pex_file.seek(match_index_start)
|
||||
rest_text = pex_file.read()
|
||||
# locate the end of circuit definition line
|
||||
match = re.search(r'\n', rest_text)
|
||||
match_index_end = match.start()
|
||||
match_index_end = match.end()
|
||||
# store the unchanged part of pex file in memory
|
||||
pex_file.seek(0)
|
||||
part1 = pex_file.read(match_index_start)
|
||||
pex_file.seek(match_index_start + match_index_end)
|
||||
pex_file.seek(match_index_end)
|
||||
part2 = pex_file.read()
|
||||
|
||||
bitcell_list = "+ "
|
||||
if OPTS.words_per_row:
|
||||
for bank in range(OPTS.num_banks):
|
||||
for bank in range(OPTS.num_banks):
|
||||
row = int(OPTS.num_words / OPTS.words_per_row) - 1
|
||||
col = int(OPTS.word_size * OPTS.words_per_row) - 1
|
||||
bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col)
|
||||
bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col)
|
||||
for col in range(OPTS.word_size * OPTS.words_per_row):
|
||||
for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports):
|
||||
bitcell_list += "bl{0}_{1} ".format(bank, col)
|
||||
bitcell_list += "br{0}_{1} ".format(bank, col)
|
||||
bitcell_list += "\n"
|
||||
control_list = "+ "
|
||||
if OPTS.words_per_row:
|
||||
for bank in range(OPTS.num_banks):
|
||||
control_list += "bank_{}/s_en0".format(bank)
|
||||
control_list += '\n'
|
||||
|
||||
part2 = bitcell_list + control_list + part2
|
||||
|
||||
pex_file.close()
|
||||
|
||||
# obtain the correct definition line from the original spice file
|
||||
sp_file = open(ref_file_name, "r")
|
||||
contents = sp_file.read()
|
||||
circuit_title = re.search(".SUBCKT " + str(name) + ".*\n", contents)
|
||||
circuit_title = re.search(".SUBCKT " + str(name) + ".*", contents)
|
||||
circuit_title = circuit_title.group()
|
||||
sp_file.close()
|
||||
|
||||
# write the new pex file with info in the memory
|
||||
output_file = open(output_file_name, "w")
|
||||
output_file.write(part1)
|
||||
output_file.write(circuit_title)
|
||||
output_file.write(circuit_title+'\n')
|
||||
output_file.write(part2)
|
||||
output_file.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
|
||||
.SUBCKT cell_6t bl br wl vdd gnd
|
||||
* Inverter 1
|
||||
MM0 Qbar Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM4 Qbar Q vdd vdd PMOS_VTG W=90n L=50n
|
||||
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n
|
||||
|
||||
* Inverer 2
|
||||
MM1 Q Qbar gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM5 Q Qbar vdd vdd PMOS_VTG W=90n L=50n
|
||||
MM1 Q Q_bar gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n
|
||||
|
||||
* Access transistors
|
||||
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
|
||||
MM2 br wl Qbar gnd NMOS_VTG W=135.00n L=50n
|
||||
MM2 br wl Q_bar gnd NMOS_VTG W=135.00n L=50n
|
||||
.ENDS cell_6t
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
|
||||
.SUBCKT dummy_cell_6t bl br wl vdd gnd
|
||||
* Inverter 1
|
||||
MM0 Qbar Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM4 Qbar Q vdd vdd PMOS_VTG W=90n L=50n
|
||||
MM0 Q_bar Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM4 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n
|
||||
|
||||
* Inverer 2
|
||||
MM1 Q Qbar gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM5 Q Qbar vdd vdd PMOS_VTG W=90n L=50n
|
||||
MM1 Q Q_bar gnd gnd NMOS_VTG W=205.00n L=50n
|
||||
MM5 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n
|
||||
|
||||
* Access transistors
|
||||
MM3 bl_noconn wl Q gnd NMOS_VTG W=135.00n L=50n
|
||||
MM2 br_noconn wl Qbar gnd NMOS_VTG W=135.00n L=50n
|
||||
MM2 br_noconn wl Q_bar gnd NMOS_VTG W=135.00n L=50n
|
||||
.ENDS cell_6t
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1542220294
|
||||
timestamp 1577066542
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -47,12 +47,17 @@ rect 17 33 21 37
|
|||
rect 25 29 29 37
|
||||
rect 33 33 37 37
|
||||
rect 41 33 45 37
|
||||
rect 9 17 13 21
|
||||
rect 25 17 29 23
|
||||
rect 41 17 45 21
|
||||
<< pdcontact >>
|
||||
rect 17 54 21 58
|
||||
rect 25 54 29 58
|
||||
rect 33 54 37 58
|
||||
<< psubstratepcontact >>
|
||||
rect 25 9 29 13
|
||||
<< nsubstratencontact >>
|
||||
rect 25 68 29 72
|
||||
<< polysilicon >>
|
||||
rect 22 57 24 60
|
||||
rect 30 57 32 60
|
||||
|
|
@ -103,19 +108,16 @@ rect 0 2 16 6
|
|||
rect 20 2 34 6
|
||||
rect 38 2 54 6
|
||||
<< m2contact >>
|
||||
rect 25 68 29 72
|
||||
rect 25 54 29 58
|
||||
rect 2 33 6 37
|
||||
rect 48 33 52 37
|
||||
rect 16 24 20 28
|
||||
rect 34 24 38 28
|
||||
rect 16 2 20 6
|
||||
rect 34 2 38 6
|
||||
<< pdm12contact >>
|
||||
rect 25 54 29 58
|
||||
<< ndm12contact >>
|
||||
rect 9 17 13 21
|
||||
rect 41 17 45 21
|
||||
<< nsm12contact >>
|
||||
rect 25 68 29 72
|
||||
rect 16 2 20 6
|
||||
rect 34 2 38 6
|
||||
<< metal2 >>
|
||||
rect 2 37 6 72
|
||||
rect 2 0 6 33
|
||||
|
|
@ -139,4 +141,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1542220294
|
||||
timestamp 1577067400
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -47,12 +47,17 @@ rect 17 33 21 37
|
|||
rect 25 29 29 37
|
||||
rect 33 33 37 37
|
||||
rect 41 33 45 37
|
||||
rect 9 17 13 21
|
||||
rect 25 17 29 23
|
||||
rect 41 17 45 21
|
||||
<< pdcontact >>
|
||||
rect 17 54 21 58
|
||||
rect 25 54 29 58
|
||||
rect 33 54 37 58
|
||||
<< psubstratepcontact >>
|
||||
rect 25 9 29 13
|
||||
<< nsubstratencontact >>
|
||||
rect 25 68 29 72
|
||||
<< polysilicon >>
|
||||
rect 22 57 24 60
|
||||
rect 30 57 32 60
|
||||
|
|
@ -103,19 +108,16 @@ rect 0 2 16 6
|
|||
rect 20 2 34 6
|
||||
rect 38 2 54 6
|
||||
<< m2contact >>
|
||||
rect 25 68 29 72
|
||||
rect 25 54 29 58
|
||||
rect 2 33 6 37
|
||||
rect 48 33 52 37
|
||||
rect 16 24 20 28
|
||||
rect 34 24 38 28
|
||||
rect 16 2 20 6
|
||||
rect 34 2 38 6
|
||||
<< pdm12contact >>
|
||||
rect 25 54 29 58
|
||||
<< ndm12contact >>
|
||||
rect 9 17 13 21
|
||||
rect 41 17 45 21
|
||||
<< nsm12contact >>
|
||||
rect 25 68 29 72
|
||||
rect 16 2 20 6
|
||||
rect 34 2 38 6
|
||||
<< metal2 >>
|
||||
rect 2 37 6 72
|
||||
rect 2 0 6 33
|
||||
|
|
@ -139,4 +141,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1560809302
|
||||
timestamp 1577163318
|
||||
<< nwell >>
|
||||
rect -8 35 42 57
|
||||
<< pwell >>
|
||||
|
|
@ -115,4 +115,6 @@ rlabel m2contact 17 52 17 52 5 vdd
|
|||
rlabel metal2 8 49 8 49 1 bl
|
||||
rlabel metal2 26 49 26 49 1 br
|
||||
rlabel metal1 4 13 4 13 1 wl
|
||||
rlabel polycontact 17 37 17 37 1 Q
|
||||
rlabel polycontact 23 28 23 28 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1562188987
|
||||
timestamp 1577067400
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -133,4 +133,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1562189027
|
||||
timestamp 1577067400
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -133,4 +133,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1560809362
|
||||
timestamp 1577067400
|
||||
<< nwell >>
|
||||
rect -8 35 42 57
|
||||
<< pwell >>
|
||||
|
|
@ -112,4 +112,6 @@ rlabel m2contact 17 52 17 52 5 vdd
|
|||
rlabel metal2 8 49 8 49 1 bl
|
||||
rlabel metal2 26 49 26 49 1 br
|
||||
rlabel metal1 4 13 4 13 1 wl
|
||||
rlabel polycontact 17 37 17 37 1 Q
|
||||
rlabel polycontact 23 28 23 28 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1542221056
|
||||
timestamp 1577067400
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -142,4 +142,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1542221056
|
||||
timestamp 1577067446
|
||||
<< nwell >>
|
||||
rect 0 46 54 75
|
||||
<< pwell >>
|
||||
|
|
@ -142,4 +142,6 @@ rlabel metal2 4 7 4 7 2 bl0
|
|||
rlabel metal2 11 7 11 7 1 bl1
|
||||
rlabel metal2 43 7 43 7 1 br1
|
||||
rlabel metal2 50 7 50 7 8 br0
|
||||
rlabel polycontact 29 49 29 49 1 Q
|
||||
rlabel polycontact 25 42 25 42 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1560809329
|
||||
timestamp 1577067503
|
||||
<< nwell >>
|
||||
rect -8 35 42 57
|
||||
<< pwell >>
|
||||
|
|
@ -116,4 +116,6 @@ rlabel m2contact 17 52 17 52 5 vdd
|
|||
rlabel metal2 8 49 8 49 1 bl
|
||||
rlabel metal2 26 49 26 49 1 br
|
||||
rlabel metal1 4 13 4 13 1 wl
|
||||
rlabel polycontact 17 37 17 37 1 Q
|
||||
rlabel polycontact 23 28 23 28 1 Q_bar
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
* SPICE3 file created from cell_6t.ext - technology: scmos
|
||||
|
||||
* Inverter 1
|
||||
M1000 Q Qbar vdd vdd p w=0.6u l=0.8u
|
||||
M1002 Q Qbar gnd gnd n w=1.6u l=0.4u
|
||||
M1000 Q Q_bar vdd vdd p w=0.6u l=0.8u
|
||||
M1002 Q Q_bar gnd gnd n w=1.6u l=0.4u
|
||||
|
||||
* Inverter 2
|
||||
M1001 vdd Q Qbar vdd p w=0.6u l=0.8u
|
||||
M1003 gnd Q Qbar gnd n w=1.6u l=0.4u
|
||||
M1001 vdd Q Q_bar vdd p w=0.6u l=0.8u
|
||||
M1003 gnd Q Q_bar gnd n w=1.6u l=0.4u
|
||||
|
||||
* Access transistors
|
||||
M1004 Q wl bl gnd n w=0.8u l=0.4u
|
||||
M1005 Qbar wl br gnd n w=0.8u l=0.4u
|
||||
M1005 Q_bar wl br gnd n w=0.8u l=0.4u
|
||||
|
||||
.ENDS
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
.SUBCKT dummy_cell_6t bl br wl vdd gnd
|
||||
|
||||
* Inverter 1
|
||||
M1000 Q Qbar vdd vdd p w=0.6u l=0.8u
|
||||
M1002 Q Qbar gnd gnd n w=1.6u l=0.4u
|
||||
M1000 Q Q_bar vdd vdd p w=0.6u l=0.8u
|
||||
M1002 Q Q_bar gnd gnd n w=1.6u l=0.4u
|
||||
|
||||
* Inverter 2
|
||||
M1001 vdd Q Qbar vdd p w=0.6u l=0.8u
|
||||
M1003 gnd Q Qbar gnd n w=1.6u l=0.4u
|
||||
M1001 vdd Q Q_bar vdd p w=0.6u l=0.8u
|
||||
M1003 gnd Q Q_bar gnd n w=1.6u l=0.4u
|
||||
|
||||
* Access transistors
|
||||
M1004 Q wl bl_noconn gnd n w=0.8u l=0.4u
|
||||
M1005 Qbar wl br_noconn gnd n w=0.8u l=0.4u
|
||||
M1005 Q_bar wl br_noconn gnd n w=0.8u l=0.4u
|
||||
|
||||
.ENDS
|
||||
|
|
|
|||
Loading…
Reference in New Issue