Merge remote-tracking branch 'origin/dev' into tech_migration

This commit is contained in:
mrg 2020-02-25 00:36:43 +00:00
commit e80677caf7
16 changed files with 427 additions and 319 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
.DS_Store .DS_Store
*~ *~
*.orig
*.rej
*.pyc *.pyc
*.aux *.aux
*.out *.out

View File

@ -116,6 +116,15 @@ class cell_properties():
self._dff_buff_array = _dff_buff_array(use_custom_ports = False, self._dff_buff_array = _dff_buff_array(use_custom_ports = False,
add_body_contacts = False) add_body_contacts = False)
self._write_driver = _cell({'din': 'din',
'bl' : 'bl',
'br' : 'br',
'en' : 'en'})
self._sense_amp = _cell({'bl' : 'bl',
'br' : 'br',
'dout' : 'dout',
'en' : 'en'})
@property @property
def bitcell(self): def bitcell(self):
return self._bitcell return self._bitcell
@ -132,3 +141,10 @@ class cell_properties():
def dff_buff_array(self): def dff_buff_array(self):
return self._dff_buff_array return self._dff_buff_array
@property
def write_driver(self):
return self._write_driver
@property
def sense_amp(self):
return self._sense_amp

View File

@ -329,6 +329,7 @@ class label(geometry):
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text) debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
new_layout.addText(text=self.text, new_layout.addText(text=self.text,
layerNumber=self.layerNumber, layerNumber=self.layerNumber,
purposeNumber=self.layerPurpose,
offsetInMicrons=self.offset, offsetInMicrons=self.offset,
magnification=self.zoom, magnification=self.zoom,
rotate=None) rotate=None)

View File

@ -378,6 +378,7 @@ class pin_layout:
# imported into Magic. # imported into Magic.
newLayout.addText(text=self.name, newLayout.addText(text=self.name,
layerNumber=layer_num, layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.center(), offsetInMicrons=self.center(),
magnification=GDS["zoom"], magnification=GDS["zoom"],
rotate=None) rotate=None)

View File

@ -180,30 +180,30 @@ class delay(simulation):
def create_read_bit_measures(self): def create_read_bit_measures(self):
""" Adds bit measurements for read0 and read1 cycles """ """ Adds bit measurements for read0 and read1 cycles """
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} self.read_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE) meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE)
for cycle in meas_cycles: for cycle in meas_cycles:
meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
for polarity,meas in single_bit_meas.items(): for polarity,meas in single_bit_meas.items():
meas.meta_str = cycle meas.meta_str = cycle
self.bit_meas[polarity].append(meas) self.read_bit_meas[polarity].append(meas)
# Dictionary values are lists, reduce to a single list of measurements # Dictionary values are lists, reduce to a single list of measurements
return [meas for meas_list in self.bit_meas.values() for meas in meas_list] return [meas for meas_list in self.read_bit_meas.values() for meas in meas_list]
def create_write_bit_measures(self): def create_write_bit_measures(self):
""" Adds bit measurements for write0 and write1 cycles """ """ Adds bit measurements for write0 and write1 cycles """
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} self.write_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE) meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE)
for cycle in meas_cycles: for cycle in meas_cycles:
meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
for polarity,meas in single_bit_meas.items(): for polarity,meas in single_bit_meas.items():
meas.meta_str = cycle meas.meta_str = cycle
self.bit_meas[polarity].append(meas) self.write_bit_meas[polarity].append(meas)
# Dictionary values are lists, reduce to a single list of measurements # Dictionary values are lists, reduce to a single list of measurements
return [meas for meas_list in self.bit_meas.values() for meas in meas_list] return [meas for meas_list in self.write_bit_meas.values() for meas in meas_list]
def get_bit_measures(self, meas_tag, probe_address, probe_data): def get_bit_measures(self, meas_tag, probe_address, probe_data):
""" """
@ -649,8 +649,9 @@ class delay(simulation):
if (time_out <= 0): if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2) debug.error("Timed out, could not find a feasible period.",2)
# Clear any write target ports and set read port # Write ports are assumed non-critical to timing, so the first available is used
self.targ_write_ports = [port] self.targ_write_ports = [self.write_ports[0]]
# Set target read port for simulation
self.targ_read_ports = [port] self.targ_read_ports = [port]
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port)) debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
@ -733,7 +734,8 @@ class delay(simulation):
# First, check that the memory has the right values at the right times # First, check that the memory has the right values at the right times
if not self.check_bit_measures(): if not self.check_bit_measures(self.read_bit_meas) or \
not self.check_bit_measures(self.write_bit_meas):
return(False,{}) return(False,{})
for port in self.targ_write_ports: for port in self.targ_write_ports:
@ -824,13 +826,13 @@ class delay(simulation):
return dout_success return dout_success
def check_bit_measures(self): def check_bit_measures(self, bit_measures):
""" """
Checks the measurements which represent the internal storage voltages Checks the measurements which represent the internal storage voltages
at the end of the read cycle. at the end of the read cycle.
""" """
success = False success = False
for polarity, meas_list in self.bit_meas.items(): for polarity, meas_list in bit_measures.items():
for meas in meas_list: for meas in meas_list:
val = meas.retrieve_measure() val = meas.retrieve_measure()
debug.info(2,"{}={}".format(meas.name, val)) debug.info(2,"{}={}".format(meas.name, val))
@ -965,7 +967,8 @@ class delay(simulation):
# Binary search algorithm to find the min period (max frequency) of input port # Binary search algorithm to find the min period (max frequency) of input port
time_out = 25 time_out = 25
self.targ_write_ports = [port] # Write ports are assumed non-critical to timing, so the first available is used
self.targ_write_ports = [self.write_ports[0]]
self.targ_read_ports = [port] self.targ_read_ports = [port]
while True: while True:
time_out -= 1 time_out -= 1
@ -1253,8 +1256,8 @@ class delay(simulation):
""" """
# Using this requires setting at least one port to target for simulation. # Using this requires setting at least one port to target for simulation.
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: if len(self.targ_write_ports) == 0 or len(self.targ_read_ports) == 0:
debug.error("No port selected for characterization.",1) debug.error("Write and read port must be specified for characterization.",1)
self.set_stimulus_variables() self.set_stimulus_variables()
# Get any available read/write port in case only a single write or read ports is being characterized. # Get any available read/write port in case only a single write or read ports is being characterized.

View File

@ -81,17 +81,25 @@ class lib:
self.lib_files = [] self.lib_files = []
# Nominal corner # Nominal corner
self.add_corner(nom_process, nom_supply, nom_temperature) corner_set = set()
nom_corner = (nom_process, nom_supply, nom_temperature)
corner_set.add(nom_corner)
if not OPTS.nominal_corner_only: if not OPTS.nominal_corner_only:
# Temperature corners # Temperature corners
self.add_corner(nom_process, nom_supply, min_temperature) corner_set.add((nom_process, nom_supply, min_temperature))
self.add_corner(nom_process, nom_supply, max_temperature) corner_set.add((nom_process, nom_supply, max_temperature))
# Supply corners # Supply corners
self.add_corner(nom_process, min_supply, nom_temperature) corner_set.add((nom_process, min_supply, nom_temperature))
self.add_corner(nom_process, max_supply, nom_temperature) corner_set.add((nom_process, max_supply, nom_temperature))
# Process corners # Process corners
self.add_corner(min_process, nom_supply, nom_temperature) corner_set.add((min_process, nom_supply, nom_temperature))
self.add_corner(max_process, nom_supply, nom_temperature) corner_set.add((max_process, nom_supply, nom_temperature))
# Enforce that nominal corner is the first to be characterized
self.add_corner(*nom_corner)
corner_set.remove(nom_corner)
for corner_tuple in corner_set:
self.add_corner(*corner_tuple)
def add_corner(self, proc, volt, temp): def add_corner(self, proc, volt, temp):
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name, self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,

View File

@ -1,12 +1,5 @@
import math import math
from globals import OPTS
# default purpose layer is used for addText() in vlsiLayout.py
if OPTS.tech_name == "s8":
purposeLayer=20
else:
purposeLayer=0
class GdsStructure: class GdsStructure:
"""Class represent a GDS Structure Object""" """Class represent a GDS Structure Object"""
def __init__(self): def __init__(self):
@ -147,7 +140,7 @@ class GdsText:
self.elementFlags="" self.elementFlags=""
self.plex="" self.plex=""
self.drawingLayer="" self.drawingLayer=""
self.purposeLayer=purposeLayer self.purposeLayer=0
self.transFlags=[0,0,0] self.transFlags=[0,0,0]
self.magFactor="" self.magFactor=""
self.rotateAngle="" self.rotateAngle=""

View File

@ -406,10 +406,11 @@ class VlsiLayout:
#add the sref to the root structure #add the sref to the root structure
self.structures[self.rootStructureName].paths.append(pathToAdd) self.structures[self.rootStructureName].paths.append(pathToAdd)
def addText(self, text, layerNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None): def addText(self, text, layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1])) offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
textToAdd = GdsText() textToAdd = GdsText()
textToAdd.drawingLayer = layerNumber textToAdd.drawingLayer = layerNumber
textToAdd.purposeLayer = purposeNumber
textToAdd.coordinates = [offsetInLayoutUnits] textToAdd.coordinates = [offsetInLayoutUnits]
textToAdd.transFlags = [0,0,0] textToAdd.transFlags = [0,0,0]
textToAdd.textString = self.padText(text) textToAdd.textString = self.padText(text)
@ -910,4 +911,3 @@ def boundaryArea(A):
""" """
area_A=(A[2]-A[0])*(A[3]-A[1]) area_A=(A[2]-A[0])*(A[3]-A[1])
return area_A return area_A

View File

@ -647,7 +647,7 @@ class control_logic(design.design):
if self.port_type=="rw": if self.port_type=="rw":
input_name = "we_bar" input_name = "we_bar"
else: else:
input_name = "cs_bar" input_name = "cs"
# GATE FOR S_EN # GATE FOR S_EN
self.s_en_gate_inst = self.add_inst(name="buf_s_en_and", self.s_en_gate_inst = self.add_inst(name="buf_s_en_and",
mod=self.sen_and3) mod=self.sen_and3)
@ -670,7 +670,7 @@ class control_logic(design.design):
if self.port_type=="rw": if self.port_type=="rw":
input_name = "we_bar" input_name = "we_bar"
else: else:
input_name = "cs_bar" input_name = "cs"
sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name]) sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name])
self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets) self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets)

View File

@ -8,6 +8,7 @@ from tech import drc, parameter
import debug import debug
import design import design
from sram_factory import factory from sram_factory import factory
from collections import namedtuple
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -46,7 +47,19 @@ class port_data(design.design):
# br lines are connect from the precharger # br lines are connect from the precharger
return self.precharge.get_br_names() return self.precharge.get_br_names()
def get_bl_name(self, port=0):
bl_name = "bl"
if len(self.all_ports) == 1:
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0):
br_name = "br"
if len(self.all_ports) == 1:
return br_name
else:
return br_name + "{}".format(port)
def create_netlist(self): def create_netlist(self):
self.precompute_constants() self.precompute_constants()
@ -94,8 +107,8 @@ class port_data(design.design):
self.add_pin("rbl_bl","INOUT") self.add_pin("rbl_bl","INOUT")
self.add_pin("rbl_br","INOUT") self.add_pin("rbl_br","INOUT")
for bit in range(self.num_cols): for bit in range(self.num_cols):
bl_name = self.precharge_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.precharge_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
self.add_pin("{0}_{1}".format(bl_name, bit),"INOUT") self.add_pin("{0}_{1}".format(bl_name, bit),"INOUT")
self.add_pin("{0}_{1}".format(br_name, bit),"INOUT") self.add_pin("{0}_{1}".format(br_name, bit),"INOUT")
if self.port in self.read_ports: if self.port in self.read_ports:
@ -253,8 +266,8 @@ class port_data(design.design):
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array) mod=self.precharge_array)
bl_name = self.precharge_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.precharge_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
# Use left BLs for RBL # Use left BLs for RBL
@ -285,8 +298,8 @@ class port_data(design.design):
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port), self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array) mod=self.column_mux_array)
bl_name = self.column_mux_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.column_mux_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, col)) temp.append("{0}_{1}".format(bl_name, col))
@ -315,8 +328,8 @@ class port_data(design.design):
self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port), self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
mod=self.sense_amp_array) mod=self.sense_amp_array)
bl_name = self.sense_amp_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.sense_amp_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout_{}".format(bit)) temp.append("dout_{}".format(bit))
@ -341,8 +354,8 @@ class port_data(design.design):
""" Creating Write Driver """ """ Creating Write Driver """
self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port), self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port),
mod=self.write_driver_array) mod=self.write_driver_array)
bl_name = self.write_driver_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.write_driver_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
@ -526,10 +539,13 @@ class port_data(design.design):
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst2 = self.precharge_array_inst inst2 = self.precharge_array_inst
if self.port==0:
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1) insn2_start_bit = 1 if self.port == 0 else 0
else:
self.connect_bitlines(inst1, inst2, self.num_cols) self.connect_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.num_cols,
inst2_start_bit=insn2_start_bit)
def route_sense_amp_to_column_mux_or_precharge_array(self, port): def route_sense_amp_to_column_mux_or_precharge_array(self, port):
@ -539,46 +555,49 @@ class port_data(design.design):
if self.col_addr_size>0: if self.col_addr_size>0:
# Sense amp is connected to the col mux # Sense amp is connected to the col mux
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bls_templ = "{inst}_out_{bit}"
inst1_br_name = "br_out_{}"
start_bit = 0 start_bit = 0
else: else:
# Sense amp is directly connected to the precharge array # Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}" inst1_bls_templ="{inst}_{bit}"
inst1_br_name = "br_{}"
if self.port==0: if self.port==0:
start_bit=1 start_bit=1
else: else:
start_bit=0 start_bit=0
self.channel_route_bitlines(inst1=inst1,
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, inst1_bls_template=inst1_bls_templ,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
def route_write_driver_to_column_mux_or_precharge_array(self, port): def route_write_driver_to_column_mux_or_precharge_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or precharge array """ """ Routing of BL and BR between sense_amp and column mux or precharge array """
inst2 = self.write_driver_array_inst inst2 = self.write_driver_array_inst
inst2_bl_name = inst2.mod.get_bl_name()
inst2_br_name = inst2.mod.get_br_name()
if self.col_addr_size>0: if self.col_addr_size>0:
# Write driver is connected to the col mux # Write driver is connected to the col mux
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bls_templ = "{inst}_out_{bit}"
inst1_br_name = "br_out_{}"
start_bit = 0 start_bit = 0
else: else:
# Sense amp is directly connected to the precharge array # Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}" inst1_bls_templ="{inst}_{bit}"
inst1_br_name = "br_{}"
if self.port==0: if self.port==0:
start_bit=1 start_bit=1
else: else:
start_bit=0 start_bit=0
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, self.channel_route_bitlines(inst1=inst1, inst2=inst2,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
def route_write_driver_to_sense_amp(self, port): def route_write_driver_to_sense_amp(self, port):
@ -589,7 +608,9 @@ class port_data(design.design):
# These should be pitch matched in the cell library, # These should be pitch matched in the cell library,
# but just in case, do a channel route. # but just in case, do a channel route.
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) self.channel_route_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.word_size)
def route_bitline_pins(self): def route_bitline_pins(self):
@ -637,62 +658,106 @@ class port_data(design.design):
def _group_bitline_instances(self, inst1, inst2, num_bits,
inst1_bls_template,
inst1_start_bit,
inst2_bls_template,
inst2_start_bit):
"""
Groups all the parameters into a named tuple and seperates them into
top and bottom instances.
"""
inst_group = namedtuple('InstanceGroup', ('inst', 'bls_template',
'bl_name', 'br_name', 'start_bit'))
inst1_group = inst_group(inst1, inst1_bls_template,
inst1.mod.get_bl_name(),
inst1.mod.get_br_name(),
inst1_start_bit)
inst2_group = inst_group(inst2, inst2_bls_template,
inst2.mod.get_bl_name(),
inst2.mod.get_br_name(),
inst2_start_bit)
# determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by():
bot_inst_group = inst1_group
top_inst_group = inst2_group
else:
bot_inst_group = inst2_group
top_inst_group = inst1_group
return (bot_inst_group, top_inst_group)
def _get_bitline_pins(self, inst_group, bit):
"""
Extracts bl/br pins from an InstanceGroup based on the bit modifier.
"""
full_bl_name = inst_group.bls_template.format(
**{'inst' : inst_group.bl_name,
'bit' : inst_group.start_bit + bit}
)
full_br_name = inst_group.bls_template.format(
**{'inst' : inst_group.br_name,
'bit' : inst_group.start_bit + bit}
)
return (inst_group.inst.get_pin(full_bl_name),
inst_group.inst.get_pin(full_br_name))
def channel_route_bitlines(self, inst1, inst2, num_bits, def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, inst1_bls_template="{inst}_{bit}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): inst1_start_bit=0,
inst2_bls_template="{inst}_{bit}",
inst2_start_bit=0):
""" """
Route the bl and br of two modules using the channel router. Route the bl and br of two modules using the channel router.
""" """
# determine top and bottom automatically. bot_inst_group, top_inst_group = self._group_bitline_instances(
# since they don't overlap, we can just check the bottom y coordinate. inst1, inst2, num_bits,
if inst1.by() < inst2.by(): inst1_bls_template, inst1_start_bit,
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) inst2_bls_template, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
else:
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
# Channel route each mux separately since we don't minimize the number # Channel route each mux separately since we don't minimize the number
# of tracks in teh channel router yet. If we did, we could route all the bits at once! # of tracks in teh channel router yet. If we did, we could route all the bits at once!
offset = bottom_inst.ul() + vector(0,self.m1_pitch) offset = bot_inst_group.inst.ul() + vector(0,self.m1_pitch)
for bit in range(num_bits): for bit in range(num_bits):
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))] bottom_names = self._get_bitline_pins(bot_inst_group, bit)
top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))] top_names = self._get_bitline_pins(top_inst_group, bit)
route_map = list(zip(bottom_names, top_names)) route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset, self.m1_stack) self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
def connect_bitlines(self, inst1, inst2, num_bits, def connect_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, inst1_bls_template="{inst}_{bit}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): inst1_start_bit=0,
inst2_bls_template="{inst}_{bit}",
inst2_start_bit=0):
""" """
Connect the bl and br of two modules. Connect the bl and br of two modules.
This assumes that they have sufficient space to create a jog This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed). in the middle between the two modules (if needed).
""" """
# determine top and bottom automatically. bot_inst_group, top_inst_group = self._group_bitline_instances(
# since they don't overlap, we can just check the bottom y coordinate. inst1, inst2, num_bits,
if inst1.by() < inst2.by(): inst1_bls_template, inst1_start_bit,
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) inst2_bls_template, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) bottom_inst = bot_inst_group.inst
else: top_inst = top_inst_group.inst
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
for col in range(num_bits): for col in range(num_bits):
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc() bot_bl_pin, bot_br_pin = self._get_bitline_pins(bot_inst_group, col)
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc() top_bl_pin, top_br_pin = self._get_bitline_pins(top_inst_group, col)
top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc() bot_bl, bot_br = bot_bl_pin.uc(), bot_br_pin.uc()
top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc() top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc()
yoffset = 0.5*(top_bl.y+bottom_bl.y) yoffset = 0.5*(top_bl.y+bot_bl.y)
self.add_path("m2",[bottom_bl, vector(bottom_bl.x,yoffset), self.add_path("m2",[bot_bl, vector(bot_bl.x,yoffset),
vector(top_bl.x,yoffset), top_bl]) vector(top_bl.x,yoffset), top_bl])
self.add_path("m2",[bottom_br, vector(bottom_br.x,yoffset), self.add_path("m2",[bot_br, vector(bot_br.x,yoffset),
vector(top_br.x,yoffset), top_br]) vector(top_br.x,yoffset), top_br])
def graph_exclude_precharge(self): def graph_exclude_precharge(self):

View File

@ -32,20 +32,13 @@ class precharge_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.pc_cell.get_bl_names() bl_name = self.pc_cell.get_bl_names()
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self):
br_name = self.pc_cell.get_br_names() br_name = self.pc_cell.get_br_names()
if len(self.all_ports) == 1: return br_name
return br_name
else:
return br_name + "{}".format(port)
def add_pins(self): def add_pins(self):
"""Adds pins for spice file""" """Adds pins for spice file"""

View File

@ -9,6 +9,7 @@ import design
import debug import debug
import utils import utils
from tech import GDS,layer, parameter,drc from tech import GDS,layer, parameter,drc
from tech import cell_properties as props
from globals import OPTS from globals import OPTS
import logical_effort import logical_effort
@ -19,8 +20,12 @@ class sense_amp(design.design):
the technology library. the technology library.
Sense amplifier to read a pair of bit-lines. Sense amplifier to read a pair of bit-lines.
""" """
pin_names = [props.sense_amp.pin.bl,
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"] props.sense_amp.pin.br,
props.sense_amp.pin.dout,
props.sense_amp.pin.en,
props.sense_amp.pin.vdd,
props.sense_amp.pin.gnd]
type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
@ -30,10 +35,18 @@ class sense_amp(design.design):
pin_map = [] pin_map = []
def get_bl_names(self): def get_bl_names(self):
return "bl" return props.sense_amp.pin.bl
def get_br_names(self): def get_br_names(self):
return "br" return props.sense_amp.pin.br
@property
def dout_name(self):
return props.sense_amp.pin.dout
@property
def en_name(self):
return props.sense_amp.pin.en
def __init__(self, name): def __init__(self, name):
design.design.__init__(self, name) design.design.__init__(self, name)
@ -79,11 +92,10 @@ class sense_amp(design.design):
def get_enable_name(self): def get_enable_name(self):
"""Returns name used for enable net""" """Returns name used for enable net"""
#FIXME: A better programmatic solution to designate pins #FIXME: A better programmatic solution to designate pins
enable_name = "en" enable_name = self.en_name
debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name)) debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name))
return enable_name return enable_name
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -33,20 +33,21 @@ class sense_amp_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self):
bl_name = "bl"
return bl_name
def get_bl_name(self, port=0): def get_br_name(self):
bl_name = self.amp.get_bl_names() br_name = "br"
if len(self.all_ports) == 1: return br_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): @property
br_name = self.amp.get_br_names() def data_name(self):
if len(self.all_ports) == 1: return "data"
return br_name
else: @property
return br_name + "{}".format(port) def en_name(self):
return "en"
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
@ -69,10 +70,10 @@ class sense_amp_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(0,self.word_size): for i in range(0,self.word_size):
self.add_pin("data_{0}".format(i), "OUTPUT") self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT")
self.add_pin("bl_{0}".format(i), "INPUT") self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT")
self.add_pin("br_{0}".format(i), "INPUT") self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT")
self.add_pin("en", "INPUT") self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -92,10 +93,10 @@ class sense_amp_array(design.design):
name = "sa_d{0}".format(i) name = "sa_d{0}".format(i)
self.local_insts.append(self.add_inst(name=name, self.local_insts.append(self.add_inst(name=name,
mod=self.amp)) mod=self.amp))
self.connect_inst(["bl_{0}".format(i), self.connect_inst([self.get_bl_name() + "_{0}".format(i),
"br_{0}".format(i), self.get_br_name() + "_{0}".format(i),
"data_{0}".format(i), self.data_name + "_{0}".format(i),
"en", "vdd", "gnd"]) self.en_name, "vdd", "gnd"])
def place_sense_amp_array(self): def place_sense_amp_array(self):
from tech import cell_properties from tech import cell_properties
@ -135,22 +136,22 @@ class sense_amp_array(design.design):
start_layer="m2", start_layer="m2",
vertical=True) vertical=True)
bl_pin = inst.get_pin("bl") bl_pin = inst.get_pin(inst.mod.get_bl_names())
br_pin = inst.get_pin("br") br_pin = inst.get_pin(inst.mod.get_br_names())
dout_pin = inst.get_pin("dout") dout_pin = inst.get_pin(inst.mod.dout_name)
self.add_layout_pin(text="bl_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
self.add_layout_pin(text="br_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
height=br_pin.height()) height=br_pin.height())
self.add_layout_pin(text="data_{0}".format(i), self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer="m2",
offset=dout_pin.ll(), offset=dout_pin.ll(),
width=dout_pin.width(), width=dout_pin.width(),
@ -159,8 +160,8 @@ class sense_amp_array(design.design):
def route_rails(self): def route_rails(self):
# add sclk rail across entire array # add sclk rail across entire array
sclk_offset = self.amp.get_pin("en").ll().scale(0,1) sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0,1)
self.add_layout_pin(text="en", self.add_layout_pin(text=self.en_name,
layer="m1", layer="m1",
offset=sclk_offset, offset=sclk_offset,
width=self.width, width=self.width,

View File

@ -37,20 +37,13 @@ class single_level_column_mux_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.mux.get_bl_names() bl_name = self.mux.get_bl_names()
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self, port=0):
br_name = self.mux.get_br_names() br_name = self.mux.get_br_names()
if len(self.all_ports) == 1: return br_name
return br_name
else:
return br_name + "{}".format(port)
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()

View File

@ -10,6 +10,7 @@ import design
import utils import utils
from globals import OPTS from globals import OPTS
from tech import GDS,layer from tech import GDS,layer
from tech import cell_properties as props
class write_driver(design.design): class write_driver(design.design):
""" """
@ -19,7 +20,13 @@ class write_driver(design.design):
the technology library. the technology library.
""" """
pin_names = ["din", "bl", "br", "en", "vdd", "gnd"] pin_names = [props.write_driver.pin.din,
props.write_driver.pin.bl,
props.write_driver.pin.br,
props.write_driver.pin.en,
props.write_driver.pin.vdd,
props.write_driver.pin.gnd]
type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
@ -38,10 +45,18 @@ class write_driver(design.design):
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def get_bl_names(self): def get_bl_names(self):
return "bl" return props.write_driver.pin.bl
def get_br_names(self): def get_br_names(self):
return "br" return props.write_driver.pin.br
@property
def din_name(self):
return props.write_driver.pin.din
@property
def en_name(self):
return props.write_driver.pin.en
def get_w_en_cin(self): def get_w_en_cin(self):
"""Get the relative capacitance of a single input""" """Get the relative capacitance of a single input"""

View File

@ -37,19 +37,21 @@ class write_driver_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.driver.get_bl_names() bl_name = "bl"
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self):
br_name = self.driver.get_br_names() br_name = "br"
if len(self.all_ports) == 1: return br_name
return br_name
else: @property
return br_name + "{}".format(port) def data_name(self):
return "data"
@property
def en_name(self):
return "en"
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
@ -71,15 +73,15 @@ class write_driver_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("data_{0}".format(i), "INPUT") self.add_pin(self.data_name + "_{0}".format(i), "INPUT")
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("bl_{0}".format(i), "OUTPUT") self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT")
self.add_pin("br_{0}".format(i), "OUTPUT") self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT")
if self.write_size: if self.write_size:
for i in range(self.num_wmasks): for i in range(self.num_wmasks):
self.add_pin("en_{0}".format(i), "INPUT") self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
else: else:
self.add_pin("en", "INPUT") self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -102,20 +104,20 @@ class write_driver_array(design.design):
mod=self.driver) mod=self.driver)
if self.write_size: if self.write_size:
self.connect_inst(["data_{0}".format(index), self.connect_inst([self.data_name + "_{0}".format(index),
"bl_{0}".format(index), self.get_bl_name() + "_{0}".format(index),
"br_{0}".format(index), self.get_br_name() + "_{0}".format(index),
"en_{0}".format(windex), "vdd", "gnd"]) self.en_name + "_{0}".format(windex), "vdd", "gnd"])
w+=1 w+=1
# when w equals write size, the next en pin can be connected since we are now at the next wmask bit # when w equals write size, the next en pin can be connected since we are now at the next wmask bit
if w == self.write_size: if w == self.write_size:
w = 0 w = 0
windex+=1 windex+=1
else: else:
self.connect_inst(["data_{0}".format(index), self.connect_inst([self.data_name + "_{0}".format(index),
"bl_{0}".format(index), self.get_bl_name() + "_{0}".format(index),
"br_{0}".format(index), self.get_br_name() + "_{0}".format(index),
"en", "vdd", "gnd"]) self.en_name, "vdd", "gnd"])
def place_write_array(self): def place_write_array(self):
@ -140,21 +142,22 @@ class write_driver_array(design.design):
def add_layout_pins(self): def add_layout_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
din_pin = self.driver_insts[i].get_pin("din") inst = self.driver_insts[i]
self.add_layout_pin(text="data_{0}".format(i), din_pin = inst.get_pin(inst.mod.din_name)
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer="m2",
offset=din_pin.ll(), offset=din_pin.ll(),
width=din_pin.width(), width=din_pin.width(),
height=din_pin.height()) height=din_pin.height())
bl_pin = self.driver_insts[i].get_pin("bl") bl_pin = inst.get_pin(inst.mod.get_bl_names())
self.add_layout_pin(text="bl_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
br_pin = self.driver_insts[i].get_pin("br") br_pin = inst.get_pin(inst.mod.get_br_names())
self.add_layout_pin(text="br_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
@ -169,7 +172,8 @@ class write_driver_array(design.design):
start_layer = "m2") start_layer = "m2")
if self.write_size: if self.write_size:
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
en_pin = self.driver_insts[bit*self.write_size].get_pin("en") inst = self.driver_insts[bit*self.write_size]
en_pin = inst.get_pin(inst.mod.en_name)
# Determine width of wmask modified en_pin with/without col mux # Determine width of wmask modified en_pin with/without col mux
wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing) wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing)
if (self.words_per_row == 1): if (self.words_per_row == 1):
@ -177,15 +181,16 @@ class write_driver_array(design.design):
else: else:
en_gap = self.driver_spacing en_gap = self.driver_spacing
self.add_layout_pin(text="en_{0}".format(bit), self.add_layout_pin(text=self.en_name + "_{0}".format(bit),
layer=en_pin.layer, layer=en_pin.layer,
offset=en_pin.ll(), offset=en_pin.ll(),
width=wmask_en_len-en_gap, width=wmask_en_len-en_gap,
height=en_pin.height()) height=en_pin.height())
else: else:
self.add_layout_pin(text="en", inst = self.driver_insts[0]
self.add_layout_pin(text=self.en_name,
layer="m1", layer="m1",
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1),
width=self.width) width=self.width)