mirror of https://github.com/VLSIDA/OpenRAM.git
add most functions needed for delay control logic, fix multi-delay pin order issue
This commit is contained in:
parent
45239ca2a9
commit
7d4b718344
|
|
@ -77,7 +77,7 @@ class control_logic_delay(design.design):
|
|||
|
||||
def add_pins(self):
|
||||
""" Add the pins to the control logic module. """
|
||||
self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
|
||||
self.add_pin_list(self.input_list + ["clk"], "INPUT")
|
||||
self.add_pin_list(self.output_list, "OUTPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
|
@ -250,10 +250,8 @@ class control_logic_delay(design.design):
|
|||
# List of input control signals
|
||||
if self.port_type == "rw":
|
||||
self.input_list = ["csb", "web"]
|
||||
self.rbl_list = ["rbl_bl"]
|
||||
else:
|
||||
self.input_list = ["csb"]
|
||||
self.rbl_list = ["rbl_bl"]
|
||||
|
||||
if self.port_type == "rw":
|
||||
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
|
||||
|
|
@ -262,11 +260,9 @@ class control_logic_delay(design.design):
|
|||
|
||||
# list of output control signals (for making a vertical bus)
|
||||
if self.port_type == "rw":
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"]
|
||||
elif self.port_type == "r":
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
|
||||
self.internal_bus_list = ["glitch1_bar", "glitch2_bar", "glitch3_bar", "pre_sen", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"]
|
||||
else:
|
||||
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
|
||||
self.internal_bus_list = ["glitch1_bar", "glitch2_bar", "glitch3_bar", "pre_sen", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
|
||||
# leave space for the bus plus one extra space
|
||||
self.internal_bus_width = (len(self.internal_bus_list) + 1) * self.m2_pitch
|
||||
|
||||
|
|
@ -302,7 +298,7 @@ class control_logic_delay(design.design):
|
|||
self.create_gated_clk_buf_row()
|
||||
self.create_delay()
|
||||
self.create_glitches()
|
||||
self.create_glitch3_additional_invs()
|
||||
self.create_pre_sen_invs()
|
||||
self.create_wlen_row()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.create_wen_row()
|
||||
|
|
@ -338,13 +334,18 @@ class control_logic_delay(design.design):
|
|||
row += 1
|
||||
self.place_pen_row(row)
|
||||
row += 1
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.place_rbl_delay_row(row)
|
||||
row += 1
|
||||
self.place_wlen_row(row)
|
||||
row += 1
|
||||
self.place_glitch1_row(row)
|
||||
row += 1
|
||||
self.place_glitch2_row(row)
|
||||
row += 1
|
||||
self.place_glitch3_row(row)
|
||||
row += 1
|
||||
self.place_pre_sen_row(row)
|
||||
row += 1
|
||||
|
||||
control_center_y = self.wl_en_inst.uy() + self.m3_pitch
|
||||
control_center_y = self.pre_sen_inv_inst.uy() + self.m3_pitch
|
||||
|
||||
# Delay chain always gets placed at row 4
|
||||
self.place_delay(4)
|
||||
|
|
@ -357,7 +358,8 @@ class control_logic_delay(design.design):
|
|||
self.height = height + 2 * self.m1_pitch
|
||||
# Max of modules or logic rows
|
||||
self.width = max([inst.rx() for inst in self.row_end_inst])
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
# TODO: why not w ports here?
|
||||
self.width = max(self.delay_inst.rx(), self.width)
|
||||
self.width += self.m2_pitch
|
||||
|
||||
|
|
@ -367,7 +369,6 @@ class control_logic_delay(design.design):
|
|||
self.route_dffs()
|
||||
self.route_wlen()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.route_rbl_delay()
|
||||
self.route_wen()
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.route_sen()
|
||||
|
|
@ -382,25 +383,24 @@ class control_logic_delay(design.design):
|
|||
""" Create the delay chain """
|
||||
self.delay_inst=self.add_inst(name="multi_delay_chain",
|
||||
mod=self.multi_delay_chain)
|
||||
self.connect_inst(["gated_clk_buf", "out1", "out6", "out7", "out14", "vdd", "gnd"])
|
||||
self.connect_inst(["gated_clk_buf", "delay1", "delay2", "delay3", "delay4", "vdd", "gnd"])
|
||||
|
||||
def place_delay(self, row):
|
||||
""" Place the replica bitline """
|
||||
""" Place the delay chain """
|
||||
debug.check(row % 2 == 0, "Must place delay chain at even row for supply alignment.")
|
||||
|
||||
# It is flipped on X axis
|
||||
y_off = row * self.and2.height + self.delay_chain.height
|
||||
y_off = row * self.and2.height + self.multi_delay_chain.height
|
||||
|
||||
# Add the RBL above the rows
|
||||
# Add to the right of the control rows and routing channel
|
||||
offset = vector(0, y_off)
|
||||
self.delay_inst.place(offset, mirror="MX")
|
||||
|
||||
def route_delay(self):
|
||||
def route_delay(self): # TODO: this
|
||||
|
||||
out_pos = self.delay_inst.get_pin("out").center()
|
||||
# Connect to the rail level with the vdd rail
|
||||
# Use gated clock since it is in every type of control logic # TODO: git blame whoever wrote this, do they mean every type made by others or is this foreshadowing our future addition of delay/async logic. If the former, seems a bit odd to include something basically explanatory. If the latter, seems odd I'm hearing about it now for the first time, because it begs the question if there are other steps that have been taken to lay groundwork for control logic varieties.
|
||||
# Use gated clock since it is in every type of control logic
|
||||
vdd_ypos = self.gated_clk_buf_inst.get_pin("vdd").cy() + self.m1_pitch
|
||||
in_pos = vector(self.input_bus["rbl_bl_delay"].cx(), vdd_ypos)
|
||||
mid1 = vector(out_pos.x, in_pos.y)
|
||||
|
|
@ -416,19 +416,19 @@ class control_logic_delay(design.design):
|
|||
def create_glitches(self):
|
||||
self.glitch1_inv_inst = self.add_inst(name="inv_glitch1",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["out6", "g1_end", "vdd", "gnd"])
|
||||
self.connect_inst(["delay2", "g1_end", "vdd", "gnd"])
|
||||
|
||||
self.glitch2_inv_inst = self.add_inst(name="inv_glitch2",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["out7", "g2_end", "vdd", "gnd"])
|
||||
self.connect_inst(["delay3", "g2_end", "vdd", "gnd"])
|
||||
|
||||
self.glitch3_inv_inst = self.add_inst(name="inv_glitch3",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["out14", "g3_end", "vdd", "gnd"])
|
||||
self.connect_inst(["delay4", "g3_end", "vdd", "gnd"])
|
||||
|
||||
self.glitch1_nand_inst = self.add_inst(name="nand2_glitch1",
|
||||
mod=self.nand2)
|
||||
self.connect_inst(["out1", "g1_end", "glitch1_bar", "vdd", "gnd"])
|
||||
self.connect_inst(["delay1", "g1_end", "glitch1_bar", "vdd", "gnd"])
|
||||
|
||||
self.glitch2_nand_inst = self.add_inst(name="nand2_glitch2",
|
||||
mod=self.nand2)
|
||||
|
|
@ -436,7 +436,38 @@ class control_logic_delay(design.design):
|
|||
|
||||
self.glitch3_nand_inst = self.add_inst(name="nand2_glitch3",
|
||||
mod=self.nand2)
|
||||
self.connect_inst(["out6", "g3_end", "glitch3_bar", "vdd", "gnd"])
|
||||
self.connect_inst(["delay2", "g3_end", "glitch3_bar", "vdd", "gnd"])
|
||||
|
||||
def place_glitch1_row(self, row):
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.glitch1_inv_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.glitch1_nand_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.glitch1_nand_inst)
|
||||
|
||||
def place_glitch2_row(self, row):
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.glitch2_inv_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.glitch2_nand_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.glitch3_nand_inst)
|
||||
|
||||
def place_glitch3_row(self, row):
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.glitch3_inv_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.glitch3_nand_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.glitch3_nand_inst)
|
||||
|
||||
def route_glitches(self): # TODO: this
|
||||
glitch1_map = zip(["A"], ["gated_clk_bar"])
|
||||
|
||||
self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.input_bus)
|
||||
|
||||
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
||||
|
||||
def create_clk_buf_row(self):
|
||||
""" Create the multistage and gated clock buffer """
|
||||
|
|
@ -444,7 +475,7 @@ class control_logic_delay(design.design):
|
|||
mod=self.clk_buf_driver)
|
||||
self.connect_inst(["clk", "clk_buf", "vdd", "gnd"])
|
||||
|
||||
def create_cs_buf_row(self):
|
||||
def create_cs_buf_row(self): # TODO: place and route
|
||||
""" Create the multistage and gated chip select buffer """
|
||||
self.cs_buf_inst = self.add_inst(name="csbuf",
|
||||
mod=self.clk_buf_driver)
|
||||
|
|
@ -570,10 +601,6 @@ class control_logic_delay(design.design):
|
|||
self.connect_output(self.wl_en_inst, "Z", "wl_en")
|
||||
|
||||
def create_pen_row(self):
|
||||
# FIXME: comment below
|
||||
# We use the rbl_bl_delay here to ensure that the p_en is only asserted when the
|
||||
# bitlines have already been discharged. Otherwise, it is a combination loop.
|
||||
|
||||
self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar",
|
||||
mod=self.p_en_bar_driver)
|
||||
self.connect_inst(["glitch1_bar", "p_en_bar", "vdd", "gnd"])
|
||||
|
|
@ -602,15 +629,23 @@ class control_logic_delay(design.design):
|
|||
|
||||
self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar")
|
||||
|
||||
def create_glitch3_additional_invs(self):
|
||||
def create_pre_sen_invs(self):
|
||||
""" A pair of inverters to create additional signals from and buffer glitch 3"""
|
||||
self.glitch3_buf_inv_inst = self.add_inst(name="inv_glitch3_buf",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["glitch3_bar", "glitch3_buf", "vdd", "gnd"])
|
||||
|
||||
self.pre_sen_inv = self.add_inst(name="inv_pre_sen",
|
||||
self.pre_sen_inv_inst = self.add_inst(name="inv_pre_sen",
|
||||
mod=self.inv)
|
||||
self.connect_inst(["gltich3_buf", "pre_sen", "vdd", "gnd"])
|
||||
self.connect_inst(["glitch3_buf", "pre_sen", "vdd", "gnd"])
|
||||
|
||||
def place_pre_sen_row(self, row):
|
||||
x_offset = self.control_x_offset
|
||||
|
||||
x_offset = self.place_util(self.glitch3_buf_inv_inst, x_offset, row)
|
||||
x_offset = self.place_util(self.pre_sen_inv_inst, x_offset, row)
|
||||
|
||||
self.row_end_inst.append(self.pre_sen_inv_inst)
|
||||
|
||||
def create_sen_row(self):
|
||||
""" Create the sense enable buffer. """
|
||||
|
|
@ -621,10 +656,6 @@ class control_logic_delay(design.design):
|
|||
# GATE FOR S_EN
|
||||
self.s_en_gate_inst = self.add_inst(name="and_s_en",
|
||||
mod=self.sen_and3)
|
||||
# FIXME: comment below
|
||||
# s_en is asserted in the second half of the cycle during a read.
|
||||
# we also must wait until the bitline has been discharged enough for proper sensing
|
||||
# hence we use rbl_bl_delay as well.
|
||||
self.connect_inst(["pre_sen", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
|
||||
|
||||
def place_sen_row(self, row):
|
||||
|
|
@ -693,7 +724,7 @@ class control_logic_delay(design.design):
|
|||
if self.port_type == "rw":
|
||||
dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
|
||||
elif self.port_type == "r":
|
||||
dff_out_map = zip(["dout_bar_0", "dout_0"], ["cs", "cs_bar"])
|
||||
dff_out_map = zip(["dout_bar_0"], ["cs"])
|
||||
else:
|
||||
dff_out_map = zip(["dout_bar_0"], ["cs"])
|
||||
self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.input_bus, self.m2_stack[::-1])
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2021 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class delay_chain(design.design):
|
||||
"""
|
||||
Generate a delay chain with the given number of stages, fanout, and output pins.
|
||||
Fanout list contains the electrical effort (fanout) of each stage.
|
||||
Usually, this will be constant, but it could have varied fanout.
|
||||
Pinout list contains the inverter stages which have an output pin attached.
|
||||
Supplying an empty pinout list will result in an output on the last stage.
|
||||
"""
|
||||
|
||||
def __init__(self, name, fanout_list, pinout_list):
|
||||
"""init function"""
|
||||
super().__init__(name)
|
||||
debug.info(1, "creating delay chain {0}".format(str(fanout_list)))
|
||||
self.add_comment("fanouts: {0}".format(str(fanout_list)))
|
||||
|
||||
# Two fanouts are needed so that we can route the vdd/gnd connections
|
||||
for f in fanout_list:
|
||||
debug.check(f>=2, "Must have >=2 fanouts for each stage.")
|
||||
|
||||
# number of inverters including any fanout loads.
|
||||
self.fanout_list = fanout_list
|
||||
self.rows = len(self.fanout_list)
|
||||
|
||||
# defaults to signle output at end of delay chain
|
||||
if len(self.pinout_list) == 0:
|
||||
self.pinout_list = [self.rows] # TODO: check for off-by-one here
|
||||
else:
|
||||
self.pinout_list = pinout_list
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_inverters()
|
||||
|
||||
def create_layout(self):
|
||||
# Each stage is a a row
|
||||
self.height = self.rows * self.inv.height
|
||||
# The width is determined by the largest fanout plus the driver
|
||||
self.width = (max(self.fanout_list) + 1) * self.inv.width
|
||||
|
||||
self.place_inverters()
|
||||
self.route_inverters()
|
||||
self.route_supplies()
|
||||
self.add_layout_pins()
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_pins(self):
|
||||
""" Add the pins of the delay chain"""
|
||||
self.add_pin("in", "INPUT")
|
||||
for pin_stage in self.pinout_list:
|
||||
self.add_pin("out{}".format(pin_stage), "OUTPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
self.dff = factory.create(module_type="dff_buf")
|
||||
dff_height = self.dff.height
|
||||
|
||||
self.inv = factory.create(module_type="pinv",
|
||||
height=dff_height)
|
||||
|
||||
def create_inverters(self):
|
||||
""" Create the inverters and connect them based on the stage list """
|
||||
self.driver_inst_list = []
|
||||
self.load_inst_map = {}
|
||||
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
|
||||
# Add the inverter
|
||||
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
|
||||
mod=self.inv)
|
||||
# keep track of the inverter instances so we can use them to get the pins
|
||||
self.driver_inst_list.append(cur_driver)
|
||||
|
||||
# Hook up the driver
|
||||
stageout_name = "out{}".format(stage_num + 1) # TODO: check for off-by-one here
|
||||
if stage_num == 0:
|
||||
stagein_name = "in"
|
||||
else:
|
||||
stagein_name = "out{}".format(stage_num)
|
||||
self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"])
|
||||
|
||||
# Now add the dummy loads to the right
|
||||
self.load_inst_map[cur_driver]=[]
|
||||
for i in range(fanout_size):
|
||||
cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num, i),
|
||||
mod=self.inv)
|
||||
# Fanout stage is always driven by driver and output is disconnected
|
||||
disconnect_name = "n_{0}_{1}".format(stage_num, i)
|
||||
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
|
||||
|
||||
# Keep track of all the loads to connect their inputs as a load
|
||||
self.load_inst_map[cur_driver].append(cur_load)
|
||||
|
||||
def place_inverters(self):
|
||||
""" Place the inverters and connect them based on the stage list """
|
||||
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
|
||||
if stage_num % 2:
|
||||
inv_mirror = "MX"
|
||||
inv_offset = vector(0, (stage_num + 1) * self.inv.height)
|
||||
else:
|
||||
inv_mirror = "R0"
|
||||
inv_offset = vector(0, stage_num * self.inv.height)
|
||||
|
||||
# Add the inverter
|
||||
cur_driver=self.driver_inst_list[stage_num]
|
||||
cur_driver.place(offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
|
||||
# Now add the dummy loads to the right
|
||||
load_list = self.load_inst_map[cur_driver]
|
||||
for i in range(fanout_size):
|
||||
inv_offset += vector(self.inv.width, 0)
|
||||
load_list[i].place(offset=inv_offset,
|
||||
mirror=inv_mirror)
|
||||
|
||||
def add_route(self, pin1, pin2):
|
||||
""" This guarantees that we route from the top to bottom row correctly. """
|
||||
pin1_pos = pin1.center()
|
||||
pin2_pos = pin2.center()
|
||||
if pin1_pos.y == pin2_pos.y:
|
||||
self.add_path("m2", [pin1_pos, pin2_pos])
|
||||
else:
|
||||
mid_point = vector(pin2_pos.x, 0.5 * (pin1_pos.y + pin2_pos.y))
|
||||
# Written this way to guarantee it goes right first if we are switching rows
|
||||
self.add_path("m2", [pin1_pos, vector(pin1_pos.x, mid_point.y), mid_point, vector(mid_point.x, pin2_pos.y), pin2_pos])
|
||||
|
||||
def route_inverters(self):
|
||||
""" Add metal routing for each of the fanout stages """
|
||||
|
||||
for i in range(len(self.driver_inst_list)):
|
||||
inv = self.driver_inst_list[i]
|
||||
for load in self.load_inst_map[inv]:
|
||||
# Drop a via on each A pin
|
||||
a_pin = load.get_pin("A")
|
||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||
to_layer="m3",
|
||||
offset=a_pin.center())
|
||||
|
||||
# Route an M3 horizontal wire to the furthest
|
||||
z_pin = inv.get_pin("Z")
|
||||
a_pin = inv.get_pin("A")
|
||||
a_max = self.load_inst_map[inv][-1].get_pin("A")
|
||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||
to_layer="m2",
|
||||
offset=a_pin.center())
|
||||
self.add_via_stack_center(from_layer=z_pin.layer,
|
||||
to_layer="m3",
|
||||
offset=z_pin.center())
|
||||
self.add_path("m3", [z_pin.center(), a_max.center()])
|
||||
|
||||
# Route Z to the A of the next stage
|
||||
if i + 1 < len(self.driver_inst_list):
|
||||
z_pin = inv.get_pin("Z")
|
||||
next_inv = self.driver_inst_list[i + 1]
|
||||
next_a_pin = next_inv.get_pin("A")
|
||||
y_mid = (z_pin.cy() + next_a_pin.cy()) / 2
|
||||
mid1_point = vector(z_pin.cx(), y_mid)
|
||||
mid2_point = vector(next_a_pin.cx(), y_mid)
|
||||
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
|
||||
|
||||
def route_supplies(self):
|
||||
# Add power and ground to all the cells except:
|
||||
# the fanout driver, the right-most load
|
||||
# The routing to connect the loads is over the first and last cells
|
||||
# We have an even number of drivers and must only do every other
|
||||
# supply rail
|
||||
|
||||
for inst in self.driver_inst_list:
|
||||
load_list = self.load_inst_map[inst]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
pin = load_list[0].get_pin(pin_name)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
|
||||
pin = load_list[-2].get_pin(pin_name)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
# input is A pin of first inverter
|
||||
# It gets routed to the left a bit to prevent pin access errors
|
||||
# due to the output pin when going up to M3
|
||||
a_pin = self.driver_inst_list[0].get_pin("A")
|
||||
mid_loc = vector(a_pin.cx() - self.m3_pitch, a_pin.cy())
|
||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||
to_layer="m2",
|
||||
offset=mid_loc)
|
||||
self.add_path(a_pin.layer, [a_pin.center(), mid_loc])
|
||||
|
||||
self.add_layout_pin_rect_center(text="in",
|
||||
layer="m2",
|
||||
offset=mid_loc)
|
||||
|
||||
# output is A pin of last load/fanout inverter
|
||||
last_driver_inst = self.driver_inst_list[-1]
|
||||
a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A")
|
||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||
to_layer="m1",
|
||||
offset=a_pin.center())
|
||||
self.add_layout_pin_rect_center(text="out",
|
||||
layer="m1",
|
||||
offset=a_pin.center())
|
||||
|
|
@ -39,14 +39,14 @@ class multi_delay_chain(design.design):
|
|||
if not pinout_list:
|
||||
self.pinout_list = [self.rows] # TODO: check for off-by-one here
|
||||
else:
|
||||
# Set() to sort in ascending order and remove duplicates
|
||||
self.pinout_list = list(set(pinout_list))
|
||||
self.pinout_list = pinout_list
|
||||
|
||||
#would like to sort and check pinout list for valid format but don't have time now
|
||||
# Check pinout bounds
|
||||
debug.check(self.pinout_list[-1] <= self.rows,
|
||||
"Ouput pin cannot exceed delay chain length.")
|
||||
debug.check(self.pinout_list[0] > 0,
|
||||
"Delay chain output pin numbers must be positive")
|
||||
# debug.check(self.pinout_list[-1] <= self.rows,
|
||||
# "Ouput pin cannot exceed delay chain length.")
|
||||
# debug.check(self.pinout_list[0] > 0,
|
||||
# "Delay chain output pin numbers must be positive")
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
Loading…
Reference in New Issue