2016-11-08 18:57:35 +01:00
|
|
|
import debug
|
|
|
|
|
import design
|
2016-11-09 21:20:52 +01:00
|
|
|
from tech import drc
|
2016-11-08 18:57:35 +01:00
|
|
|
from pinv import pinv
|
2017-12-12 23:53:19 +01:00
|
|
|
import contact
|
2016-11-08 18:57:35 +01:00
|
|
|
from bitcell_array import bitcell_array
|
|
|
|
|
from ptx import ptx
|
|
|
|
|
from vector import vector
|
|
|
|
|
from globals import OPTS
|
|
|
|
|
|
|
|
|
|
class replica_bitline(design.design):
|
|
|
|
|
"""
|
2018-02-07 23:54:59 +01:00
|
|
|
Generate a module that simulates the delay of control logic
|
2018-02-16 20:51:01 +01:00
|
|
|
and bit line charging. Stages is the depth of the delay
|
2018-02-07 23:54:59 +01:00
|
|
|
line and rows is the height of the replica bit loads.
|
2016-11-08 18:57:35 +01:00
|
|
|
"""
|
|
|
|
|
|
2018-02-16 20:51:01 +01:00
|
|
|
def __init__(self, delay_stages, delay_fanout, bitcell_loads, name="replica_bitline"):
|
2017-08-24 00:02:15 +02:00
|
|
|
design.design.__init__(self, name)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-01-20 01:38:19 +01:00
|
|
|
g = reload(__import__(OPTS.delay_chain))
|
|
|
|
|
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-01-20 01:38:19 +01:00
|
|
|
g = reload(__import__(OPTS.replica_bitcell))
|
|
|
|
|
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-01-20 01:38:19 +01:00
|
|
|
c = reload(__import__(OPTS.bitcell))
|
|
|
|
|
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
for pin in ["en", "out", "vdd", "gnd"]:
|
|
|
|
|
self.add_pin(pin)
|
2018-02-07 23:54:59 +01:00
|
|
|
self.bitcell_loads = bitcell_loads
|
2018-02-16 20:51:01 +01:00
|
|
|
self.delay_stages = delay_stages
|
|
|
|
|
self.delay_fanout = delay_fanout
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
self.create_modules()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.calculate_module_offsets()
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_modules()
|
|
|
|
|
self.route()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_layout_pins()
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_lvs_correspondence_points()
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
self.DRC_LVS()
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
def calculate_module_offsets(self):
|
|
|
|
|
""" Calculate all the module offsets """
|
|
|
|
|
|
|
|
|
|
# These aren't for instantiating, but we use them to get the dimensions
|
2017-12-12 23:53:19 +01:00
|
|
|
self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# M1/M2 routing pitch is based on contacted pitch
|
2017-12-12 23:53:19 +01:00
|
|
|
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space,self.m2_space)
|
|
|
|
|
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# This corrects the offset pitch difference between M2 and M1
|
2017-12-12 23:53:19 +01:00
|
|
|
self.offset_fix = vector(0.5*(self.m2_width-self.m1_width),0)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# delay chain will be rotated 90, so move it over a width
|
|
|
|
|
# we move it up a inv height just for some routing room
|
|
|
|
|
self.rbl_inv_offset = vector(self.delay_chain.height, self.inv.width)
|
|
|
|
|
# access TX goes right on top of inverter, leave space for an inverter which is
|
|
|
|
|
# about the same as a TX. We'll need to add rails though.
|
2017-12-12 23:53:19 +01:00
|
|
|
self.access_tx_offset = vector(1.25*self.inv.height,self.rbl_inv_offset.y) + vector(0,2.5*self.inv.width)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.delay_chain_offset = self.rbl_inv_offset + vector(0,4*self.inv.width)
|
|
|
|
|
|
|
|
|
|
# Replica bitline and such are not rotated, but they must be placed far enough
|
|
|
|
|
# away from the delay chain/inverter with space for three M2 tracks
|
|
|
|
|
self.bitcell_offset = self.rbl_inv_offset + vector(2*self.m2_pitch, 0) + vector(0, self.bitcell.height + self.inv.width)
|
|
|
|
|
|
|
|
|
|
self.rbl_offset = self.bitcell_offset
|
|
|
|
|
|
|
|
|
|
|
2017-09-30 01:22:13 +02:00
|
|
|
self.height = self.rbl_offset.y + self.rbl.height + self.m2_pitch
|
2017-08-24 00:02:15 +02:00
|
|
|
self.width = self.rbl_offset.x + self.bitcell.width
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_modules(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Create modules for later instantiation """
|
|
|
|
|
self.bitcell = self.replica_bitcell = self.mod_replica_bitcell()
|
|
|
|
|
self.add_mod(self.bitcell)
|
|
|
|
|
|
|
|
|
|
# This is the replica bitline load column that is the height of our array
|
2018-02-07 23:54:59 +01:00
|
|
|
self.rbl = bitcell_array(name="bitline_load", cols=1, rows=self.bitcell_loads)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_mod(self.rbl)
|
2018-02-07 23:54:59 +01:00
|
|
|
|
|
|
|
|
# FIXME: The FO and depth of this should be tuned
|
2018-02-16 20:51:01 +01:00
|
|
|
self.delay_chain = self.mod_delay_chain([self.delay_fanout]*self.delay_stages)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_mod(self.delay_chain)
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.inv = pinv()
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_mod(self.inv)
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.access_tx = ptx(tx_type="pmos")
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_mod(self.access_tx)
|
|
|
|
|
|
|
|
|
|
def add_modules(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Add all of the module instances in the logical netlist """
|
|
|
|
|
# This is the threshold detect inverter on the output of the RBL
|
|
|
|
|
self.rbl_inv_inst=self.add_inst(name="rbl_inv",
|
|
|
|
|
mod=self.inv,
|
|
|
|
|
offset=self.rbl_inv_offset+vector(0,self.inv.width),
|
|
|
|
|
rotate=270,
|
|
|
|
|
mirror="MX")
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["bl[0]", "out", "vdd", "gnd"])
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.tx_inst=self.add_inst(name="rbl_access_tx",
|
|
|
|
|
mod=self.access_tx,
|
|
|
|
|
offset=self.access_tx_offset,
|
|
|
|
|
rotate=90)
|
2016-11-08 18:57:35 +01:00
|
|
|
# D, G, S, B
|
|
|
|
|
self.connect_inst(["vdd", "delayed_en", "bl[0]", "vdd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
# add the well and poly contact
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.dc_inst=self.add_inst(name="delay_chain",
|
|
|
|
|
mod=self.delay_chain,
|
|
|
|
|
offset=self.delay_chain_offset,
|
|
|
|
|
rotate=90)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.rbc_inst=self.add_inst(name="bitcell",
|
|
|
|
|
mod=self.replica_bitcell,
|
|
|
|
|
offset=self.bitcell_offset,
|
|
|
|
|
mirror="MX")
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["bl[0]", "br[0]", "delayed_en", "vdd", "gnd"])
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
self.rbl_inst=self.add_inst(name="load",
|
|
|
|
|
mod=self.rbl,
|
|
|
|
|
offset=self.rbl_offset)
|
2018-02-07 23:54:59 +01:00
|
|
|
self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
def route(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Connect all the signals together """
|
2016-11-08 18:57:35 +01:00
|
|
|
self.route_gnd()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.route_vdd()
|
|
|
|
|
self.route_access_tx()
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
def route_access_tx(self):
|
|
|
|
|
# GATE ROUTE
|
|
|
|
|
# 1. Add the poly contact and nwell enclosure
|
|
|
|
|
# Determines the y-coordinate of where to place the gate input poly pin
|
|
|
|
|
# (middle in between the pmos and nmos)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
poly_pin = self.tx_inst.get_pin("G")
|
|
|
|
|
poly_offset = poly_pin.rc()
|
2017-08-24 00:02:15 +02:00
|
|
|
# This centers the contact on the poly
|
2017-12-12 23:53:19 +01:00
|
|
|
contact_offset = poly_offset.scale(0,1) + self.dc_inst.get_pin("out").bc().scale(1,0)
|
|
|
|
|
self.add_contact_center(layers=("poly", "contact", "metal1"),
|
|
|
|
|
offset=contact_offset)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_rect(layer="poly",
|
2017-12-12 23:53:19 +01:00
|
|
|
offset=poly_pin.lr(),
|
2017-08-24 00:02:15 +02:00
|
|
|
width=contact_offset.x-poly_offset.x,
|
2017-12-12 23:53:19 +01:00
|
|
|
height=self.poly_width)
|
2017-08-24 00:02:15 +02:00
|
|
|
nwell_offset = self.rbl_inv_offset + vector(-self.inv.height,self.inv.width)
|
|
|
|
|
self.add_rect(layer="nwell",
|
|
|
|
|
offset=nwell_offset,
|
|
|
|
|
width=0.5*self.inv.height,
|
|
|
|
|
height=self.delay_chain_offset.y-nwell_offset.y)
|
|
|
|
|
|
|
|
|
|
# 2. Route delay chain output to access tx gate
|
|
|
|
|
delay_en_offset = self.dc_inst.get_pin("out").bc()
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_path("metal1", [delay_en_offset,contact_offset])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# 3. Route the mid-point of previous route to the bitcell WL
|
|
|
|
|
# route bend of previous net to bitcell WL
|
|
|
|
|
wl_offset = self.rbc_inst.get_pin("WL").lc()
|
2017-12-12 23:53:19 +01:00
|
|
|
wl_mid = vector(contact_offset.x,wl_offset.y)
|
|
|
|
|
self.add_path("metal1", [contact_offset, wl_mid, wl_offset])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# DRAIN ROUTE
|
|
|
|
|
# Route the drain to the vdd rail
|
|
|
|
|
drain_offset = self.tx_inst.get_pin("D").lc()
|
2017-08-24 00:02:15 +02:00
|
|
|
inv_vdd_offset = self.rbl_inv_inst.get_pin("vdd").uc()
|
2017-12-12 23:53:19 +01:00
|
|
|
vdd_offset = inv_vdd_offset.scale(1,0) + drain_offset.scale(0,1)
|
|
|
|
|
self.add_path("metal1", [drain_offset, vdd_offset])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# SOURCE ROUTE
|
|
|
|
|
# Route the source to the RBL inverter input
|
|
|
|
|
source_offset = self.tx_inst.get_pin("S").bc()
|
|
|
|
|
mid1 = source_offset.scale(1,0) + vector(0,self.rbl_inv_offset.y+self.inv.width+self.m2_pitch)
|
2017-08-24 00:02:15 +02:00
|
|
|
inv_A_offset = self.rbl_inv_inst.get_pin("A").uc()
|
|
|
|
|
mid2 = vector(inv_A_offset.x, mid1.y)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_path("metal1",[source_offset, mid1, mid2, inv_A_offset])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# Route the connection of the source route (mid2) to the RBL bitline (left)
|
|
|
|
|
source_offset = mid2
|
2017-08-24 00:02:15 +02:00
|
|
|
# Route the M2 to the right of the vdd rail between rbl_inv and bitcell
|
|
|
|
|
gnd_pin = self.rbl_inv_inst.get_pin("gnd").ll()
|
2017-12-12 23:53:19 +01:00
|
|
|
mid1 = vector(gnd_pin.x+self.m2_pitch,source_offset.y)
|
2017-08-24 00:02:15 +02:00
|
|
|
# Via will go halfway down from the bitcell
|
|
|
|
|
bl_offset = self.rbc_inst.get_pin("BL").bc()
|
|
|
|
|
via_offset = bl_offset - vector(0,0.5*self.inv.width)
|
|
|
|
|
mid2 = vector(mid1.x,via_offset.y)
|
|
|
|
|
# self.add_contact(layers=("metal1", "via1", "metal2"),
|
2017-12-12 23:53:19 +01:00
|
|
|
# offset=via_offset - vector(0.5*self.m2_width,0.5*self.m1_width))
|
|
|
|
|
self.add_wire(("metal1","via1","metal2"),[source_offset,mid1,mid2,via_offset,bl_offset])
|
2017-08-24 00:02:15 +02:00
|
|
|
#self.add_path("metal2",[via_offset,bl_offset])
|
|
|
|
|
|
|
|
|
|
def route_vdd(self):
|
|
|
|
|
# Add a rail in M2 that is to the right of the inverter gnd pin
|
|
|
|
|
# The replica column may not fit in a single standard cell pitch, so add the vdd rail to the
|
|
|
|
|
# right of it.
|
|
|
|
|
vdd_start = vector(self.bitcell_offset.x + self.bitcell.width + self.m1_pitch,0)
|
|
|
|
|
# It is the height of the entire RBL and bitcell
|
|
|
|
|
self.add_layout_pin(text="vdd",
|
|
|
|
|
layer="metal1",
|
|
|
|
|
offset=vdd_start,
|
2017-12-12 23:53:19 +01:00
|
|
|
width=self.m1_width,
|
|
|
|
|
height=self.rbl.height+self.bitcell.height+2*self.inv.width+0.5*self.m1_width)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Connect the vdd pins of the bitcell load directly to vdd
|
2017-09-14 00:46:41 +02:00
|
|
|
vdd_pins = self.rbl_inst.get_pins("vdd")
|
2017-08-24 00:02:15 +02:00
|
|
|
for pin in vdd_pins:
|
|
|
|
|
offset = vector(vdd_start.x,pin.by())
|
|
|
|
|
self.add_rect(layer="metal1",
|
|
|
|
|
offset=offset,
|
|
|
|
|
width=self.rbl_offset.x-vdd_start.x,
|
2017-12-12 23:53:19 +01:00
|
|
|
height=self.m1_width)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Also connect the replica bitcell vdd pin to vdd
|
|
|
|
|
pin = self.rbc_inst.get_pin("vdd")
|
|
|
|
|
offset = vector(vdd_start.x,pin.by())
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_rect(layer="metal1",
|
|
|
|
|
offset=offset,
|
2017-08-24 00:02:15 +02:00
|
|
|
width=self.bitcell_offset.x-vdd_start.x,
|
2017-12-12 23:53:19 +01:00
|
|
|
height=self.m1_width)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Add a second vdd pin. No need for full length. It is must connect at the next level.
|
|
|
|
|
inv_vdd_offset = self.rbl_inv_inst.get_pin("vdd").ll()
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_layout_pin(text="vdd",
|
2017-08-24 00:02:15 +02:00
|
|
|
layer="metal1",
|
|
|
|
|
offset=inv_vdd_offset.scale(1,0),
|
2017-12-12 23:53:19 +01:00
|
|
|
width=self.m1_width,
|
2017-08-24 00:02:15 +02:00
|
|
|
height=self.delay_chain_offset.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def route_gnd(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Route all signals connected to gnd """
|
|
|
|
|
|
2018-02-07 23:15:13 +01:00
|
|
|
gnd_start = self.rbl_inv_inst.get_pin("gnd").bc()
|
2018-02-05 19:22:38 +01:00
|
|
|
gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch)
|
2018-02-07 23:15:13 +01:00
|
|
|
|
|
|
|
|
# Add a rail in M1 from bottom of delay chain to two above the RBL
|
|
|
|
|
# This prevents DRC errors with vias for the WL
|
|
|
|
|
dc_top = self.dc_inst.ur()
|
|
|
|
|
self.add_segment_center(layer="metal1",
|
|
|
|
|
start=vector(gnd_start.x, dc_top.y),
|
|
|
|
|
end=gnd_end)
|
|
|
|
|
|
|
|
|
|
# Add a rail in M2 from RBL inverter to two above the RBL
|
2018-02-05 19:22:38 +01:00
|
|
|
self.add_segment_center(layer="metal2",
|
|
|
|
|
start=gnd_start,
|
|
|
|
|
end=gnd_end)
|
2018-02-07 23:15:13 +01:00
|
|
|
|
|
|
|
|
# Add pin from bottom to RBL inverter
|
2018-02-05 19:22:38 +01:00
|
|
|
self.add_layout_pin_center_segment(text="gnd",
|
|
|
|
|
layer="metal1",
|
|
|
|
|
start=gnd_start.scale(1,0),
|
|
|
|
|
end=gnd_start)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Connect the WL pins directly to gnd
|
2018-02-05 19:22:38 +01:00
|
|
|
gnd_pin = self.get_pin("gnd").rc()
|
2018-02-07 23:54:59 +01:00
|
|
|
for row in range(self.bitcell_loads):
|
2017-08-24 00:02:15 +02:00
|
|
|
wl = "wl[{}]".format(row)
|
|
|
|
|
pin = self.rbl_inst.get_pin(wl)
|
2018-02-05 19:22:38 +01:00
|
|
|
start = vector(gnd_pin.x,pin.cy())
|
|
|
|
|
self.add_segment_center(layer="metal1",
|
|
|
|
|
start=start,
|
|
|
|
|
end=pin.lc())
|
|
|
|
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
|
|
|
|
offset=start)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Add via for the delay chain
|
2018-02-05 19:22:38 +01:00
|
|
|
offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height)
|
|
|
|
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
|
|
|
|
offset=offset)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
# Add via for the inverter
|
2018-02-05 19:22:38 +01:00
|
|
|
offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height)
|
|
|
|
|
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
|
|
|
|
offset=offset)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-02-02 21:27:24 +01:00
|
|
|
# Connect the bitcell gnd pins to the rail
|
2017-09-14 00:46:41 +02:00
|
|
|
gnd_pins = self.get_pins("gnd")
|
2018-02-02 21:27:24 +01:00
|
|
|
gnd_start = gnd_pins[0].ul()
|
2017-09-14 00:46:41 +02:00
|
|
|
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
|
2018-02-02 21:27:24 +01:00
|
|
|
# Add L shapes to each vertical gnd rail
|
2017-08-24 00:02:15 +02:00
|
|
|
for pin in rbl_gnd_pins:
|
2018-02-02 21:27:24 +01:00
|
|
|
if pin.layer != "metal2":
|
|
|
|
|
continue
|
|
|
|
|
gnd_end = pin.uc()
|
|
|
|
|
gnd_mid = vector(gnd_end.x, gnd_start.y)
|
|
|
|
|
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid, gnd_end])
|
|
|
|
|
gnd_start = gnd_mid
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# Add a second gnd pin to the second delay chain rail. No need for full length.
|
2017-09-14 00:46:41 +02:00
|
|
|
dc_gnd_offset = self.dc_inst.get_pins("gnd")[1].ll()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_layout_pin(text="gnd",
|
|
|
|
|
layer="metal1",
|
|
|
|
|
offset=dc_gnd_offset.scale(1,0),
|
2017-12-12 23:53:19 +01:00
|
|
|
width=self.m1_width,
|
2017-08-24 00:02:15 +02:00
|
|
|
height=self.delay_chain_offset.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_layout_pins(self):
|
|
|
|
|
""" Route the input and output signal """
|
2017-12-12 23:53:19 +01:00
|
|
|
en_offset = self.dc_inst.get_pin("in").ll()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_layout_pin(text="en",
|
|
|
|
|
layer="metal1",
|
|
|
|
|
offset=en_offset.scale(1,0),
|
2017-12-12 23:53:19 +01:00
|
|
|
width=self.m1_width,
|
2017-08-24 00:02:15 +02:00
|
|
|
height=en_offset.y)
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
out_offset = self.rbl_inv_inst.get_pin("Z").ll()
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_layout_pin(text="out",
|
|
|
|
|
layer="metal1",
|
|
|
|
|
offset=out_offset.scale(1,0),
|
2017-12-12 23:53:19 +01:00
|
|
|
width=self.m1_width,
|
2017-08-24 00:02:15 +02:00
|
|
|
height=out_offset.y)
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
def add_lvs_correspondence_points(self):
|
|
|
|
|
""" This adds some points for easier debugging if LVS goes wrong.
|
|
|
|
|
These should probably be turned off by default though, since extraction
|
|
|
|
|
will show these as ports in the extracted netlist.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pin = self.rbl_inv_inst.get_pin("A")
|
|
|
|
|
self.add_label_pin(text="bl[0]",
|
|
|
|
|
layer=pin.layer,
|
|
|
|
|
offset=pin.ll(),
|
|
|
|
|
height=pin.height(),
|
|
|
|
|
width=pin.width())
|
|
|
|
|
|
|
|
|
|
pin = self.dc_inst.get_pin("out")
|
|
|
|
|
self.add_label_pin(text="delayed_en",
|
|
|
|
|
layer=pin.layer,
|
|
|
|
|
offset=pin.ll(),
|
|
|
|
|
height=pin.height(),
|
|
|
|
|
width=pin.width())
|
|
|
|
|
|