2016-11-08 18:57:35 +01:00
|
|
|
from math import log
|
|
|
|
|
import design
|
2016-11-09 21:20:52 +01:00
|
|
|
from tech import drc, parameter
|
2016-11-08 18:57:35 +01:00
|
|
|
import debug
|
2017-12-12 23:53:19 +01:00
|
|
|
import contact
|
2016-11-08 18:57:35 +01:00
|
|
|
from pinv import pinv
|
2017-12-12 23:53:19 +01:00
|
|
|
from pnand2 import pnand2
|
|
|
|
|
from pnand3 import pnand3
|
2018-03-12 21:14:53 +01:00
|
|
|
from pinvbuf import pinvbuf
|
2018-03-21 21:20:48 +01:00
|
|
|
from dff_inv import dff_inv
|
|
|
|
|
from dff_inv_array import dff_inv_array
|
2016-11-08 18:57:35 +01:00
|
|
|
import math
|
|
|
|
|
from vector import vector
|
|
|
|
|
from globals import OPTS
|
|
|
|
|
|
|
|
|
|
class control_logic(design.design):
|
|
|
|
|
"""
|
|
|
|
|
Dynamically generated Control logic for the total SRAM circuit.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, num_rows):
|
|
|
|
|
""" Constructor """
|
|
|
|
|
design.design.__init__(self, "control_logic")
|
2017-08-24 00:02:15 +02:00
|
|
|
debug.info(1, "Creating {}".format(self.name))
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
self.num_rows = num_rows
|
|
|
|
|
self.create_layout()
|
|
|
|
|
self.DRC_LVS()
|
|
|
|
|
|
|
|
|
|
def create_layout(self):
|
|
|
|
|
""" Create layout and route between modules """
|
|
|
|
|
self.setup_layout_offsets()
|
2018-03-21 21:20:48 +01:00
|
|
|
self.add_pins()
|
2018-03-15 01:30:41 +01:00
|
|
|
self.create_modules()
|
|
|
|
|
self.add_rails()
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_modules()
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_routing()
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
def add_pins(self):
|
|
|
|
|
""" Add the pins to the control logic module. """
|
2018-03-15 01:30:41 +01:00
|
|
|
for pin in self.input_list + ["clk"]:
|
|
|
|
|
self.add_pin(pin,"INPUT")
|
|
|
|
|
for pin in self.output_list:
|
|
|
|
|
self.add_pin(pin,"OUTPUT")
|
|
|
|
|
self.add_pin("vdd","POWER")
|
|
|
|
|
self.add_pin("gnd","GROUND")
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
def create_modules(self):
|
|
|
|
|
""" add all the required modules """
|
|
|
|
|
|
|
|
|
|
dff = dff_inv()
|
|
|
|
|
dff_height = dff.height
|
|
|
|
|
|
|
|
|
|
self.ctrl_dff_array = dff_inv_array(rows=3,columns=1)
|
|
|
|
|
self.add_mod(self.ctrl_dff_array)
|
|
|
|
|
|
|
|
|
|
self.nand2 = pnand2(height=dff_height)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_mod(self.nand2)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.nand3 = pnand3(height=dff_height)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_mod(self.nand3)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
# Special gates: inverters for buffering
|
2018-03-21 21:20:48 +01:00
|
|
|
self.clkbuf = pinvbuf(4,16,height=dff_height)
|
2018-03-12 21:14:53 +01:00
|
|
|
self.add_mod(self.clkbuf)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.inv = self.inv1 = pinv(size=1, height=dff_height)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.add_mod(self.inv1)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.inv2 = pinv(size=4, height=dff_height)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_mod(self.inv2)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.inv8 = pinv(size=16, height=dff_height)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_mod(self.inv8)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-05-12 01:32:00 +02:00
|
|
|
from importlib import reload
|
2018-01-20 01:38:19 +01:00
|
|
|
c = reload(__import__(OPTS.replica_bitline))
|
|
|
|
|
replica_bitline = getattr(c, OPTS.replica_bitline)
|
2018-02-07 23:54:59 +01:00
|
|
|
# FIXME: These should be tuned according to the size!
|
2018-07-19 19:51:20 +02:00
|
|
|
delay_stages = 4 # Must be non-inverting
|
|
|
|
|
delay_fanout = 3 # This can be anything >=2
|
2018-02-15 01:50:08 +01:00
|
|
|
bitcell_loads = int(math.ceil(self.num_rows / 5.0))
|
2018-02-16 20:51:01 +01:00
|
|
|
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.add_mod(self.replica_bitline)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setup_layout_offsets(self):
|
|
|
|
|
""" Setup layout offsets, determine the size of the busses etc """
|
2017-08-24 00:02:15 +02:00
|
|
|
# These aren't for instantiating, but we use them to get the dimensions
|
2018-03-15 01:30:41 +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
|
|
|
|
2017-09-30 01:22:13 +02:00
|
|
|
# Have the cell gap leave enough room to route an M2 wire.
|
2017-08-24 00:02:15 +02:00
|
|
|
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
|
2018-03-15 01:30:41 +01:00
|
|
|
#self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
# List of input control signals
|
2018-03-17 01:46:29 +01:00
|
|
|
self.input_list =["csb","web","oeb"]
|
2018-03-21 21:20:48 +01:00
|
|
|
self.dff_output_list =["cs_bar", "cs", "we_bar", "we", "oe_bar", "oe"]
|
|
|
|
|
# list of output control signals (for making a vertical bus)
|
2018-07-24 19:35:07 +02:00
|
|
|
self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs", "oe"]
|
2018-07-24 23:15:11 +02:00
|
|
|
# leave space for the bus plus one extra space
|
|
|
|
|
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
|
2018-03-21 21:20:48 +01:00
|
|
|
# Ooutputs to the bank
|
2018-07-16 21:58:15 +02:00
|
|
|
self.output_list = ["s_en", "w_en", "clk_buf_bar", "clk_buf"]
|
|
|
|
|
# # with tri/tri_en
|
|
|
|
|
# self.output_list = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_buf_bar", "clk_buf"]
|
2018-03-15 01:30:41 +01:00
|
|
|
self.supply_list = ["vdd", "gnd"]
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
def add_rails(self):
|
2018-03-21 21:20:48 +01:00
|
|
|
""" Add the input signal inverted tracks """
|
2018-07-16 21:58:15 +02:00
|
|
|
height = 4*self.inv1.height - self.m2_pitch
|
2018-07-24 19:35:07 +02:00
|
|
|
offset = vector(self.ctrl_dff_array.width,0)
|
|
|
|
|
|
|
|
|
|
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
def add_modules(self):
|
|
|
|
|
""" Place all the modules """
|
2018-07-24 23:15:11 +02:00
|
|
|
# Keep track of all right-most instances to determine row boundary
|
|
|
|
|
# and add the vdd/gnd pins
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst = []
|
2018-07-24 23:15:11 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# Add the control flops on the left of the bus
|
2018-03-21 21:20:48 +01:00
|
|
|
self.add_dffs()
|
2018-07-24 23:15:11 +02:00
|
|
|
|
|
|
|
|
# Add the logic on the right of the bus
|
|
|
|
|
self.add_clk_row(row=0) # clk is a double-high cell
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_we_row(row=2)
|
2018-07-16 21:58:15 +02:00
|
|
|
# self.add_trien_row(row=3)
|
|
|
|
|
# self.add_trien_bar_row(row=4)
|
2018-07-24 23:15:11 +02:00
|
|
|
self.add_rbl_in_row(row=3)
|
2018-07-16 21:58:15 +02:00
|
|
|
self.add_sen_row(row=4)
|
|
|
|
|
self.add_rbl(row=5)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-09-30 01:22:13 +02:00
|
|
|
self.add_lvs_correspondence_points()
|
|
|
|
|
|
2018-07-16 21:58:15 +02:00
|
|
|
# This offset is used for placement of the control logic in
|
|
|
|
|
# the SRAM level.
|
2018-07-16 23:13:41 +02:00
|
|
|
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by())
|
2018-07-16 21:58:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
self.height = self.rbl_inst.uy()
|
|
|
|
|
# Max of modules or logic rows
|
2018-07-24 19:12:54 +02:00
|
|
|
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst]))
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_routing(self):
|
|
|
|
|
""" Routing between modules """
|
2018-03-21 21:20:48 +01:00
|
|
|
self.route_dffs()
|
2018-07-16 21:58:15 +02:00
|
|
|
#self.route_trien()
|
|
|
|
|
#self.route_trien_bar()
|
2018-07-24 23:15:11 +02:00
|
|
|
self.route_rbl_in()
|
2018-03-15 01:30:41 +01:00
|
|
|
self.route_wen()
|
|
|
|
|
self.route_sen()
|
|
|
|
|
self.route_clk()
|
|
|
|
|
self.route_supply()
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2018-03-12 21:14:53 +01:00
|
|
|
def add_rbl(self,row):
|
|
|
|
|
""" Add the replica bitline """
|
2018-03-15 01:30:41 +01:00
|
|
|
y_off = row * self.inv1.height + 2*self.m1_pitch
|
2018-07-16 21:58:15 +02:00
|
|
|
|
2018-03-12 21:14:53 +01:00
|
|
|
# Add the RBL above the rows
|
|
|
|
|
# Add to the right of the control rows and routing channel
|
|
|
|
|
self.replica_bitline_offset = vector(0, y_off)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.rbl_inst=self.add_inst(name="replica_bitline",
|
|
|
|
|
mod=self.replica_bitline,
|
|
|
|
|
offset=self.replica_bitline_offset)
|
2018-07-24 23:15:11 +02:00
|
|
|
self.connect_inst(["rbl_in", "pre_s_en", "vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
|
2018-07-16 21:58:15 +02:00
|
|
|
def add_clk_row(self,row):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Add the multistage clock buffer below the control flops """
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
clkbuf_offset = vector(x_off,y_off)
|
2018-07-24 19:12:54 +02:00
|
|
|
self.clkbuf_inst = self.add_inst(name="clkbuf",
|
|
|
|
|
mod=self.clkbuf,
|
|
|
|
|
offset=clkbuf_offset)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
self.connect_inst(["clk","clk_buf_bar","clk_buf","vdd","gnd"])
|
2018-07-16 21:58:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst.append(self.clkbuf_inst)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
|
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
def add_rbl_in_row(self,row):
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
# input: OE, clk_buf_bar,CS output: rbl_in_bar
|
|
|
|
|
self.rbl_in_bar_offset = vector(x_off, y_off)
|
|
|
|
|
self.rbl_in_bar_inst=self.add_inst(name="nand3_rbl_in_bar",
|
2018-07-24 19:12:54 +02:00
|
|
|
mod=self.nand3,
|
2018-07-24 23:15:11 +02:00
|
|
|
offset=self.rbl_in_bar_offset,
|
2018-07-24 19:12:54 +02:00
|
|
|
mirror=mirror)
|
2018-07-24 23:15:11 +02:00
|
|
|
self.connect_inst(["clk_buf_bar", "oe", "cs", "rbl_in_bar", "vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
x_off += self.nand3.width
|
|
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
# input: rbl_in_bar, output: rbl_in
|
|
|
|
|
self.rbl_in_offset = vector(x_off, y_off)
|
|
|
|
|
self.rbl_in_inst=self.add_inst(name="inv_rbl_in",
|
|
|
|
|
mod=self.inv1,
|
|
|
|
|
offset=self.rbl_in_offset,
|
|
|
|
|
mirror=mirror)
|
|
|
|
|
self.connect_inst(["rbl_in_bar", "rbl_in", "vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
self.row_end_inst.append(self.rbl_in_inst)
|
2018-07-24 19:12:54 +02:00
|
|
|
|
2018-03-12 21:14:53 +01:00
|
|
|
def add_sen_row(self,row):
|
2018-03-15 01:30:41 +01:00
|
|
|
""" The sense enable buffer gets placed to the far right of the
|
|
|
|
|
row. """
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2018-07-24 23:15:11 +02:00
|
|
|
|
|
|
|
|
# input: pre_s_en, output: pre_s_en_bar
|
|
|
|
|
self.pre_s_en_bar_offset = vector(x_off, y_off)
|
|
|
|
|
self.pre_s_en_bar_inst=self.add_inst(name="inv_pre_s_en_bar",
|
|
|
|
|
mod=self.inv2,
|
|
|
|
|
offset=self.pre_s_en_bar_offset,
|
|
|
|
|
mirror=mirror)
|
|
|
|
|
self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"])
|
|
|
|
|
|
|
|
|
|
x_off += self.inv2.width
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
# BUFFER INVERTERS FOR S_EN
|
2017-08-24 00:02:15 +02:00
|
|
|
# input: input: pre_s_en_bar, output: s_en
|
|
|
|
|
self.s_en_offset = vector(x_off, y_off)
|
2018-07-24 19:12:54 +02:00
|
|
|
self.s_en_inst=self.add_inst(name="inv_s_en",
|
|
|
|
|
mod=self.inv8,
|
|
|
|
|
offset=self.s_en_offset,
|
|
|
|
|
mirror=mirror)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["pre_s_en_bar", "s_en", "vdd", "gnd"])
|
2018-07-24 19:12:54 +02:00
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst.append(self.s_en_inst)
|
|
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
def add_trien_row(self, row):
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
|
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
x_off += self.nand2.width
|
|
|
|
|
|
|
|
|
|
# BUFFER INVERTERS FOR TRI_EN
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_offset = vector(x_off, y_off)
|
|
|
|
|
self.tri_en_inst=self.add_inst(name="inv_tri_en1",
|
|
|
|
|
mod=self.inv2,
|
|
|
|
|
offset=tri_en_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["pre_tri_en_bar", "pre_tri_en1", "vdd", "gnd"])
|
|
|
|
|
x_off += self.inv2.width
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_buf1_offset = vector(x_off, y_off)
|
|
|
|
|
self.tri_en_buf1_inst=self.add_inst(name="tri_en_buf1",
|
|
|
|
|
mod=self.inv2,
|
|
|
|
|
offset=tri_en_buf1_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["pre_tri_en1", "pre_tri_en_bar1", "vdd", "gnd"])
|
|
|
|
|
x_off += self.inv2.width
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_buf2_offset = vector(x_off, y_off)
|
|
|
|
|
self.tri_en_buf2_inst=self.add_inst(name="tri_en_buf2",
|
|
|
|
|
mod=self.inv8,
|
|
|
|
|
offset=tri_en_buf2_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["pre_tri_en_bar1", "tri_en", "vdd", "gnd"])
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst.append(self.tri_en_inst)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
def add_trien_bar_row(self, row):
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_array.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
# input: OE, clk_buf_bar output: tri_en_bar
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_bar_offset = vector(x_off,y_off)
|
|
|
|
|
self.tri_en_bar_inst=self.add_inst(name="nand2_tri_en",
|
|
|
|
|
mod=self.nand2,
|
|
|
|
|
offset=tri_en_bar_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["clk_buf_bar", "oe", "pre_tri_en_bar", "vdd", "gnd"])
|
|
|
|
|
x_off += self.nand2.width
|
|
|
|
|
|
|
|
|
|
# BUFFER INVERTERS FOR TRI_EN
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_bar_buf1_offset = vector(x_off, y_off)
|
|
|
|
|
self.tri_en_bar_buf1_inst=self.add_inst(name="tri_en_bar_buf1",
|
|
|
|
|
mod=self.inv2,
|
|
|
|
|
offset=tri_en_bar_buf1_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["pre_tri_en_bar", "pre_tri_en2", "vdd", "gnd"])
|
|
|
|
|
x_off += self.inv2.width
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_bar_buf2_offset = vector(x_off, y_off)
|
|
|
|
|
self.tri_en_bar_buf2_inst=self.add_inst(name="tri_en_bar_buf2",
|
|
|
|
|
mod=self.inv8,
|
|
|
|
|
offset=tri_en_bar_buf2_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["pre_tri_en2", "tri_en_bar", "vdd", "gnd"])
|
|
|
|
|
x_off += self.inv8.width
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst.append(self.tri_en_bar_buf2_inst)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
def route_dffs(self):
|
2018-03-15 01:30:41 +01:00
|
|
|
""" Route the input inverters """
|
2018-03-21 21:20:48 +01:00
|
|
|
|
2018-07-24 19:35:07 +02:00
|
|
|
dff_out_map = zip(["dout_bar[{}]".format(i) for i in range(3)], ["cs", "we", "oe"])
|
|
|
|
|
self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.rail_offsets)
|
|
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
# Connect the clock rail to the other clock rail
|
|
|
|
|
in_pos = self.ctrl_dff_inst.get_pin("clk").uc()
|
|
|
|
|
mid_pos = in_pos + vector(0,self.m2_pitch)
|
2018-07-24 19:35:07 +02:00
|
|
|
rail_pos = vector(self.rail_offsets["clk_buf"].x, mid_pos.y)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.add_wire(("metal1","via1","metal2"),[in_pos, mid_pos, rail_pos])
|
|
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
|
|
|
|
offset=rail_pos,
|
|
|
|
|
rotate=90)
|
2018-03-21 23:23:32 +01:00
|
|
|
|
|
|
|
|
self.copy_layout_pin(self.ctrl_dff_inst, "din[0]", "csb")
|
|
|
|
|
self.copy_layout_pin(self.ctrl_dff_inst, "din[1]", "web")
|
|
|
|
|
self.copy_layout_pin(self.ctrl_dff_inst, "din[2]", "oeb")
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
def add_dffs(self):
|
|
|
|
|
""" Add the three input DFFs (with inverters) """
|
|
|
|
|
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
|
|
|
|
|
mod=self.ctrl_dff_array,
|
|
|
|
|
offset=vector(0,0))
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
self.connect_inst(self.input_list + self.dff_output_list + ["clk_buf"] + self.supply_list)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
|
|
|
|
|
def get_offset(self,row):
|
|
|
|
|
""" Compute the y-offset and mirroring """
|
2018-03-12 21:14:53 +01:00
|
|
|
y_off = row*self.inv1.height
|
|
|
|
|
if row % 2:
|
|
|
|
|
y_off += self.inv1.height
|
|
|
|
|
mirror="MX"
|
|
|
|
|
else:
|
|
|
|
|
mirror="R0"
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
return (y_off,mirror)
|
|
|
|
|
|
|
|
|
|
def add_we_row(self,row):
|
2018-07-24 19:35:07 +02:00
|
|
|
x_off = self.ctrl_dff_inst.width + self.internal_bus_width
|
2018-07-24 19:12:54 +02:00
|
|
|
(y_off,mirror)=self.get_offset(row)
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
# input: WE, clk_buf_bar, CS output: w_en_bar
|
2018-07-24 19:12:54 +02:00
|
|
|
w_en_bar_offset = vector(x_off, y_off)
|
|
|
|
|
self.w_en_bar_inst=self.add_inst(name="nand3_w_en_bar",
|
|
|
|
|
mod=self.nand3,
|
|
|
|
|
offset=w_en_bar_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
x_off += self.nand3.width
|
|
|
|
|
|
|
|
|
|
# input: w_en_bar, output: pre_w_en
|
2018-07-24 19:12:54 +02:00
|
|
|
pre_w_en_offset = vector(x_off, y_off)
|
|
|
|
|
self.pre_w_en_inst=self.add_inst(name="inv_pre_w_en",
|
|
|
|
|
mod=self.inv1,
|
|
|
|
|
offset=pre_w_en_offset,
|
|
|
|
|
mirror=mirror)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["w_en_bar", "pre_w_en", "vdd", "gnd"])
|
2017-08-24 00:02:15 +02:00
|
|
|
x_off += self.inv1.width
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
# BUFFER INVERTERS FOR W_EN
|
2018-07-24 19:12:54 +02:00
|
|
|
pre_w_en_bar_offset = vector(x_off, y_off)
|
|
|
|
|
self.pre_w_en_bar_inst=self.add_inst(name="inv_pre_w_en_bar",
|
|
|
|
|
mod=self.inv2,
|
|
|
|
|
offset=pre_w_en_bar_offset,
|
|
|
|
|
mirror=mirror)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"])
|
2018-03-15 01:30:41 +01:00
|
|
|
x_off += self.inv2.width
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
w_en_offset = vector(x_off, y_off)
|
|
|
|
|
self.w_en_inst=self.add_inst(name="inv_w_en2",
|
|
|
|
|
mod=self.inv8,
|
|
|
|
|
offset=w_en_offset,
|
|
|
|
|
mirror=mirror)
|
2017-08-24 00:02:15 +02:00
|
|
|
self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"])
|
2018-03-15 01:30:41 +01:00
|
|
|
x_off += self.inv8.width
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.row_end_inst.append(self.w_en_inst)
|
2018-03-12 21:14:53 +01:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
def route_rbl_in(self):
|
|
|
|
|
""" Connect the logic for the rbl_in generation """
|
|
|
|
|
rbl_in_map = zip(["A", "B", "C"], ["clk_buf_bar", "oe", "cs"])
|
|
|
|
|
self.connect_vertical_bus(rbl_in_map, self.rbl_in_bar_inst, self.rail_offsets)
|
2018-07-24 19:35:07 +02:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
# Connect the NAND3 output to the inverter
|
|
|
|
|
# The pins are assumed to extend all the way to the cell edge
|
2018-07-24 23:15:11 +02:00
|
|
|
rbl_in_bar_pos = self.rbl_in_bar_inst.get_pin("Z").center()
|
|
|
|
|
inv_in_pos = self.rbl_in_inst.get_pin("A").center()
|
|
|
|
|
mid1 = vector(inv_in_pos.x,rbl_in_bar_pos.y)
|
|
|
|
|
self.add_path("metal1",[rbl_in_bar_pos,mid1,inv_in_pos])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Connect the output to the RBL
|
2018-07-24 23:15:11 +02:00
|
|
|
rbl_out_pos = self.rbl_in_inst.get_pin("Z").center()
|
2018-03-15 01:30:41 +01:00
|
|
|
rbl_in_pos = self.rbl_inst.get_pin("en").center()
|
2018-07-24 23:15:11 +02:00
|
|
|
mid1 = vector(rbl_in_pos.x,rbl_out_pos.y)
|
|
|
|
|
self.add_wire(("metal3","via2","metal2"),[rbl_out_pos,mid1,rbl_in_pos])
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
2018-07-24 23:15:11 +02:00
|
|
|
offset=rbl_out_pos,
|
2018-03-15 01:30:41 +01:00
|
|
|
rotate=90)
|
|
|
|
|
self.add_via_center(layers=("metal2","via2","metal3"),
|
2018-07-24 23:15:11 +02:00
|
|
|
offset=rbl_out_pos,
|
2018-03-15 01:30:41 +01:00
|
|
|
rotate=90)
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
def connect_rail_from_right(self,inst, pin, rail):
|
|
|
|
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
2017-12-12 23:53:19 +01:00
|
|
|
in_pos = inst.get_pin(pin).center()
|
2018-07-24 19:35:07 +02:00
|
|
|
rail_pos = vector(self.rail_offsets[rail].x, in_pos.y)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_wire(("metal1","via1","metal2"),[in_pos, rail_pos])
|
|
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
|
|
|
|
offset=rail_pos,
|
|
|
|
|
rotate=90)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
def connect_rail_from_right_m2m3(self,inst, pin, rail):
|
|
|
|
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
2018-03-15 01:30:41 +01:00
|
|
|
in_pos = inst.get_pin(pin).center()
|
2018-07-24 19:35:07 +02:00
|
|
|
rail_pos = vector(self.rail_offsets[rail].x, in_pos.y)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
|
2017-08-24 00:02:15 +02:00
|
|
|
# Bring it up to M2 for M2/M3 routing
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
|
|
|
|
offset=in_pos,
|
2016-11-08 18:57:35 +01:00
|
|
|
rotate=90)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_via_center(layers=("metal2","via2","metal3"),
|
|
|
|
|
offset=in_pos,
|
2016-11-08 18:57:35 +01:00
|
|
|
rotate=90)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_via_center(layers=("metal2","via2","metal3"),
|
|
|
|
|
offset=rail_pos,
|
|
|
|
|
rotate=90)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def connect_rail_from_left(self,inst, pin, rail):
|
|
|
|
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
2018-03-15 01:30:41 +01:00
|
|
|
in_pos = inst.get_pin(pin).lc()
|
2018-07-24 19:35:07 +02:00
|
|
|
rail_pos = vector(self.rail_offsets[rail].x, in_pos.y)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_wire(("metal1","via1","metal2"),[in_pos, rail_pos])
|
|
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
|
|
|
|
offset=rail_pos,
|
2016-11-08 18:57:35 +01:00
|
|
|
rotate=90)
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
def connect_rail_from_left_m2m3(self,inst, pin, rail):
|
|
|
|
|
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
|
2018-03-15 01:30:41 +01:00
|
|
|
in_pos = inst.get_pin(pin).lc()
|
2018-07-24 19:35:07 +02:00
|
|
|
rail_pos = vector(self.rail_offsets[rail].x, in_pos.y)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
|
|
|
|
|
self.add_via_center(layers=("metal2","via2","metal3"),
|
|
|
|
|
offset=in_pos,
|
2017-08-24 00:02:15 +02:00
|
|
|
rotate=90)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_via_center(layers=("metal2","via2","metal3"),
|
|
|
|
|
offset=rail_pos,
|
2017-08-24 00:02:15 +02:00
|
|
|
rotate=90)
|
|
|
|
|
|
|
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
def route_wen(self):
|
2018-07-24 19:35:07 +02:00
|
|
|
wen_map = zip(["A", "B", "C"], ["clk_buf_bar", "cs", "we"])
|
|
|
|
|
self.connect_vertical_bus(wen_map, self.w_en_bar_inst, self.rail_offsets)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
# Connect the NAND3 output to the inverter
|
|
|
|
|
# The pins are assumed to extend all the way to the cell edge
|
2018-07-24 19:12:54 +02:00
|
|
|
w_en_bar_pos = self.w_en_bar_inst.get_pin("Z").center()
|
|
|
|
|
inv_in_pos = self.pre_w_en_inst.get_pin("A").center()
|
2018-03-15 01:30:41 +01:00
|
|
|
mid1 = vector(inv_in_pos.x,w_en_bar_pos.y)
|
|
|
|
|
self.add_path("metal1",[w_en_bar_pos,mid1,inv_in_pos])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.add_path("metal1",[self.pre_w_en_inst.get_pin("Z").center(), self.pre_w_en_bar_inst.get_pin("A").center()])
|
|
|
|
|
self.add_path("metal1",[self.pre_w_en_bar_inst.get_pin("Z").center(), self.w_en_inst.get_pin("A").center()])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.connect_output(self.w_en_inst, "Z", "w_en")
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
def route_trien(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
# Connect the NAND2 output to the buffer
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_bar_pos = self.tri_en_bar_inst.get_pin("Z").center()
|
|
|
|
|
inv_in_pos = self.tri_en_inst.get_pin("A").center()
|
2018-03-15 01:30:41 +01:00
|
|
|
mid1 = vector(tri_en_bar_pos.x,inv_in_pos.y)
|
|
|
|
|
self.add_wire(("metal1","via1","metal2"),[tri_en_bar_pos,mid1,inv_in_pos])
|
|
|
|
|
|
|
|
|
|
# Connect the INV output to the buffer
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_pos = self.tri_en_inst.get_pin("Z").center()
|
|
|
|
|
inv_in_pos = self.tri_en_buf1_inst.get_pin("A").center()
|
2018-03-15 01:30:41 +01:00
|
|
|
mid_xoffset = 0.5*(tri_en_pos.x + inv_in_pos.x)
|
|
|
|
|
mid1 = vector(mid_xoffset,tri_en_pos.y)
|
|
|
|
|
mid2 = vector(mid_xoffset,inv_in_pos.y)
|
|
|
|
|
self.add_path("metal1",[tri_en_pos,mid1,mid2,inv_in_pos])
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.add_path("metal1",[self.tri_en_buf1_ist.get_pin("Z").center(), self.tri_en_buf2_inst.get_pin("A").center()])
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.connect_output(self.tri_en_buf2_inst, "Z", "tri_en")
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
def route_trien_bar(self):
|
|
|
|
|
|
2018-07-24 19:35:07 +02:00
|
|
|
trien_map = zip(["A", "B"], ["clk_buf_bar", "oe"])
|
|
|
|
|
self.connect_vertical_bus(trien_map, self.tri_en_bar_inst, self.rail_offsets)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
# Connect the NAND2 output to the buffer
|
2018-07-24 19:12:54 +02:00
|
|
|
tri_en_bar_pos = self.tri_en_bar_inst.get_pin("Z").center()
|
|
|
|
|
inv_in_pos = self.tri_en_bar_buf1_inst.get_pin("A").center()
|
2018-03-15 01:30:41 +01:00
|
|
|
mid_xoffset = 0.5*(tri_en_bar_pos.x + inv_in_pos.x)
|
|
|
|
|
mid1 = vector(mid_xoffset,tri_en_bar_pos.y)
|
|
|
|
|
mid2 = vector(mid_xoffset,inv_in_pos.y)
|
|
|
|
|
self.add_path("metal1",[tri_en_bar_pos,mid1,mid2,inv_in_pos])
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.add_path("metal1",[self.tri_en_bar_buf1_inst.get_pin("Z").center(), self.tri_en_bar_buf2_inst.get_pin("A").center()])
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.connect_output(self.tri_en_bar_buf2_inst, "Z", "tri_en_bar")
|
2017-08-24 00:02:15 +02:00
|
|
|
|
|
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
def route_sen(self):
|
|
|
|
|
rbl_out_pos = self.rbl_inst.get_pin("out").bc()
|
2018-07-24 19:12:54 +02:00
|
|
|
in_pos = self.pre_s_en_bar_inst.get_pin("A").lc()
|
2017-12-12 23:53:19 +01:00
|
|
|
mid1 = vector(rbl_out_pos.x,in_pos.y)
|
2018-03-15 01:30:41 +01:00
|
|
|
self.add_wire(("metal1","via1","metal2"),[rbl_out_pos,mid1,in_pos])
|
2017-12-12 23:53:19 +01:00
|
|
|
#s_en_pos = self.s_en.get_pin("Z").lc()
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.add_path("metal1",[self.pre_s_en_bar_inst.get_pin("Z").center(), self.s_en_inst.get_pin("A").center()])
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
self.connect_output(self.s_en_inst, "Z", "s_en")
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
def route_clk(self):
|
|
|
|
|
""" Route the clk and clk_buf_bar signal internally """
|
|
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
clk_pin = self.clkbuf_inst.get_pin("A")
|
2018-03-21 21:20:48 +01:00
|
|
|
self.add_layout_pin_segment_center(text="clk",
|
2017-12-12 23:53:19 +01:00
|
|
|
layer="metal2",
|
2018-03-15 01:30:41 +01:00
|
|
|
start=clk_pin.bc(),
|
|
|
|
|
end=clk_pin.bc().scale(1,0))
|
2017-09-30 01:22:13 +02:00
|
|
|
|
2018-07-24 19:35:07 +02:00
|
|
|
clkbuf_map = zip(["Z", "Zb"], ["clk_buf", "clk_buf_bar"])
|
|
|
|
|
self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2"))
|
|
|
|
|
|
|
|
|
|
# self.connect_rail_from_right_m2m3(self.clkbuf_inst, "Z", "clk_buf")
|
|
|
|
|
# self.connect_rail_from_right_m2m3(self.clkbuf_inst, "Zb", "clk_buf_bar")
|
2018-07-24 19:12:54 +02:00
|
|
|
self.connect_output(self.clkbuf_inst, "Z", "clk_buf")
|
|
|
|
|
self.connect_output(self.clkbuf_inst, "Zb", "clk_buf_bar")
|
2018-03-15 01:30:41 +01:00
|
|
|
|
|
|
|
|
def connect_output(self, inst, pin_name, out_name):
|
|
|
|
|
""" Create an output pin on the right side from the pin of a given instance. """
|
2018-03-21 23:23:32 +01:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
out_pin = inst.get_pin(pin_name)
|
2018-03-15 01:30:41 +01:00
|
|
|
right_pos=out_pin.center() + vector(self.width-out_pin.cx(),0)
|
2018-03-21 21:20:48 +01:00
|
|
|
self.add_layout_pin_segment_center(text=out_name,
|
2018-03-15 01:30:41 +01:00
|
|
|
layer="metal1",
|
|
|
|
|
start=out_pin.center(),
|
|
|
|
|
end=right_pos)
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
def route_supply(self):
|
2018-07-24 19:12:54 +02:00
|
|
|
""" Add vdd and gnd to the instance cells """
|
2018-07-16 21:58:15 +02:00
|
|
|
|
2018-07-24 23:15:11 +02:00
|
|
|
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
|
2018-07-24 19:12:54 +02:00
|
|
|
for inst in self.row_end_inst:
|
|
|
|
|
pins = inst.get_pins("vdd")
|
|
|
|
|
for pin in pins:
|
|
|
|
|
if pin.layer == "metal1":
|
2018-07-24 23:15:11 +02:00
|
|
|
row_loc = pin.rc()
|
|
|
|
|
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
|
|
|
|
self.add_power_pin("vdd", pin_loc)
|
|
|
|
|
self.add_path("metal1", [row_loc, pin_loc])
|
2018-03-15 01:30:41 +01:00
|
|
|
|
2018-07-24 19:12:54 +02:00
|
|
|
pins = inst.get_pins("gnd")
|
|
|
|
|
for pin in pins:
|
|
|
|
|
if pin.layer == "metal1":
|
2018-07-24 23:15:11 +02:00
|
|
|
row_loc = pin.rc()
|
|
|
|
|
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
|
|
|
|
self.add_power_pin("gnd", pin_loc)
|
|
|
|
|
self.add_path("metal1", [row_loc, pin_loc])
|
2018-07-24 19:12:54 +02:00
|
|
|
|
2018-03-21 21:20:48 +01:00
|
|
|
|
|
|
|
|
self.copy_layout_pin(self.rbl_inst,"gnd")
|
|
|
|
|
self.copy_layout_pin(self.rbl_inst,"vdd")
|
2018-07-24 19:12:54 +02:00
|
|
|
|
|
|
|
|
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
|
|
|
|
|
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
|
2018-03-21 21:20:48 +01:00
|
|
|
|
2018-03-17 01:46:29 +01:00
|
|
|
|
2017-09-30 01:22:13 +02: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.
|
|
|
|
|
"""
|
2018-03-12 21:14:53 +01:00
|
|
|
# pin=self.clk_inv1.get_pin("Z")
|
|
|
|
|
# self.add_label_pin(text="clk1_bar",
|
|
|
|
|
# layer="metal1",
|
|
|
|
|
# offset=pin.ll(),
|
|
|
|
|
# height=pin.height(),
|
|
|
|
|
# width=pin.width())
|
|
|
|
|
|
|
|
|
|
# pin=self.clk_inv2.get_pin("Z")
|
|
|
|
|
# self.add_label_pin(text="clk2",
|
|
|
|
|
# layer="metal1",
|
|
|
|
|
# offset=pin.ll(),
|
|
|
|
|
# height=pin.height(),
|
|
|
|
|
# width=pin.width())
|
2017-09-30 01:22:13 +02:00
|
|
|
|
2018-03-15 01:30:41 +01:00
|
|
|
pin=self.rbl_inst.get_pin("out")
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_label_pin(text="out",
|
2018-03-15 01:30:41 +01:00
|
|
|
layer=pin.layer,
|
2017-12-12 23:53:19 +01:00
|
|
|
offset=pin.ll(),
|
|
|
|
|
height=pin.height(),
|
|
|
|
|
width=pin.width())
|
|
|
|
|
|
2018-03-12 21:14:53 +01:00
|
|
|
|