Remove EOL whitespace globally

This commit is contained in:
mrg
2020-11-03 06:29:17 -08:00
parent aec5865d71
commit da721a677d
295 changed files with 2808 additions and 2811 deletions
+73 -73
View File
@@ -31,16 +31,16 @@ class bank(design.design):
self.num_wmasks = int(ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
if not self.num_spare_cols:
self.num_spare_cols = 0
if name == "":
name = "bank_{0}_{1}".format(self.word_size, self.num_words)
super().__init__(name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,
self.num_words))
# The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create
# the internal gated signals.
@@ -62,12 +62,12 @@ class bank(design.design):
self.add_modules()
self.add_pins() # Must create the replica bitcell array first
self.create_instances()
def create_layout(self):
self.place_instances()
self.setup_routing_constraints()
self.route_layout()
# Can remove the following, but it helps for debug!
# self.add_lvs_correspondence_points()
@@ -110,13 +110,13 @@ class bank(design.design):
self.add_pin("wl_en{0}".format(port), "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def route_layout(self):
""" Create routing amoung the modules """
self.route_central_bus()
self.route_unused_wordlines()
for port in self.all_ports:
self.route_bitlines(port)
self.route_rbl(port)
@@ -125,7 +125,7 @@ class bank(design.design):
self.route_control_lines(port)
if self.num_banks > 1:
self.route_bank_select(port)
self.route_supplies()
def route_rbl(self, port):
@@ -149,7 +149,7 @@ class bank(design.design):
layer="m3",
start=left_right_offset,
end=pin_offset)
def route_bitlines(self, port):
""" Route the bitlines depending on the port type rw, w, or r. """
@@ -158,7 +158,7 @@ class bank(design.design):
if port in self.read_ports:
self.route_port_data_out(port)
self.route_port_data_to_bitcell_array(port)
def create_instances(self):
""" Create the instances of the netlist. """
@@ -185,7 +185,7 @@ class bank(design.design):
# The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
self.bitcell_array_top = self.bitcell_array.height
self.bitcell_array_right = self.bitcell_array.width
# These are the offsets of the main array (excluding dummy and replica rows/cols)
self.main_bitcell_array_top = self.bitcell_array.get_main_array_top()
# Just past the dummy column
@@ -213,7 +213,7 @@ class bank(design.design):
"""
port = 0
# UPPER RIGHT QUADRANT
# Bitcell array is placed at (0,0)
self.bitcell_array_offset = vector(0, 0)
@@ -258,14 +258,14 @@ class bank(design.design):
"""
port=1
# LOWER LEFT QUADRANT
# Bitcell array is placed at (0,0)
# UPPER LEFT QUADRANT
# Above the bitcell array
self.port_data_offsets[port] = vector(0, self.bitcell_array_top)
# LOWER RIGHT QUADRANT
# To the right of the bitcell array
x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap
@@ -294,12 +294,12 @@ class bank(design.design):
else:
y_offset = self.port_address_offsets[port].y
self.bank_select_offsets[port] = vector(x_offset, y_offset)
def place_instances(self):
""" Place the instances. """
self.compute_instance_offsets()
self.place_bitcell_array(self.bitcell_array_offset)
self.place_port_data(self.port_data_offsets)
@@ -308,7 +308,7 @@ class bank(design.design):
self.place_column_decoder(self.column_decoder_offsets)
self.place_bank_select(self.bank_select_offsets)
def compute_sizes(self):
""" Computes the required sizes to create the bank """
@@ -351,7 +351,7 @@ class bank(design.design):
self.control_signals.append(["gated_" + str for str in self.input_control_signals[port]])
else:
self.control_signals.append(self.input_control_signals[port])
# The central bus is the column address (one hot) and row address (binary)
if self.col_addr_size>0:
@@ -379,7 +379,7 @@ class bank(design.design):
local_array_size = OPTS.local_array_size
except AttributeError:
local_array_size = 0
if local_array_size > 0:
# Find the even multiple that satisfies the fanout with equal sized local arrays
total_cols = self.num_cols + self.num_spare_cols
@@ -406,11 +406,11 @@ class bank(design.design):
bit_offsets=self.bit_offsets)
self.port_data.append(temp_pre)
self.add_mod(self.port_data[port])
if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select)
def create_bitcell_array(self):
""" Creating Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
@@ -426,12 +426,12 @@ class bank(design.design):
temp.extend(self.bitcell_array.get_wordline_names())
if len(self.all_ports) > 1:
temp.append("rbl_wl1")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_bitcell_array(self, offset):
""" Placing Bitcell Array """
self.bitcell_array_inst.place(offset)
@@ -470,7 +470,7 @@ class bank(design.design):
def place_port_data(self, offsets):
""" Placing Port Data """
for port in self.all_ports:
# Top one is unflipped, bottom is flipped along X direction
if port % 2 == 1:
@@ -481,7 +481,7 @@ class bank(design.design):
def create_port_address(self):
""" Create the hierarchical row decoder """
self.port_address_inst = [None] * len(self.all_ports)
for port in self.all_ports:
self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
@@ -496,32 +496,32 @@ class bank(design.design):
temp.append("rbl_wl{}".format(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_port_address(self, offsets):
""" Place the hierarchical row decoder """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
# The address and control bus will be in between decoder and the main memory array
# This bus will route address bits to the decoder input and column mux inputs.
# The wires are actually routed after we placed the stuff on both sides.
# The predecoder is below the x-axis and the main decoder is above the x-axis
# The address flop and decoder are aligned in the x coord.
for port in self.all_ports:
if port % 2:
mirror = "MY"
else:
mirror = "R0"
self.port_address_inst[port].place(offset=offsets[port], mirror=mirror)
def create_column_decoder(self):
"""
Create a 2:4 or 3:8 column address decoder.
"""
self.dff =factory.create(module_type="dff")
if self.col_addr_size == 0:
return
elif self.col_addr_size == 1:
@@ -541,7 +541,7 @@ class bank(design.design):
# No error checking before?
debug.error("Invalid column decoder?", -1)
self.add_mod(self.column_decoder)
self.column_decoder_inst = [None] * len(self.all_ports)
for port in self.all_ports:
self.column_decoder_inst[port] = self.add_inst(name="col_address_decoder{}".format(port),
@@ -554,14 +554,14 @@ class bank(design.design):
temp.append("sel{0}_{1}".format(port, bit))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_column_decoder(self, offsets):
"""
Place a 2:4 or 3:8 column address decoder.
"""
if self.col_addr_size == 0:
return
debug.check(len(offsets)>=len(self.all_ports),
"Insufficient offsets to place column decoder.")
@@ -571,7 +571,7 @@ class bank(design.design):
else:
mirror = "R0"
self.column_decoder_inst[port].place(offset=offsets[port], mirror=mirror)
def create_bank_select(self):
""" Create the bank select logic. """
@@ -582,7 +582,7 @@ class bank(design.design):
for port in self.all_ports:
self.bank_select_inst[port] = self.add_inst(name="bank_select{}".format(port),
mod=self.bank_select)
temp = []
temp.extend(self.input_control_signals[port])
temp.append("bank_sel{}".format(port))
@@ -601,7 +601,7 @@ class bank(design.design):
for port in self.all_ports:
self.bank_select_inst[port].place(offsets[port])
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# Copy only the power pins already on the power layer
@@ -624,7 +624,7 @@ class bank(design.design):
def route_bank_select(self, port):
""" Route the bank select logic. """
if self.port_id[port] == "rw":
bank_sel_signals = ["clk_buf", "w_en", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_s_en", "gated_p_en_bar"]
@@ -634,11 +634,11 @@ class bank(design.design):
else:
bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"]
copy_control_signals = self.input_control_signals[port] + ["bank_sel{}".format(port)]
for signal in range(len(copy_control_signals)):
self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal])
for signal in range(len(gated_bank_sel_signals)):
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc()
@@ -651,7 +651,7 @@ class bank(design.design):
offset=out_pos)
self.add_via_center(layers=self.m2_stack,
offset=out_pos)
def setup_routing_constraints(self):
"""
After the modules are instantiated, find the dimensions for the
@@ -660,7 +660,7 @@ class bank(design.design):
self.max_y_offset = max([x.uy() for x in self.insts]) + 3 * self.m1_width
self.min_y_offset = min([x.by() for x in self.insts])
self.max_x_offset = max([x.rx() for x in self.insts]) + 3 * self.m1_width
self.min_x_offset = min([x.lx() for x in self.insts])
@@ -668,7 +668,7 @@ class bank(design.design):
ur = vector(self.max_x_offset, self.max_y_offset)
ll = vector(self.min_x_offset, self.min_y_offset)
self.core_bbox = [ll, ur]
self.height = ur.y - ll.y
self.width = ur.x - ll.x
@@ -692,7 +692,7 @@ class bank(design.design):
vertical=True,
make_pins=(self.num_banks==1),
pitch=self.m3_pitch)
# Port 1
if len(self.all_ports)==2:
# The other control bus is routed up to two pitches above the bitcell array
@@ -731,12 +731,12 @@ class bank(design.design):
inst1_br_name=inst1_br_name,
inst2_bl_name=inst2_bl_name,
inst2_br_name=inst2_br_name)
# Connect the replica bitlines
for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]):
self.connect_bitline(inst1, inst2, array_name, data_name)
def route_port_data_out(self, port):
""" Add pins for the port data out """
@@ -747,7 +747,7 @@ class bank(design.design):
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width())
def route_port_address_in(self, port):
""" Routes the row decoder inputs and supplies """
@@ -771,19 +771,19 @@ class bank(design.design):
wmask_name = "bank_wmask_{}".format(row)
bank_wmask_name = "bank_wmask{0}_{1}".format(port, row)
self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name)
for col in range(self.num_spare_cols):
sparecol_name = "bank_spare_wen{}".format(col)
bank_sparecol_name = "bank_spare_wen{0}_{1}".format(port, col)
self.copy_layout_pin(self.port_data_inst[port], sparecol_name, bank_sparecol_name)
def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
"""
Route the bl and br of two modules using the channel router.
"""
# determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by():
@@ -801,14 +801,14 @@ class bank(design.design):
top_names = [top_inst.get_pin(top_bl_name.format(bit)), top_inst.get_pin(top_br_name.format(bit))]
route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
def connect_bitline(self, inst1, inst2, inst1_name, inst2_name):
"""
Connect two pins of two modules.
This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed).
"""
# determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by():
@@ -821,17 +821,17 @@ class bank(design.design):
bottom_pin = bottom_inst.get_pin(bottom_name)
top_pin = top_inst.get_pin(top_name)
debug.check(bottom_pin.layer == top_pin.layer, "Pin layers do not match.")
bottom_loc = bottom_pin.uc()
top_loc = top_pin.bc()
yoffset = 0.5 * (top_loc.y + bottom_loc.y)
self.add_path(top_pin.layer,
[bottom_loc,
vector(bottom_loc.x, yoffset),
vector(top_loc.x, yoffset),
top_loc])
def connect_bitlines(self, inst1, inst2,
inst1_bl_name, inst1_br_name,
inst2_bl_name, inst2_br_name):
@@ -847,12 +847,12 @@ class bank(design.design):
""" Connect Wordline driver to bitcell array wordline """
self.route_port_address_in(port)
if port % 2:
self.route_port_address_out(port, "right")
else:
self.route_port_address_out(port, "left")
def route_port_address_out(self, port, side="left"):
""" Connecting Wordline driver output to Bitcell WL connection """
@@ -866,7 +866,7 @@ class bank(design.design):
else:
driver_wl_pos = driver_wl_pin.lc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name)
if side == "left":
bitcell_wl_pos = bitcell_wl_pin.lc()
port_address_pos = self.port_address_inst[port].rx()
@@ -875,7 +875,7 @@ class bank(design.design):
bitcell_wl_pos = bitcell_wl_pin.rc()
port_address_pos = self.port_address_inst[port].lx()
bitcell_array_pos = self.bitcell_array_inst.rx()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * port_address_pos + 0.5 * bitcell_array_pos, 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
if driver_wl_pin.layer != bitcell_wl_pin.layer:
@@ -886,7 +886,7 @@ class bank(design.design):
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
else:
self.add_path(bitcell_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
@@ -906,7 +906,7 @@ class bank(design.design):
to_layer=bitcell_wl_pin.layer,
offset=mid2)
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
def route_column_address_lines(self, port):
""" Connecting the select lines of column mux to the address bus """
if not self.col_addr_size>0:
@@ -914,15 +914,15 @@ class bank(design.design):
stack = getattr(self, layer_props.bank.stack)
pitch = getattr(self, layer_props.bank.pitch)
if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# The Address LSB
self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port))
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
@@ -942,7 +942,7 @@ class bank(design.design):
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names]
route_map = list(zip(decode_pins, column_mux_pins))
self.create_vertical_channel_route(route_map,
offset,
@@ -964,7 +964,7 @@ class bank(design.design):
# self.add_label(text=wl_name,
# layer="m1",
# offset=wl_pin.center())
# # Add the bitline names
# for i in range(self.num_cols):
# bl_name = "bl_{}".format(i)
@@ -1025,10 +1025,10 @@ class bank(design.design):
# Add a path to connect to the array
self.add_path(pin_layer, [left_loc, left_pin_loc])
self.add_path(pin_layer, [right_loc, right_pin_loc])
def route_control_lines(self, port):
""" Route the control lines of the entire bank """
# Make a list of tuples that we will connect.
# From control signal to the module pin
# Connection from the central bus to the main control block crosses
@@ -1040,7 +1040,7 @@ class bank(design.design):
if port in self.write_ports:
connection.append((self.prefix + "w_en{}".format(port),
self.port_data_inst[port].get_pin("w_en")))
if port in self.read_ports:
connection.append((self.prefix + "s_en{}".format(port),
self.port_data_inst[port].get_pin("s_en")))
@@ -1057,7 +1057,7 @@ class bank(design.design):
self.add_via_stack_center(from_layer=pin.layer,
to_layer="m2",
offset=control_pos)
# clk to wordline_driver
control_signal = self.prefix + "wl_en{}".format(port)
if port % 2:
@@ -1081,7 +1081,7 @@ class bank(design.design):
for port in self.read_ports:
if self.port_data[port]:
self.port_data[port].graph_exclude_precharge()
def get_cell_name(self, inst_name, row, col):
"""
Gets the spice name of the target bitcell.
@@ -1097,8 +1097,8 @@ class bank(design.design):
self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
def clear_exclude_bits(self):
"""
"""
Clears the bit exclusions
"""
self.bitcell_array.clear_exclude_bits()
+24 -24
View File
@@ -27,7 +27,7 @@ class bank_select(design.design):
super().__init__(name)
self.port = port
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -36,7 +36,7 @@ class bank_select(design.design):
self.add_pins()
self.add_modules()
self.create_instances()
def create_layout(self):
self.calculate_module_offsets()
self.place_instances()
@@ -44,12 +44,12 @@ class bank_select(design.design):
self.height = max([x.uy() for x in self.inv_inst]) + self.m1_width
self.width = max([x.rx() for x in self.inv_inst])
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
# Number of control lines in the bus
if self.port == "rw":
self.num_control_lines = 4
@@ -86,7 +86,7 @@ class bank_select(design.design):
self.nor2 = factory.create(module_type="pnor2", height=height)
self.add_mod(self.nor2)
self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x_nor)
@@ -94,15 +94,15 @@ class bank_select(design.design):
self.add_mod(self.nand2)
def calculate_module_offsets(self):
self.xoffset_nand = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
self.xoffset_nor = self.inv4x.width + 3 * self.m2_pitch + drc("pwell_to_nwell")
self.xoffset_bank_sel_inv = 0
self.xoffset_inputs = 0
self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height
def create_instances(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv_sel)
self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"])
@@ -119,7 +119,7 @@ class bank_select(design.design):
# These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low)
if input_name in ("clk_buf"):
self.logic_inst.append(self.add_inst(name=name_nor,
mod=self.nor2))
self.connect_inst([input_name,
@@ -127,7 +127,7 @@ class bank_select(design.design):
gated_name + "_temp_bar",
"vdd",
"gnd"])
# They all get inverters on the output
self.inv_inst.append(self.add_inst(name=name_inv,
mod=self.inv4x_nor))
@@ -135,7 +135,7 @@ class bank_select(design.design):
gated_name,
"vdd",
"gnd"])
# the rest are AND (nand2+inv) gates
else:
self.logic_inst.append(self.add_inst(name=name_nand,
@@ -155,7 +155,7 @@ class bank_select(design.design):
"gnd"])
def place_instances(self):
# bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
@@ -166,27 +166,27 @@ class bank_select(design.design):
logic_inst = self.logic_inst[i]
inv_inst = self.inv_inst[i]
input_name = self.input_control_signals[i]
if i == 0:
y_offset = 0
else:
y_offset = self.inv4x_nor.height + self.inv4x.height * (i - 1)
if i % 2:
y_offset += self.inv4x.height
mirror = "MX"
else:
mirror = ""
# These require OR (nor2+inv) gates since they are active low.
# (writes occur on clk low)
if input_name in ("clk_buf"):
logic_inst.place(offset=[self.xoffset_nor, y_offset],
mirror=mirror)
# the rest are AND (nand2+inv) gates
else:
logic_inst.place(offset=[self.xoffset_nand, y_offset],
@@ -197,7 +197,7 @@ class bank_select(design.design):
mirror=mirror)
def route_instances(self):
# bank_sel is vertical wire
bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")
xoffset_bank_sel = bank_sel_inv_pin.lx()
@@ -227,19 +227,19 @@ class bank_select(design.design):
height=self.inv4x.height)
self.add_via_center(layers=self.m1_stack,
offset=bank_sel_bar_pin.rc())
for i in range(self.num_control_lines):
logic_inst = self.logic_inst[i]
inv_inst = self.inv_inst[i]
input_name = self.input_control_signals[i]
gated_name = self.control_signals[i]
if input_name in ("clk_buf"):
xoffset_bank_signal = xoffset_bank_sel_bar
else:
xoffset_bank_signal = xoffset_bank_sel
# Connect the logic output to inverter input
out_pin = logic_inst.get_pin("Z")
out_pos = out_pin.center()
@@ -248,7 +248,7 @@ class bank_select(design.design):
mid1_pos = vector(0.5 * (out_pos.x + in_pos.x), out_pos.y)
mid2_pos = vector(0.5 * (out_pos.x + in_pos.x), in_pos.y)
self.add_path("m1", [out_pos, mid1_pos, mid2_pos, in_pos])
# Connect the logic B input to bank_sel / bank_sel_bar
logic_pin = logic_inst.get_pin("B")
logic_pos = logic_pin.center()
@@ -304,7 +304,7 @@ class bank_select(design.design):
self.add_layout_pin_rect_center(text=n,
layer="m3",
offset=pin_pos)
# Add vdd/gnd supply rails
gnd_pin = self.inv_inst[num].get_pin("gnd")
left_gnd_pos = vector(0, gnd_pin.cy())
@@ -312,7 +312,7 @@ class bank_select(design.design):
layer="m1",
start=left_gnd_pos,
end=gnd_pin.rc())
vdd_pin = self.inv_inst[num].get_pin("vdd")
left_vdd_pos = vector(0, vdd_pin.cy())
self.add_layout_pin_segment_center(text="vdd",
+2 -2
View File
@@ -25,11 +25,11 @@ class bitcell_array(bitcell_base_array):
# This will create a default set of bitline/wordline names
self.create_all_bitline_names()
self.create_all_wordline_names()
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
+8 -8
View File
@@ -47,11 +47,11 @@ class bitcell_base_array(design.design):
"br_{0}_{1}".format(port, col)])
# Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
def create_all_wordline_names(self, row_size=None):
if row_size == None:
row_size = self.row_size
for row in range(row_size):
for port in self.all_ports:
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
@@ -69,7 +69,7 @@ class bitcell_base_array(design.design):
def get_bitcell_pins(self, row, col):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
indexed by column and row, for instance use in bitcell_array
"""
bitcell_pins = []
for port in self.all_ports:
@@ -81,7 +81,7 @@ class bitcell_base_array(design.design):
return bitcell_pins
def get_rbl_wordline_names(self, port=None):
"""
"""
Return the WL for the given RBL port.
"""
if port == None:
@@ -102,7 +102,7 @@ class bitcell_base_array(design.design):
return self.all_bitline_names
else:
return self.bitline_names[port]
def get_all_bitline_names(self, port=None):
""" Return ALL the bitline names (including rbl) """
temp = []
@@ -121,7 +121,7 @@ class bitcell_base_array(design.design):
return self.all_wordline_names
else:
return self.wordline_names[port]
def get_all_wordline_names(self, port=None):
""" Return all the wordline names """
temp = []
@@ -133,7 +133,7 @@ class bitcell_base_array(design.design):
if len(self.all_ports) > 1:
temp.extend(self.get_rbl_wordline_names(1))
return temp
def add_layout_pins(self):
""" Add the layout pins """
bitline_names = self.cell.get_all_bitline_names()
@@ -161,7 +161,7 @@ class bitcell_base_array(design.design):
offset=wl_pin.ll().scale(0, 1),
width=self.width,
height=wl_pin.height())
# Copy a vdd/gnd layout pin from every cell
for row in range(self.row_size):
for col in range(self.column_size):
+1 -1
View File
@@ -34,7 +34,7 @@ class col_cap_array(bitcell_base_array):
if not end_caps_enabled:
self.create_all_wordline_names()
self.create_all_bitline_names()
self.add_modules()
self.add_pins()
self.create_instances()
+3 -3
View File
@@ -46,7 +46,7 @@ class column_mux_array(design.design):
# self.sel_layer = "m1"
# self.sel_pitch = self.m2_pitch
# self.bitline_layer = "m2"
if preferred_directions[self.sel_layer] == "V":
self.via_directions = ("H", "H")
else:
@@ -125,7 +125,7 @@ class column_mux_array(design.design):
# Default to single spaced columns
if not self.offsets:
self.offsets = [n * self.mux.width for n in range(self.columns)]
# For every column, add a pass gate
for col_num, xoffset in enumerate(self.offsets[0:self.columns]):
if cell_props.bitcell.mirror.y and (col_num + self.column_offset) % 2:
@@ -209,7 +209,7 @@ class column_mux_array(design.design):
br_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("br_out").bc()
bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.sel_pitch)
br_out_offset_end = br_offset_end - vector(0, (self.words_per_row + 2) * self.sel_pitch)
self.add_path(self.sel_layer, [bl_out_offset_begin, bl_out_offset_end])
self.add_path(self.sel_layer, [br_out_offset_begin, br_out_offset_end])
+68 -68
View File
@@ -28,7 +28,7 @@ class control_logic(design.design):
self.add_comment("num_rows: {0}".format(num_rows))
self.add_comment("words_per_row: {0}".format(words_per_row))
self.add_comment("word_size {0}".format(word_size))
self.sram=sram
self.num_rows = num_rows
self.words_per_row = words_per_row
@@ -42,21 +42,21 @@ class control_logic(design.design):
self.num_cols = word_size * words_per_row + self.num_spare_cols
self.num_words = num_rows * words_per_row
self.enable_delay_chain_resizing = False
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
# Determines how much larger the sen delay should be. Accounts for possible error in model.
# FIXME: This should be made a parameter
self.wl_timing_tolerance = 1
self.wl_stage_efforts = None
self.sen_stage_efforts = None
if self.port_type == "rw":
self.num_control_signals = 2
else:
self.num_control_signals = 1
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -66,7 +66,7 @@ class control_logic(design.design):
self.add_pins()
self.add_modules()
self.create_instances()
def create_layout(self):
""" Create layout and route between modules """
self.place_instances()
@@ -84,16 +84,16 @@ class control_logic(design.design):
def add_modules(self):
""" Add all the required modules """
self.dff = factory.create(module_type="dff_buf")
dff_height = self.dff.height
self.ctrl_dff_array = factory.create(module_type="dff_buf_array",
rows=self.num_control_signals,
columns=1)
self.add_mod(self.ctrl_dff_array)
self.and2 = factory.create(module_type="pand2",
size=12,
height=dff_height)
@@ -103,7 +103,7 @@ class control_logic(design.design):
size=self.num_cols,
height=dff_height)
self.add_mod(self.rbl_driver)
# clk_buf drives a flop for every address
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
# plus data flops and control flops
@@ -114,13 +114,13 @@ class control_logic(design.design):
self.clk_buf_driver = factory.create(module_type="pdriver",
fanout=clock_fanout,
height=dff_height)
self.add_mod(self.clk_buf_driver)
# We will use the maximum since this same value is used to size the wl_en
# and the p_en_bar drivers
# max_fanout = max(self.num_rows, self.num_cols)
# wl_en drives every row in the bank
self.wl_en_driver = factory.create(module_type="pdriver",
fanout=self.num_rows,
@@ -144,7 +144,7 @@ class control_logic(design.design):
size=1,
height=dff_height)
self.add_mod(self.inv)
# p_en_bar drives every column in the bitcell array
# but it is sized the same as the wl_en driver with
# prepended 3 inverter stages to guarantee it is slower and odd polarity
@@ -183,14 +183,14 @@ class control_logic(design.design):
# Fanout can be varied as well but is a little more complicated but potentially optimal.
debug.info(1, "Setting delay chain to {} stages with {} fanout to match {} delay".format(delay_stages, delay_fanout, required_delay))
return (delay_stages, delay_fanout)
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
previous_delay_per_stage = previous_fanout + 1 + self.inv_parasitic_delay
previous_delay_chain_delay = previous_delay_per_stage * previous_stages
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
fanout_rise = fanout_fall = 2 # This can be anything >=2
# The delay chain uses minimum sized inverters. There are (fanout+1)*stages inverters and each
# inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
@@ -201,7 +201,7 @@ class control_logic(design.design):
debug.info(2,
"Required delays from chain: fall={}, rise={}".format(required_delay_fall,
required_delay_rise))
# If the fanout is different between rise/fall by this amount. Stage algorithm is made more pessimistic.
WARNING_FANOUT_DIFF = 5
stages_close = False
@@ -218,7 +218,7 @@ class control_logic(design.design):
stages_close = True
safe_fanout_rise = fanout_rise
safe_fanout_fall = fanout_fall
if stages_fall == stages_rise:
break
elif abs(stages_fall - stages_rise) == 1 and WARNING_FANOUT_DIFF < abs(fanout_fall - fanout_rise):
@@ -232,14 +232,14 @@ class control_logic(design.design):
fanout_fall+=1
else:
fanout_rise+=1
total_stages = max(stages_fall, stages_rise) * 2
debug.info(1, "New Delay chain: stages={}, fanout_rise={}, fanout_fall={}".format(total_stages, fanout_rise, fanout_fall))
# Creates interleaved fanout list of rise/fall delays. Assumes fall is the first stage.
stage_list = [fanout_fall if i % 2==0 else fanout_rise for i in range(total_stages)]
return stage_list
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
from math import ceil
# Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
@@ -249,7 +249,7 @@ class control_logic(design.design):
delay_per_stage = fanout + 1 + self.inv_parasitic_delay
delay_stages = ceil(required_delay / delay_per_stage)
return delay_stages
def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """
@@ -265,7 +265,7 @@ class control_logic(design.design):
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
else:
self.dff_output_list = ["cs_bar", "cs"]
# 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"]
@@ -275,7 +275,7 @@ class control_logic(design.design):
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "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
# Outputs to the bank
if self.port_type == "rw":
self.output_list = ["s_en", "w_en"]
@@ -286,14 +286,14 @@ class control_logic(design.design):
self.output_list.append("p_en_bar")
self.output_list.append("wl_en")
self.output_list.append("clk_buf")
self.supply_list = ["vdd", "gnd"]
def route_rails(self):
""" Add the input signal inverted tracks """
height = self.control_logic_center.y - self.m2_pitch
offset = vector(self.ctrl_dff_array.width, 0)
self.input_bus = self.create_vertical_bus("m2",
offset,
self.internal_bus_list,
@@ -325,7 +325,7 @@ class control_logic(design.design):
# All of the control logic is placed to the right of the DFFs and bus
self.control_x_offset = self.ctrl_dff_array.width + self.internal_bus_width
row = 0
# Add the logic on the right of the bus
self.place_clk_buf_row(row)
@@ -396,7 +396,7 @@ class control_logic(design.design):
# Add to the right of the control rows and routing channel
offset = vector(self.delay_chain.width, y_off)
self.delay_inst.place(offset, mirror="MY")
def route_delay(self):
out_pos = self.delay_inst.get_pin("out").bc()
@@ -408,21 +408,21 @@ class control_logic(design.design):
self.add_wire(self.m1_stack, [out_pos, mid1, in_pos])
self.add_via_center(layers=self.m1_stack,
offset=in_pos)
# Input from RBL goes to the delay line for futher delay
self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
def create_clk_buf_row(self):
""" Create the multistage and gated clock buffer """
self.clk_buf_inst = self.add_inst(name="clkbuf",
mod=self.clk_buf_driver)
self.connect_inst(["clk", "clk_buf", "vdd", "gnd"])
def place_clk_buf_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.clk_buf_inst, x_offset, row)
self.row_end_inst.append(self.clk_buf_inst)
def route_clk_buf(self):
@@ -443,17 +443,17 @@ class control_logic(design.design):
self.clk_bar_inst = self.add_inst(name="inv_clk_bar",
mod=self.inv)
self.connect_inst(["clk_buf", "clk_bar", "vdd", "gnd"])
self.gated_clk_bar_inst = self.add_inst(name="and2_gated_clk_bar",
mod=self.and2)
self.connect_inst(["clk_bar", "cs", "gated_clk_bar", "vdd", "gnd"])
def place_gated_clk_bar_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.clk_bar_inst, x_offset, row)
x_offset = self.place_util(self.gated_clk_bar_inst, x_offset, row)
self.row_end_inst.append(self.gated_clk_bar_inst)
def route_gated_clk_bar(self):
@@ -468,7 +468,7 @@ class control_logic(design.design):
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer=in_pin.layer,
offset=in_pos)
# This is the second gate over, so it needs to be on M3
clkbuf_map = zip(["B"], ["cs"])
@@ -495,9 +495,9 @@ class control_logic(design.design):
x_offset = self.control_x_offset
x_offset = self.place_util(self.gated_clk_buf_inst, x_offset, row)
self.row_end_inst.append(self.gated_clk_buf_inst)
def route_gated_clk_buf(self):
clkbuf_map = zip(["A", "B"], ["clk_buf", "cs"])
self.connect_vertical_bus(clkbuf_map,
@@ -514,7 +514,7 @@ class control_logic(design.design):
self.add_via_stack_center(from_layer=z_pin.layer,
to_layer="m2",
offset=z_pin.center())
def create_wlen_row(self):
# input pre_p_en, output: wl_en
self.wl_en_inst=self.add_inst(name="buf_wl_en",
@@ -531,7 +531,7 @@ class control_logic(design.design):
def route_wlen(self):
wlen_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_pen_row(self):
@@ -544,7 +544,7 @@ class control_logic(design.design):
self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar",
mod=self.p_en_bar_driver)
self.connect_inst(["p_en_bar_unbuf", "p_en_bar", "vdd", "gnd"])
def place_pen_row(self, row):
x_offset = self.control_x_offset
@@ -568,7 +568,7 @@ class control_logic(design.design):
offset=in_pin.center())
self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar")
def create_sen_row(self):
""" Create the sense enable buffer. """
if self.port_type=="rw":
@@ -582,24 +582,24 @@ class control_logic(design.design):
# 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(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
def place_sen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.s_en_gate_inst, x_offset, row)
self.row_end_inst.append(self.s_en_gate_inst)
def route_sen(self):
if self.port_type=="rw":
input_name = "we_bar"
else:
input_name = "cs"
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.input_bus)
self.connect_output(self.s_en_gate_inst, "Z", "s_en")
def create_rbl_delay_row(self):
@@ -612,15 +612,15 @@ class control_logic(design.design):
x_offset = self.control_x_offset
x_offset = self.place_util(self.rbl_bl_delay_inv_inst, x_offset, row)
self.row_end_inst.append(self.rbl_bl_delay_inv_inst)
def route_rbl_delay(self):
# Connect from delay line
# Connect to rail
self.route_output_to_bus_jogged(self.rbl_bl_delay_inv_inst, "rbl_bl_delay_bar")
rbl_map = zip(["A"], ["rbl_bl_delay"])
self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.input_bus)
@@ -638,26 +638,26 @@ class control_logic(design.design):
mod=self.wen_and)
# Only drive the writes in the second half of the clock cycle during a write operation.
self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"])
def place_wen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.w_en_gate_inst, x_offset, row)
self.row_end_inst.append(self.w_en_gate_inst)
def route_wen(self):
if self.port_type == "rw":
input_name = "we"
else:
# No we for write-only reports, so use cs
input_name = "cs"
wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay_bar", "gated_clk_bar"])
self.connect_vertical_bus(wen_map, self.w_en_gate_inst, self.input_bus)
self.connect_output(self.w_en_gate_inst, "Z", "w_en")
def create_dffs(self):
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
mod=self.ctrl_dff_array)
@@ -669,7 +669,7 @@ class control_logic(design.design):
def place_dffs(self):
self.ctrl_dff_inst.place(vector(0, 0))
def route_dffs(self):
if self.port_type == "rw":
dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
@@ -678,7 +678,7 @@ class control_logic(design.design):
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])
# Connect the clock rail to the other clock rail
# by routing in the supply rail track to avoid channel conflicts
in_pos = self.ctrl_dff_inst.get_pin("clk").uc()
@@ -691,7 +691,7 @@ class control_logic(design.design):
self.copy_layout_pin(self.ctrl_dff_inst, "din_0", "csb")
if (self.port_type == "rw"):
self.copy_layout_pin(self.ctrl_dff_inst, "din_1", "web")
def get_offset(self, row):
""" Compute the y-offset and mirroring """
y_off = row * self.and2.height
@@ -702,14 +702,14 @@ class control_logic(design.design):
mirror="R0"
return (y_off, mirror)
def connect_output(self, inst, pin_name, out_name):
""" Create an output pin on the right side from the pin of a given instance. """
out_pin = inst.get_pin(pin_name)
out_pos = out_pin.center()
right_pos = out_pos + vector(self.width - out_pin.cx(), 0)
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer="m2",
offset=out_pos)
@@ -722,7 +722,7 @@ class control_logic(design.design):
""" Add vdd and gnd to the instance cells """
supply_layer = self.dff.get_pin("vdd").layer
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
for inst in self.row_end_inst:
pins = inst.get_pins("vdd")
@@ -740,13 +740,13 @@ class control_logic(design.design):
pin_loc = vector(max_row_x_loc, pin.rc().y)
self.add_power_pin("gnd", pin_loc, start_layer=pin.layer)
self.add_path(supply_layer, [row_loc, pin_loc])
self.copy_layout_pin(self.delay_inst, "gnd")
self.copy_layout_pin(self.delay_inst, "vdd")
self.copy_layout_pin(self.ctrl_dff_inst, "gnd")
self.copy_layout_pin(self.ctrl_dff_inst, "vdd")
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
@@ -772,10 +772,10 @@ class control_logic(design.design):
offset=pin.ll(),
height=pin.height(),
width=pin.width())
def graph_exclude_dffs(self):
"""Exclude dffs from graph as they do not represent critical path"""
self.graph_inst_exclude.add(self.ctrl_dff_inst)
if self.port_type=="rw" or self.port_type=="w":
self.graph_inst_exclude.add(self.w_en_gate_inst)
@@ -799,4 +799,4 @@ class control_logic(design.design):
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer="m2",
offset=out_pos)
+6 -6
View File
@@ -126,13 +126,13 @@ class custom_cell(design.design):
if w == self.write_size:
w = 0
windex+=1
elif self.num_spare_cols and not self.write_size:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(0), "vdd", "gnd"])
else:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
@@ -177,13 +177,13 @@ class custom_cell(design.design):
for i in range(self.num_spare_cols):
index = self.word_size + i
xoffset = (self.columns + i) * self.driver_spacing
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
@@ -233,14 +233,14 @@ class custom_cell(design.design):
offset=en_pin.ll(),
width=wmask_en_len - en_gap,
height=en_pin.height())
for i in range(self.num_spare_cols):
inst = self.driver_insts[self.word_size + i]
en_pin = inst.get_pin(inst.mod.en_name)
self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks),
layer="m1",
offset=en_pin.lr() + vector(-drc("minwidth_m1"),0))
elif self.num_spare_cols and not self.write_size:
# shorten enable rail to accomodate those for spare write drivers
inst = self.driver_insts[0]
+12 -12
View File
@@ -24,14 +24,14 @@ class delay_chain(design.design):
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.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -40,7 +40,7 @@ class delay_chain(design.design):
self.add_modules()
self.add_pins()
self.create_inverters()
def create_layout(self):
# Each stage is a a row
self.height = len(self.fanout_list) * self.inv.height
@@ -53,7 +53,7 @@ class delay_chain(design.design):
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")
@@ -86,7 +86,7 @@ class delay_chain(design.design):
else:
stagein_name = "dout_{}".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):
@@ -95,7 +95,7 @@ class delay_chain(design.design):
# 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)
@@ -108,19 +108,19 @@ class delay_chain(design.design):
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()
@@ -131,7 +131,7 @@ class delay_chain(design.design):
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 """
@@ -180,12 +180,12 @@ class delay_chain(design.design):
self.add_power_pin(pin_name,
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
pin = load_list[-2].get_pin(pin_name)
self.add_power_pin(pin_name,
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
def add_layout_pins(self):
# input is A pin of first inverter
+8 -8
View File
@@ -27,7 +27,7 @@ class dff_array(design.design):
super().__init__(name)
debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -36,11 +36,11 @@ class dff_array(design.design):
self.add_modules()
self.add_pins()
self.create_dff_array()
def create_layout(self):
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
self.place_dff_array()
self.add_layout_pins()
self.add_boundary()
@@ -49,7 +49,7 @@ class dff_array(design.design):
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
@@ -86,7 +86,7 @@ class dff_array(design.design):
mirror = "MX"
self.dff_insts[row, col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din_{0}".format(row)
@@ -96,7 +96,7 @@ class dff_array(design.design):
din_name = "din_{0}_{1}".format(row, col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout_{0}".format(row)
@@ -106,7 +106,7 @@ class dff_array(design.design):
dout_name = "dout_{0}_{1}".format(row, col)
return dout_name
def add_layout_pins(self):
for row in range(self.rows):
for col in range(self.columns):
@@ -117,7 +117,7 @@ class dff_array(design.design):
# Continous gnd rail along with label.
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
self.add_power_pin("gnd", gnd_pin.center(), start_layer=gnd_pin.layer)
for row in range(self.rows):
for col in range(self.columns):
din_pin = self.dff_insts[row, col].get_pin("D")
+11 -11
View File
@@ -21,7 +21,7 @@ class dff_buf(design.design):
and qbar. This is to enable driving large fanout loads.
"""
unique_id = 1
def __init__(self, inv1_size=2, inv2_size=4, name=""):
if name=="":
@@ -30,7 +30,7 @@ class dff_buf(design.design):
super().__init__(name)
debug.info(1, "Creating {}".format(self.name))
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
# This causes a DRC in the pinv which assumes min width rails. This ensures the output
# contact does not violate spacing to the rail in the NMOS.
@@ -39,7 +39,7 @@ class dff_buf(design.design):
self.inv1_size=inv1_size
self.inv2_size=inv2_size
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -57,7 +57,7 @@ class dff_buf(design.design):
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
@@ -71,7 +71,7 @@ class dff_buf(design.design):
size=self.inv2_size,
height=self.dff.height)
self.add_mod(self.inv2)
def add_pins(self):
self.add_pin("D", "INPUT")
self.add_pin("Q", "OUTPUT")
@@ -93,7 +93,7 @@ class dff_buf(design.design):
self.inv1_inst=self.add_inst(name="dff_buf_inv1",
mod=self.inv1)
self.connect_inst(["qint", "Qb", "vdd", "gnd"])
self.inv2_inst=self.add_inst(name="dff_buf_inv2",
mod=self.inv2)
self.connect_inst(["Qb", "Q", "vdd", "gnd"])
@@ -119,16 +119,16 @@ class dff_buf(design.design):
except AttributeError:
pass
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing + self.well_extend_active, 0))
# Add INV2 to the right
self.inv2_inst.place(vector(self.inv1_inst.rx(), 0))
def route_wires(self):
if "li" in layer:
self.route_layer = "li"
else:
self.route_layer = "m1"
# Route dff q to inv1 a
q_pin = self.dff_inst.get_pin("Q")
a1_pin = self.inv1_inst.get_pin("A")
@@ -143,7 +143,7 @@ class dff_buf(design.design):
a2_pin = self.inv2_inst.get_pin("A")
self.mid_qb_pos = vector(0.5 * (z1_pin.cx() + a2_pin.cx()), z1_pin.cy())
self.add_zjog(z1_pin.layer, z1_pin.center(), a2_pin.center())
def add_layout_pins(self):
# Continous vdd rail along with label.
@@ -161,7 +161,7 @@ class dff_buf(design.design):
offset=gnd_pin.ll(),
width=self.width,
height=vdd_pin.height())
clk_pin = self.dff_inst.get_pin("clk")
self.add_layout_pin(text="clk",
layer=clk_pin.layer,
+12 -12
View File
@@ -19,7 +19,7 @@ class dff_buf_array(design.design):
Unlike the data flops, these are never spaced out.
"""
unique_id = 1
def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""):
self.rows = rows
self.columns = columns
@@ -31,10 +31,10 @@ class dff_buf_array(design.design):
debug.info(1, "Creating {}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size))
self.inv1_size = inv1_size
self.inv2_size = inv2_size
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -110,7 +110,7 @@ class dff_buf_array(design.design):
pass
dff_pitch = self.dff.width + well_spacing + self.well_extend_active
for row in range(self.rows):
for col in range(self.columns):
# name = "Xdff_r{0}_c{1}".format(row, col)
@@ -122,7 +122,7 @@ class dff_buf_array(design.design):
mirror = "MX"
self.dff_insts[row, col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din_{0}".format(row)
@@ -132,7 +132,7 @@ class dff_buf_array(design.design):
din_name = "din_{0}_{1}".format(row, col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout_{0}".format(row)
@@ -142,7 +142,7 @@ class dff_buf_array(design.design):
dout_name = "dout_{0}_{1}".format(row, col)
return dout_name
def get_dout_bar_name(self, row, col):
if self.columns == 1:
dout_bar_name = "dout_bar_{0}".format(row)
@@ -158,11 +158,11 @@ class dff_buf_array(design.design):
vdd0_pin=self.dff_insts[row, 0].get_pin("vdd")
vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd")
self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height())
gnd0_pin=self.dff_insts[row, 0].get_pin("gnd")
gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd")
self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height())
for row in range(self.rows):
for col in range(self.columns):
# Continous vdd rail along with label.
@@ -172,9 +172,9 @@ class dff_buf_array(design.design):
# Continous gnd rail along with label.
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
self.add_power_pin("gnd", gnd_pin.lc(), start_layer=gnd_pin.layer)
def add_layout_pins(self):
for row in range(self.rows):
for col in range(self.columns):
din_pin = self.dff_insts[row, col].get_pin("D")
@@ -200,7 +200,7 @@ class dff_buf_array(design.design):
offset=dout_bar_pin.ll(),
width=dout_bar_pin.width(),
height=dout_bar_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0, 0].get_pin("clk")
clk_ypos = 2 * self.m3_pitch + self.m3_width
+10 -10
View File
@@ -19,7 +19,7 @@ class dff_inv(design.design):
do not have Qbar, so this will create it.
"""
unique_id = 1
def __init__(self, inv_size=2, name=""):
if name=="":
@@ -30,7 +30,7 @@ class dff_inv(design.design):
self.add_comment("inv: {0}".format(inv_size))
self.inv_size = inv_size
# This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width.
# This causes a DRC in the pinv which assumes min width rails. This ensures the output
# contact does not violate spacing to the rail in the NMOS.
@@ -44,7 +44,7 @@ class dff_inv(design.design):
self.add_pins()
self.add_modules()
self.create_modules()
def create_layout(self):
self.width = self.dff.width + self.inv1.width
self.height = self.dff.height
@@ -52,10 +52,10 @@ class dff_inv(design.design):
self.place_modules()
self.add_wires()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
self.add_pin("D")
self.add_pin("Q")
@@ -67,7 +67,7 @@ class dff_inv(design.design):
def add_modules(self):
self.dff = dff_inv.dff_inv(self.inv_size)
self.add_mod(self.dff)
self.inv1 = factory.create(module_type="pinv",
size=self.inv_size,
height=self.dff.height)
@@ -88,8 +88,8 @@ class dff_inv(design.design):
# Place the INV1 to the right
self.inv1_inst.place(vector(self.dff_inst.rx(),0))
def add_wires(self):
# Route dff q to inv1 a
q_pin = self.dff_inst.get_pin("Q")
@@ -106,7 +106,7 @@ class dff_inv(design.design):
self.add_via_center(layers=self.m1_stack,
offset=a1_pin.center())
def add_layout_pins(self):
# Continous vdd rail along with label.
@@ -124,7 +124,7 @@ class dff_inv(design.design):
offset=gnd_pin.ll(),
width=self.width,
height=vdd_pin.height())
clk_pin = self.dff_inst.get_pin("clk")
self.add_layout_pin(text="clk",
layer=clk_pin.layer,
+21 -21
View File
@@ -19,7 +19,7 @@ class dff_inv_array(design.design):
Unlike the data flops, these are never spaced out.
"""
unique_id = 1
def __init__(self, rows, columns, inv_size=2, name=""):
self.rows = rows
self.columns = columns
@@ -31,9 +31,9 @@ class dff_inv_array(design.design):
debug.info(1, "Creating {}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, columns))
self.add_comment("inv1: {0}".format(inv1_size))
self.inv_size = inv_size
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -42,7 +42,7 @@ class dff_inv_array(design.design):
self.add_pins()
self.add_modules()
self.create_dff_array()
def create_layout(self):
self.width = self.columns * self.dff.width
self.height = self.rows * self.dff.height
@@ -53,14 +53,14 @@ class dff_inv_array(design.design):
self.DRC_LVS()
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self):
for row in range(self.rows):
for row in range(self.rows):
for col in range(self.columns):
self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows):
for row in range(self.rows):
for col in range(self.columns):
self.add_pin(self.get_dout_name(row,col), "OUTPUT")
self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT")
@@ -70,20 +70,20 @@ class dff_inv_array(design.design):
def create_dff_array(self):
self.dff_insts={}
for row in range(self.rows):
for row in range(self.rows):
for col in range(self.columns):
name = "Xdff_r{0}_c{1}".format(row,col)
self.dff_insts[row,col]=self.add_inst(name=name,
mod=self.dff)
self.connect_inst([self.get_din_name(row,col),
self.get_dout_name(row,col),
self.get_dout_bar_name(row,col),
self.get_dout_bar_name(row,col),
"clk",
"vdd",
"gnd"])
def place_dff_array(self):
for row in range(self.rows):
for row in range(self.rows):
for col in range(self.columns):
name = "Xdff_r{0}_c{1}".format(row,col)
if (row % 2 == 0):
@@ -92,9 +92,9 @@ class dff_inv_array(design.design):
else:
base = vector(col*self.dff.width,(row+1)*self.dff.height)
mirror = "MX"
self.dff_insts[row,col].place(offset=base,
self.dff_insts[row,col].place(offset=base,
mirror=mirror)
def get_din_name(self, row, col):
if self.columns == 1:
din_name = "din_{0}".format(row)
@@ -104,7 +104,7 @@ class dff_inv_array(design.design):
din_name = "din_{0}_{1}".format(row,col)
return din_name
def get_dout_name(self, row, col):
if self.columns == 1:
dout_name = "dout_{0}".format(row)
@@ -114,7 +114,7 @@ class dff_inv_array(design.design):
dout_name = "dout_{0}_{1}".format(row,col)
return dout_name
def get_dout_bar_name(self, row, col):
if self.columns == 1:
dout_bar_name = "dout_bar_{0}".format(row)
@@ -124,10 +124,10 @@ class dff_inv_array(design.design):
dout_bar_name = "dout_bar_{0}_{1}".format(row,col)
return dout_bar_name
def add_layout_pins(self):
for row in range(self.rows):
for col in range(self.columns):
for col in range(self.columns):
# Adds power pin on left of row
vdd_pin=self.dff_insts[row,col].get_pin("vdd")
self.add_power_pin("vdd", vdd_pin.lc())
@@ -135,10 +135,10 @@ class dff_inv_array(design.design):
# Adds gnd pin on left of row
gnd_pin=self.dff_insts[row,col].get_pin("gnd")
self.add_power_pin("gnd", gnd_pin.lc())
for row in range(self.rows):
for col in range(self.columns):
for row in range(self.rows):
for col in range(self.columns):
din_pin = self.dff_insts[row,col].get_pin("D")
debug.check(din_pin.layer=="m2","DFF D pin not on metal2")
self.add_layout_pin(text=self.get_din_name(row,col),
@@ -163,7 +163,7 @@ class dff_inv_array(design.design):
width=dout_bar_pin.width(),
height=dout_bar_pin.height())
# Create vertical spines to a single horizontal rail
clk_pin = self.dff_insts[0,0].get_pin("clk")
clk_ypos = 2*self.m3_pitch+self.m3_width
@@ -188,4 +188,4 @@ class dff_inv_array(design.design):
height=self.height)
# Drop a via to the M3 pin
self.add_via_center(layers=self.m2_stack,
offset=vector(clk_pin.cx(),clk_ypos))
offset=vector(clk_pin.cx(),clk_ypos))
+9 -9
View File
@@ -1,6 +1,6 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# Copyright (c) 2016-2019 Regents of the University of California
# All rights reserved.
#
from bitcell_base_array import bitcell_base_array
@@ -20,13 +20,13 @@ class dummy_array(bitcell_base_array):
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
""" Create and connect the netlist """
# This will create a default set of bitline/wordline names
self.create_all_bitline_names()
self.create_all_wordline_names()
self.add_modules()
self.add_pins()
self.create_instances()
@@ -38,16 +38,16 @@ class dummy_array(bitcell_base_array):
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell))
self.cell = factory.create(module_type="bitcell")
self.add_mod(self.dummy_cell)
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
@@ -67,7 +67,7 @@ class dummy_array(bitcell_base_array):
self.add_pin(wl_name, "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_layout_pins(self):
""" Add the layout pins """
@@ -86,7 +86,7 @@ class dummy_array(bitcell_base_array):
offset=br_pin.ll().scale(1, 0),
width=br_pin.width(),
height=self.height)
wl_names = self.cell.get_all_wl_names()
for row in range(self.row_size):
for port in self.all_ports:
@@ -104,7 +104,7 @@ class dummy_array(bitcell_base_array):
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name)
def input_load(self):
# FIXME: This appears to be old code from previous characterization. Needs to be updated.
wl_wire = self.gen_wl_wire()
+27 -27
View File
@@ -27,11 +27,11 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.")
self.rbl = [1, 1 if len(self.all_ports)>1 else 0]
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
@@ -43,11 +43,11 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
self.place()
self.route()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -88,7 +88,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
rows=self.row_size,
cols=cols,
rbl=self.rbl)
self.add_mod(la)
self.local_mods.append(la)
@@ -108,7 +108,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
self.rbl_bitline_names[0].append("rbl_bl_{}_0".format(port))
for port in self.all_ports:
self.rbl_bitline_names[0].append("rbl_br_{}_0".format(port))
for col in range(self.column_size):
for port in self.all_ports:
self.bitline_names[port].append("bl_{0}_{1}".format(port, col))
@@ -120,7 +120,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
self.rbl_bitline_names[1].append("rbl_bl_{}_1".format(port))
for port in self.all_ports:
self.rbl_bitline_names[1].append("rbl_br_{}_1".format(port))
# Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
# Make a flat list too
@@ -130,19 +130,19 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
self.add_pin_list(self.all_bitline_names, "INOUT")
if len(self.all_ports) > 1:
self.add_pin_list(self.rbl_bitline_names[1], "INOUT")
def add_wordline_pins(self):
self.rbl_wordline_names = [[] for x in self.all_ports]
self.wordline_names = [[] for x in self.all_ports]
for bit in self.all_ports:
for port in self.all_ports:
self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit))
self.all_rbl_wordline_names = [x for sl in zip(*self.rbl_wordline_names) for x in sl]
# Regular WLs
for row in range(self.row_size):
for port in self.all_ports:
@@ -163,11 +163,11 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
name = "la_{0}".format(col)
self.local_insts.append(self.add_inst(name=name,
mod=mod))
temp = []
if col == 0:
temp.extend(self.get_rbl_bitline_names(0))
port_inouts = [x for x in mod.get_inouts() if x.startswith("bl") or x.startswith("br")]
for pin_name in port_inouts:
# Offset of the last underscore that defines the bit number
@@ -180,18 +180,18 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
# Strip the bit and add the new one
new_name = "{0}_{1}".format(base_name, col + col_value)
temp.append(new_name)
if len(self.all_ports) > 1 and mod == self.local_mods[-1]:
temp.extend(self.get_rbl_bitline_names(1))
for port in self.all_ports:
port_inputs = [x for x in mod.get_inputs() if "wl_{}".format(port) in x]
temp.extend(port_inputs)
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place(self):
offset = vector(0, 0)
for inst in self.local_insts:
@@ -204,7 +204,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
def route(self):
pass
def add_layout_pins(self):
# Regular bitlines
@@ -230,11 +230,11 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
layer=left_pin.layer,
start=left_pin.lc(),
end=right_pin.rc())
# Replica bitlines
self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0")
if len(self.all_ports) > 1:
self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0")
@@ -269,10 +269,10 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
return offsets
def graph_exclude_bits(self, targ_row, targ_col):
"""
Excludes bits in column from being added to graph except target
"""
Excludes bits in column from being added to graph except target
"""
# This must find which local array includes the specified column
# Find the summation of columns that is large and take the one before
for i, col in enumerate(self.col_offsets):
@@ -303,7 +303,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
# This must find which local array includes the specified column
# Find the summation of columns that is large and take the one before
for i, local_col in enumerate(self.col_offsets):
@@ -321,9 +321,9 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
local_col = col - self.col_offsets[i - 1]
return local_array.get_cell_name(inst_name + '.x' + local_inst.name, row, local_col)
def clear_exclude_bits(self):
"""
"""
Clears the bit exclusions
"""
for mod in self.local_mods:
@@ -331,6 +331,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
def graph_exclude_dffs(self):
"""Exclude dffs from graph as they do not represent critical path"""
self.graph_inst_exclude.add(self.ctrl_dff_inst)
+50 -50
View File
@@ -22,14 +22,14 @@ class hierarchical_decoder(design.design):
super().__init__(name)
self.AND_FORMAT = "DEC_AND_{0}"
self.pre2x4_inst = []
self.pre3x8_inst = []
self.pre4x16_inst = []
b = factory.create(module_type="bitcell")
self.cell_height = b.height
self.num_outputs = num_outputs
self.num_inputs = math.ceil(math.log(self.num_outputs, 2))
(self.no_of_pre2x4, self.no_of_pre3x8, self.no_of_pre4x16)=self.determine_predecodes(self.num_inputs)
@@ -37,7 +37,7 @@ class hierarchical_decoder(design.design):
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_modules()
self.setup_netlist_constants()
@@ -49,33 +49,33 @@ class hierarchical_decoder(design.design):
self.setup_layout_constants()
self.place_pre_decoder()
self.place_row_decoder()
self.height = max(self.predecoder_height, self.row_decoder_height) + self.bus_space
self.route_inputs()
self.route_outputs()
self.route_decoder_bus()
self.route_vdd_gnd()
self.offset_x_coordinates()
self.width = self.and_inst[0].rx() + 0.5 * self.m1_width
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
self.and2 = factory.create(module_type="and2_dec",
height=self.cell_height)
self.add_mod(self.and2)
self.and3 = factory.create(module_type="and3_dec",
height=self.cell_height)
self.add_mod(self.and3)
# TBD
# self.and4 = factory.create(module_type="and4_dec")
# self.add_mod(self.and4)
self.add_decoders()
def add_decoders(self):
@@ -83,7 +83,7 @@ class hierarchical_decoder(design.design):
self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
height=self.cell_height)
self.add_mod(self.pre2_4)
self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
height=self.cell_height)
self.add_mod(self.pre3_8)
@@ -91,11 +91,11 @@ class hierarchical_decoder(design.design):
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
height=self.cell_height)
self.add_mod(self.pre4_16)
def determine_predecodes(self, num_inputs):
"""
"""
Determines the number of 2:4, 3:8 and 4:16 pre-decoders
needed based on the number of inputs
needed based on the number of inputs
"""
if (num_inputs == 2):
return (1, 0, 0)
@@ -151,7 +151,7 @@ class hierarchical_decoder(design.design):
lines.append(index)
index = index + 1
self.predec_groups.append(lines)
def setup_layout_constants(self):
""" Calculate the overall dimensions of the hierarchical decoder """
@@ -190,7 +190,7 @@ class hierarchical_decoder(design.design):
self.input_layer = layer_props.hierarchical_decoder.input_layer
self.output_layer = layer_props.hierarchical_decoder.output_layer
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
# Two extra pitches between modules on left and right
self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + self.bus_pitch
self.row_decoder_height = self.and2.height * self.num_outputs
@@ -215,7 +215,7 @@ class hierarchical_decoder(design.design):
offset=input_offset,
names=input_bus_names,
length=self.predecoder_height)
self.route_input_to_predecodes()
def route_input_to_predecodes(self):
@@ -231,13 +231,13 @@ class hierarchical_decoder(design.design):
decoder_offset = decoder_pin.center()
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_bus(decoder_offset, input_offset)
for pre_num in range(self.no_of_pre3x8):
for i in range(3):
index = pre_num * 3 + i + self.no_of_pre2x4 * 2
input_pos = self.input_bus["addr_{}".format(index)].center()
in_name = "in_{}".format(i)
@@ -245,13 +245,13 @@ class hierarchical_decoder(design.design):
decoder_offset = decoder_pin.center()
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_bus(decoder_offset, input_offset)
for pre_num in range(self.no_of_pre4x16):
for i in range(4):
index = pre_num * 4 + i + self.no_of_pre3x8 * 3 + self.no_of_pre2x4 * 2
input_pos = self.input_bus["addr_{}".format(index)].center()
in_name = "in_{}".format(i)
@@ -259,15 +259,15 @@ class hierarchical_decoder(design.design):
decoder_offset = decoder_pin.center()
input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1)
self.route_input_bus(decoder_offset, input_offset)
def route_input_bus(self, input_offset, output_offset):
"""
Route a vertical M2 coordinate to another
vertical M2 coordinate to the predecode inputs
"""
self.add_via_stack_center(from_layer=self.bus_layer,
to_layer=self.input_layer,
offset=input_offset)
@@ -276,10 +276,10 @@ class hierarchical_decoder(design.design):
offset=output_offset,
directions=self.bus_directions)
self.add_path(self.input_layer, [input_offset, output_offset])
def add_pins(self):
""" Add the module pins """
for i in range(self.num_inputs):
self.add_pin("addr_{0}".format(i), "INPUT")
@@ -290,10 +290,10 @@ class hierarchical_decoder(design.design):
def create_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """
for i in range(self.no_of_pre2x4):
self.create_pre2x4(i)
for i in range(self.no_of_pre3x8):
self.create_pre3x8(i)
@@ -302,7 +302,7 @@ class hierarchical_decoder(design.design):
def create_pre2x4(self, num):
""" Add a 2x4 predecoder to the left of the origin """
if (self.num_inputs == 2):
index_off1 = index_off2 = 0
else:
@@ -355,19 +355,19 @@ class hierarchical_decoder(design.design):
self.pre4x16_inst.append(self.add_inst(name="pre4x16_{0}".format(num),
mod=self.pre4_16))
self.connect_inst(pins)
def place_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """
for i in range(self.no_of_pre2x4):
self.place_pre2x4(i)
for i in range(self.no_of_pre3x8):
self.place_pre3x8(i)
for i in range(self.no_of_pre4x16):
self.place_pre4x16(i)
self.predecode_height = 0
if self.no_of_pre2x4 > 0:
self.predecode_height = self.pre2x4_inst[-1].uy()
@@ -378,10 +378,10 @@ class hierarchical_decoder(design.design):
def place_pre2x4(self, num):
""" Place 2x4 predecoder to the left of the origin """
base= vector(-self.pre2_4.width, num * (self.pre2_4.height + self.predecoder_spacing))
self.pre2x4_inst[num].place(base)
def place_pre3x8(self, num):
""" Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """
height = self.no_of_pre2x4 * (self.pre2_4.height + self.predecoder_spacing) \
@@ -396,7 +396,7 @@ class hierarchical_decoder(design.design):
+ num * (self.pre4_16.height + self.predecoder_spacing)
offset = vector(-self.pre4_16.width, height)
self.pre4x16_inst[num].place(offset)
def create_row_decoder(self):
""" Create the row-decoder by placing AND2/AND3 and Inverters
and add the primary decoder output pins. """
@@ -407,7 +407,7 @@ class hierarchical_decoder(design.design):
""" Add a column of AND gates for final decode """
self.and_inst = []
# Row Decoder AND GATE array for address inputs <5.
if (self.num_inputs == 4 or self.num_inputs == 5):
for i in range(len(self.predec_groups[0])):
@@ -435,7 +435,7 @@ class hierarchical_decoder(design.design):
name = self.AND_FORMAT.format(output)
self.and_inst.append(self.add_inst(name=name,
mod=self.and3))
pins = ["out_{0}".format(i),
"out_{0}".format(j + len(self.predec_groups[0])),
"out_{0}".format(k + len(self.predec_groups[0]) + len(self.predec_groups[1])),
@@ -456,7 +456,7 @@ class hierarchical_decoder(design.design):
Add a column of AND gates for final decode.
This may have more than one decoder per row to match the bitcell height.
"""
# Row Decoder AND GATE array for address inputs <5.
if (self.num_inputs == 4 or self.num_inputs == 5):
self.place_and_array(and_mod=self.and2)
@@ -489,7 +489,7 @@ class hierarchical_decoder(design.design):
for row in range(self.num_outputs):
and_inst = self.and_inst[row]
self.copy_layout_pin(and_inst, "Z", "decode_{0}".format(row))
def route_decoder_bus(self):
"""
Creates vertical metal 2 bus to connect predecoder and decoder stages.
@@ -522,7 +522,7 @@ class hierarchical_decoder(design.design):
x_offset = self.pre2x4_inst[pre_num].rx() + self.output_layer_pitch
y_offset = self.pre2x4_inst[pre_num].by() + i * self.cell_height
self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset)
# FIXME: convert to connect_bus
for pre_num in range(self.no_of_pre3x8):
for i in range(8):
@@ -542,7 +542,7 @@ class hierarchical_decoder(design.design):
x_offset = self.pre4x16_inst[pre_num].rx() + self.output_layer_pitch
y_offset = self.pre4x16_inst[pre_num].by() + i * self.cell_height
self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset)
def route_bus_to_decoder(self):
"""
Use the self.predec_groups to determine the connections to the decoder AND gates.
@@ -555,7 +555,7 @@ class hierarchical_decoder(design.design):
and the 128th AND3 is connected to [3,7,15]
"""
output_index = 0
if (self.num_inputs == 4 or self.num_inputs == 5):
for index_B in self.predec_groups[1]:
for index_A in self.predec_groups[0]:
@@ -596,7 +596,7 @@ class hierarchical_decoder(design.design):
Add a pin for each row of vdd/gnd which are
must-connects next level up.
"""
if layer_props.hierarchical_decoder.vertical_supply:
for n in ["vdd", "gnd"]:
pins = self.and_inst[0].get_pins(n)
@@ -636,7 +636,7 @@ class hierarchical_decoder(design.design):
for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(pre, pin_name)
def route_predecode_bus_outputs(self, rail_name, pin, row):
"""
Connect the routing rail to the given metal1 pin
@@ -646,17 +646,17 @@ class hierarchical_decoder(design.design):
pin_pos = pin.center()
rail_pos = vector(self.predecode_bus[rail_name].cx(), pin_pos.y)
self.add_path(self.input_layer, [rail_pos, pin_pos])
self.add_via_stack_center(from_layer=self.bus_layer,
to_layer=self.input_layer,
offset=rail_pos,
directions=self.bus_directions)
self.add_via_stack_center(from_layer=pin.layer,
to_layer=self.input_layer,
offset=pin_pos,
directions=("H", "H"))
def route_predecode_bus_inputs(self, rail_name, pin, x_offset, y_offset):
"""
Connect the routing rail to the given metal1 pin using a jog
+17 -17
View File
@@ -31,10 +31,10 @@ class hierarchical_predecode(design.design):
# If we are pitch matched to the bitcell, it's a predecoder
# otherwise it's a column decoder (out of pgates)
self.column_decoder = (height != b.height)
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
super().__init__(name)
def add_pins(self):
for k in range(self.number_of_inputs):
self.add_pin("in_{0}".format(k), "INPUT")
@@ -48,7 +48,7 @@ class hierarchical_predecode(design.design):
debug.check(self.number_of_inputs <= 4,
"Invalid number of predecode inputs: {}".format(self.number_of_inputs))
if self.column_decoder:
and_type = "pand{}".format(self.number_of_inputs)
inv_type = "pinv"
@@ -79,7 +79,7 @@ class hierarchical_predecode(design.design):
self.route()
self.add_boundary()
self.DRC_LVS()
def setup_layout_constraints(self):
# Inputs to cells are on input layer
@@ -92,7 +92,7 @@ class hierarchical_predecode(design.design):
self.input_layer = layer_props.hierarchical_predecode.input_layer
self.output_layer = layer_props.hierarchical_predecode.output_layer
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
self.height = self.number_of_outputs * self.and_mod.height
# x offset for input inverters
@@ -139,7 +139,7 @@ class hierarchical_predecode(design.design):
def place_input_inverters(self):
""" Place the input inverters to invert input signals for the decode stage. """
for inv_num in range(self.number_of_inputs):
if (inv_num % 2 == 0):
y_off = inv_num * (self.inv.height)
mirror = "R0"
@@ -149,7 +149,7 @@ class hierarchical_predecode(design.design):
offset = vector(self.x_off_inv_1, y_off)
self.inv_inst[inv_num].place(offset=offset,
mirror=mirror)
def create_and_array(self, connections):
""" Create the AND stage for the decodes """
self.and_inst = []
@@ -196,7 +196,7 @@ class hierarchical_predecode(design.design):
pin = top_and_gate.get_pin("D")
else:
debug.error("Too many inputs for predecoder.", -1)
y_offset = pin.cy()
in_pin = "in_{}".format(num)
a_pin = "A_{}".format(num)
@@ -222,7 +222,7 @@ class hierarchical_predecode(design.design):
offset=z_pin.ll(),
height=z_pin.height(),
width=z_pin.width())
def route_input_inverters(self):
"""
Route all conections of the inputs inverters [Inputs, outputs, vdd, gnd]
@@ -232,7 +232,7 @@ class hierarchical_predecode(design.design):
in_pin = "in_{}".format(inv_num)
inv_out_pin = self.inv_inst[inv_num].get_pin("Z")
# add output so that it is just below the vdd or gnd rail
# since this is where the p/n devices are and there are no
# pins in the and gates.
@@ -241,7 +241,7 @@ class hierarchical_predecode(design.design):
right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0)
rail_pos = vector(self.decode_rails[out_pin].cx(), y_offset)
self.add_path(self.output_layer, [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
self.add_via_stack_center(from_layer=inv_out_pin.layer,
to_layer=self.output_layer,
offset=inv_out_pos)
@@ -249,7 +249,7 @@ class hierarchical_predecode(design.design):
to_layer=self.bus_layer,
offset=rail_pos,
directions=self.bus_directions)
# route input
pin = self.inv_inst[inv_num].get_pin("A")
inv_in_pos = pin.center()
@@ -267,11 +267,11 @@ class hierarchical_predecode(design.design):
offset=in_pos,
height=via.mod.second_layer_height,
width=via.mod.second_layer_width)
if layer_props.hierarchical_predecode.vertical_supply:
below_rail = vector(self.decode_rails[out_pin].cx(), y_offset - (self.cell_height / 2))
self.add_path(self.bus_layer, [rail_pos, below_rail], width=self.li_width + self.m1_enclose_mcon * 2)
def route_and_to_rails(self):
# This 2D array defines the connection mapping
and_input_line_combination = self.get_and_input_line_combination()
@@ -302,7 +302,7 @@ class hierarchical_predecode(design.design):
direction = None
else:
direction = ("H", "H")
self.add_via_stack_center(from_layer=pin.layer,
to_layer=self.input_layer,
offset=pin_pos,
@@ -334,7 +334,7 @@ class hierarchical_predecode(design.design):
self.add_power_pin(name=n,
loc=pin.uc(),
start_layer=pin.layer)
# In other techs, we are using standard cell decoder cells with horizontal power
else:
for num in range(0, self.number_of_outputs):
@@ -354,6 +354,6 @@ class hierarchical_predecode(design.design):
self.add_power_pin(name=n,
loc=pin_pos,
start_layer=and_pin.layer)
@@ -25,9 +25,9 @@ class hierarchical_predecode3x8(hierarchical_predecode):
self.add_modules()
self.create_input_inverters()
connections=[["inbar_0", "inbar_1", "inbar_2", "out_0", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "out_1", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "out_1", "vdd", "gnd"],
["inbar_0", "in_1", "inbar_2", "out_2", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "out_3", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "out_3", "vdd", "gnd"],
["inbar_0", "inbar_1", "in_2", "out_4", "vdd", "gnd"],
["in_0", "inbar_1", "in_2", "out_5", "vdd", "gnd"],
["inbar_0", "in_1", "in_2", "out_6", "vdd", "gnd"],
@@ -41,7 +41,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
["Abar_0", "A_1", "Abar_2"],
["A_0", "A_1", "Abar_2"],
["Abar_0", "Abar_1", "A_2"],
["A_0", "Abar_1", "A_2"],
["Abar_0", "A_1", "A_2"],
["A_0", "Abar_1", "A_2"],
["Abar_0", "A_1", "A_2"],
["A_0", "A_1", "A_2"]]
return combination
@@ -25,17 +25,17 @@ class hierarchical_predecode4x16(hierarchical_predecode):
self.add_modules()
self.create_input_inverters()
connections=[["inbar_0", "inbar_1", "inbar_2", "inbar_3", "out_0", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "inbar_3", "out_1", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "inbar_3", "out_1", "vdd", "gnd"],
["inbar_0", "in_1", "inbar_2", "inbar_3", "out_2", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "inbar_3", "out_3", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "inbar_3", "out_3", "vdd", "gnd"],
["inbar_0", "inbar_1", "in_2", "inbar_3", "out_4", "vdd", "gnd"],
["in_0", "inbar_1", "in_2", "inbar_3", "out_5", "vdd", "gnd"],
["inbar_0", "in_1", "in_2", "inbar_3", "out_6", "vdd", "gnd"],
["in_0", "in_1", "in_2", "inbar_3", "out_7", "vdd", "gnd"],
["inbar_0", "inbar_1", "inbar_2", "in_3", "out_8", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "in_3", "out_9", "vdd", "gnd"],
["in_0", "inbar_1", "inbar_2", "in_3", "out_9", "vdd", "gnd"],
["inbar_0", "in_1", "inbar_2", "in_3", "out_10", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "in_3", "out_11", "vdd", "gnd"],
["in_0", "in_1", "inbar_2", "in_3", "out_11", "vdd", "gnd"],
["inbar_0", "inbar_1", "in_2", "in_3", "out_12", "vdd", "gnd"],
["in_0", "inbar_1", "in_2", "in_3", "out_13", "vdd", "gnd"],
["inbar_0", "in_1", "in_2", "in_3", "out_14", "vdd", "gnd"],
@@ -50,15 +50,15 @@ class hierarchical_predecode4x16(hierarchical_predecode):
["Abar_0", "A_1", "Abar_2", "Abar_3"],
["A_0", "A_1", "Abar_2", "Abar_3"],
["Abar_0", "Abar_1", "A_2" , "Abar_3"],
["A_0", "Abar_1", "A_2" , "Abar_3"],
["Abar_0", "A_1", "A_2" , "Abar_3"],
["A_0", "Abar_1", "A_2" , "Abar_3"],
["Abar_0", "A_1", "A_2" , "Abar_3"],
["A_0", "A_1", "A_2" , "Abar_3"],
["Abar_0", "Abar_1", "Abar_2", "A_3"],
["A_0", "Abar_1", "Abar_2", "A_3"],
["Abar_0", "A_1", "Abar_2", "A_3"],
["A_0", "A_1", "Abar_2", "A_3"],
["Abar_0", "Abar_1", "A_2", "A_3"],
["A_0", "Abar_1", "A_2", "A_3"],
["Abar_0", "A_1", "A_2", "A_3"],
["A_0", "Abar_1", "A_2", "A_3"],
["Abar_0", "A_1", "A_2", "A_3"],
["A_0", "A_1", "A_2", "A_3"]]
return combination
+24 -24
View File
@@ -32,9 +32,9 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.rbl = rbl
self.left_rbl = left_rbl
self.right_rbl = right_rbl
debug.check(len(self.all_ports) < 3, "Local bitcell array only supports dual port or less.")
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -42,7 +42,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
@@ -56,7 +56,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.add_layout_pins()
self.route()
self.add_boundary()
self.DRC_LVS()
@@ -78,7 +78,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
rows=self.rows + 1,
cols=self.cols)
self.add_mod(self.wl_array)
def add_pins(self):
# Outputs from the wordline driver (by port)
self.driver_wordline_outputs = []
@@ -87,18 +87,18 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.wordline_names = self.bitcell_array.wordline_names
self.all_wordline_names = self.bitcell_array.all_wordline_names
self.bitline_names = self.bitcell_array.bitline_names
self.all_bitline_names = self.bitcell_array.all_bitline_names
self.rbl_wordline_names = self.bitcell_array.rbl_wordline_names
self.all_rbl_wordline_names = self.bitcell_array.all_rbl_wordline_names
self.rbl_bitline_names = self.bitcell_array.rbl_bitline_names
self.all_rbl_bitline_names = self.bitcell_array.all_rbl_bitline_names
self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_all_wordline_names()]
# Arrays are always:
# bit lines (left to right)
# word lines (bottom to top)
@@ -133,10 +133,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
else:
temp += self.get_wordline_names(port)[::-1]
self.driver_wordline_outputs.append([x + "i" for x in temp])
temp += self.driver_wordline_outputs[-1]
temp += ["vdd", "gnd"]
self.connect_inst(temp)
self.bitcell_array_inst = self.add_inst(name="array",
@@ -180,7 +180,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
for x in self.get_inouts():
self.copy_layout_pin(self.bitcell_array_inst, x)
supply_insts = [*self.wl_insts, self.bitcell_array_inst]
for pin_name in ["vdd", "gnd"]:
for inst in supply_insts:
@@ -189,7 +189,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.add_power_pin(name=pin_name,
loc=pin.center(),
start_layer=pin.layer)
def route(self):
# Route the global wordlines
@@ -198,27 +198,27 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)
else:
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1]
wordline_pins = self.wl_array.get_inputs()
for (wl_name, in_pin_name) in zip(wordline_names, wordline_pins):
# wl_pin = self.bitcell_array_inst.get_pin(wl_name)
in_pin = self.wl_insts[port].get_pin(in_pin_name)
y_offset = in_pin.cy()
if port == 0:
y_offset -= 2 * self.m3_pitch
else:
y_offset += 2 * self.m3_pitch
self.add_layout_pin_segment_center(text=wl_name,
layer="m3",
start=vector(self.wl_insts[port].lx(), y_offset),
end=vector(self.wl_insts[port].lx() + self.wl_array.width, y_offset))
mid = vector(in_pin.cx(), y_offset)
self.add_path("m2", [in_pin.center(), mid])
self.add_via_stack_center(from_layer=in_pin.layer,
to_layer="m2",
offset=in_pin.center())
@@ -228,7 +228,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
# Route the buffers
for port in self.all_ports:
driver_outputs = self.driver_wordline_outputs[port]
for (driver_name, net_name) in zip(self.wl_insts[port].mod.get_outputs(), driver_outputs):
array_name = net_name[:-1]
out_pin = self.wl_insts[port].get_pin(driver_name)
@@ -242,7 +242,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
mid_loc = vector(self.wl_insts[port].lx() - 1.5 * self.m3_pitch, out_loc.y)
in_loc = in_pin.rc()
self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc])
def get_main_array_top(self):
return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_top()
@@ -262,13 +262,13 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
# must add the offset of the instance
offsets = [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()]
return offsets
def graph_exclude_bits(self, targ_row=None, targ_col=None):
"""
Excludes bits in column from being added to graph except target
"""
self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
def graph_exclude_replica_col_bits(self):
"""
Exclude all but replica in the local array.
@@ -281,8 +281,8 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col)
def clear_exclude_bits(self):
"""
"""
Clears the bit exclusions
"""
self.bitcell_array.clear_exclude_bits()
+110 -110
View File
@@ -19,9 +19,9 @@ from globals import OPTS
class multibank(design.design):
"""
Dynamically generated a single bank including bitcell array,
hierarchical_decoder, precharge, (optional column_mux and column decoder),
hierarchical_decoder, precharge, (optional column_mux and column decoder),
write driver and sense amplifiers.
This module includes the tristate and bank select logic.
This module includes the tristate and bank select logic.
"""
def __init__(self, name, word_size, num_words, words_per_row, num_banks=1):
@@ -41,7 +41,7 @@ class multibank(design.design):
self.prefix="gated_"
else:
self.prefix=""
self.compute_sizes()
self.add_pins()
self.add_modules()
@@ -50,16 +50,16 @@ class multibank(design.design):
# FIXME: Move this to the add modules function
self.add_bank_select()
self.route_layout()
# Can remove the following, but it helps for debug!
self.add_lvs_correspondence_points()
self.add_lvs_correspondence_points()
# Remember the bank center for further placement
self.bank_center=self.offset_all_coordinates().scale(-1,-1)
self.DRC_LVS()
def add_pins(self):
@@ -91,23 +91,23 @@ class multibank(design.design):
#self.route_tri_gate_out()
self.route_sense_amp_out()
self.route_wordline_driver()
self.route_write_driver()
self.route_write_driver()
self.route_row_decoder()
self.route_column_address_lines()
self.route_control_lines()
self.add_control_pins()
if self.num_banks > 1:
self.route_bank_select()
self.route_bank_select()
self.route_supplies()
def create_instances(self):
""" Add modules. The order should not matter! """
# Above the bitcell array
self.add_bitcell_array()
self.add_precharge_array()
# Below the bitcell array
self.add_column_mux_array()
self.add_sense_amp_array()
@@ -120,7 +120,7 @@ class multibank(design.design):
self.add_wordline_driver()
self.add_column_decoder()
def compute_sizes(self):
""" Computes the required sizes to create the bank """
@@ -139,7 +139,7 @@ class multibank(design.design):
self.supply_rail_width = 4*self.m2_width
# FIXME: This spacing should be width dependent...
self.supply_rail_pitch = self.supply_rail_width + 4*self.m2_space
# Number of control lines in the bus
self.num_control_lines = 6
# The order of the control signals on the control bus:
@@ -153,7 +153,7 @@ class multibank(design.design):
if self.col_addr_size>0:
self.num_col_addr_lines = 2**self.col_addr_size
else:
self.num_col_addr_lines = 0
self.num_col_addr_lines = 0
# The width of this bus is needed to place other modules (e.g. decoder)
# A width on each side too
@@ -169,7 +169,7 @@ class multibank(design.design):
""" Add all the modules using the class loader """
self.tri = self.mod_tri_gate()
self.bitcell = self.mod_bitcell()
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
@@ -178,12 +178,12 @@ class multibank(design.design):
self.add_mod(self.precharge_array)
if self.col_addr_size > 0:
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.column_mux_array)
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
@@ -199,8 +199,8 @@ class multibank(design.design):
self.row_decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.row_decoder)
self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.tri_gate_array)
@@ -213,12 +213,12 @@ class multibank(design.design):
if(self.num_banks > 1):
self.bank_select = self.mod_bank_select()
self.add_mod(self.bank_select)
def add_bitcell_array(self):
""" Adding Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.bitcell_array,
offset=vector(0,0))
temp = []
@@ -238,7 +238,7 @@ class multibank(design.design):
# The enclosure is for the well and the spacing is to the bitcell wells
y_offset = self.bitcell_array.height + self.m2_gap
self.precharge_array_inst=self.add_inst(name="precharge_array",
mod=self.precharge_array,
mod=self.precharge_array,
offset=vector(0,y_offset))
temp = []
for i in range(self.num_cols):
@@ -255,7 +255,7 @@ class multibank(design.design):
self.column_mux_height = 0
return
y_offset = self.column_mux_height
y_offset = self.column_mux_height
self.col_mux_array_inst=self.add_inst(name="column_mux_array",
mod=self.column_mux_array,
offset=vector(0,y_offset).scale(-1,-1))
@@ -287,7 +287,7 @@ class multibank(design.design):
else:
temp.append("bl_out_{0}".format(i))
temp.append("br_out_{0}".format(i))
temp.extend([self.prefix+"s_en", "vdd", "gnd"])
self.connect_inst(temp)
@@ -295,16 +295,16 @@ class multibank(design.design):
""" Adding Write Driver """
y_offset = self.sense_amp_array.height + self.column_mux_height \
+ self.m2_gap + self.write_driver_array.height
self.write_driver_array_inst=self.add_inst(name="write_driver_array",
mod=self.write_driver_array,
+ self.m2_gap + self.write_driver_array.height
self.write_driver_array_inst=self.add_inst(name="write_driver_array",
mod=self.write_driver_array,
offset=vector(0,y_offset).scale(-1,-1))
temp = []
for i in range(self.word_size):
temp.append("bank_din_{0}".format(i))
for i in range(self.word_size):
if (self.words_per_row == 1):
for i in range(self.word_size):
if (self.words_per_row == 1):
temp.append("bl_{0}".format(i))
temp.append("br_{0}".format(i))
else:
@@ -317,10 +317,10 @@ class multibank(design.design):
""" data tri gate to drive the data bus """
y_offset = self.sense_amp_array.height+self.column_mux_height \
+ self.m2_gap + self.tri_gate_array.height
self.tri_gate_array_inst=self.add_inst(name="tri_gate_array",
mod=self.tri_gate_array,
self.tri_gate_array_inst=self.add_inst(name="tri_gate_array",
mod=self.tri_gate_array,
offset=vector(0,y_offset).scale(-1,-1))
temp = []
for i in range(self.word_size):
temp.append("sa_out_{0}".format(i))
@@ -332,16 +332,16 @@ class multibank(design.design):
def add_row_decoder(self):
""" Add the hierarchical row decoder """
# The address and control bus will be in between decoder and the main memory array
# This bus will route address bits to the decoder input and column mux inputs.
# The address and control bus will be in between decoder and the main memory array
# This bus will route address bits to the decoder input and column mux inputs.
# The wires are actually routed after we placed the stuff on both sides.
# The predecoder is below the x-axis and the main decoder is above the x-axis
# The address flop and decoder are aligned in the x coord.
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
self.row_decoder_inst=self.add_inst(name="row_decoder",
mod=self.row_decoder,
self.row_decoder_inst=self.add_inst(name="row_decoder",
mod=self.row_decoder,
offset=vector(x_offset,0))
temp = []
@@ -357,8 +357,8 @@ class multibank(design.design):
# The wordline driver is placed to the right of the main decoder width.
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
self.wordline_driver_inst=self.add_inst(name="wordline_driver",
mod=self.wordline_driver,
self.wordline_driver_inst=self.add_inst(name="wordline_driver",
mod=self.wordline_driver,
offset=vector(x_offset,0))
temp = []
@@ -371,16 +371,16 @@ class multibank(design.design):
temp.append("gnd")
self.connect_inst(temp)
def add_column_decoder_module(self):
"""
"""
Create a 2:4 or 3:8 column address decoder.
"""
# Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc("well_to_well"))
self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder,
self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder,
offset=vector(x_off,y_off))
temp = []
@@ -390,9 +390,9 @@ class multibank(design.design):
temp.append("sel_{0}".format(j))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def add_column_decoder(self):
"""
"""
Create a decoder to decode column select lines. This could be an inverter/buffer for 1:2,
2:4 decoder, or 3:8 decoder.
"""
@@ -408,7 +408,7 @@ class multibank(design.design):
else:
# No error checking before?
debug.error("Invalid column decoder?",-1)
self.add_column_decoder_module()
@@ -417,7 +417,7 @@ class multibank(design.design):
if not self.num_banks > 1:
return
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
if self.col_addr_size > 0:
y_off = min(self.col_decoder_inst.by(), self.col_mux_array_inst.by())
@@ -441,7 +441,7 @@ class multibank(design.design):
for inst in self.insts:
self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd")
def route_bank_select(self):
""" Route the bank select logic. """
for input_name in self.input_control_signals+["bank_sel"]:
@@ -461,8 +461,8 @@ class multibank(design.design):
self.add_via_center(layers=self.m2_stack,
offset=out_pos,
rotate=90)
def setup_layout_constraints(self):
""" After the modules are instantiated, find the dimensions for the
control bus, power ring, etc. """
@@ -472,36 +472,36 @@ class multibank(design.design):
#driver.
# Leave room for the output below the tri gate.
#tri_gate_min_y_offset = self.tri_gate_array_inst.by() - 3*self.m2_pitch
write_driver_min_y_offset = self.write_driver_array_inst.by() - 3*self.m2_pitch
write_driver_min_y_offset = self.write_driver_array_inst.by() - 3*self.m2_pitch
row_decoder_min_y_offset = self.row_decoder_inst.by()
if self.col_addr_size > 0:
col_decoder_min_y_offset = self.col_decoder_inst.by()
else:
col_decoder_min_y_offset = row_decoder_min_y_offset
if self.num_banks>1:
# The control gating logic is below the decoder
# Min of the control gating logic and tri gate.
self.min_y_offset = min(col_decoder_min_y_offset - self.bank_select.height, write_driver_min_y_offset)
else:
# Just the min of the decoder logic logic and tri gate.
# Just the min of the decoder logic logic and tri gate.
self.min_y_offset = min(col_decoder_min_y_offset, write_driver_min_y_offset)
# The max point is always the top of the precharge bitlines
# Add a vdd and gnd power rail above the array
self.max_y_offset = self.precharge_array_inst.uy() + 3*self.m1_width
self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width
self.min_x_offset = self.row_decoder_inst.lx()
self.min_x_offset = self.row_decoder_inst.lx()
# # Create the core bbox for the power rings
ur = vector(self.max_x_offset, self.max_y_offset)
ll = vector(self.min_x_offset, self.min_y_offset)
self.core_bbox = [ll, ur]
self.height = ur.y - ll.y
self.width = ur.x - ll.x
def route_central_bus(self):
""" Create the address, supply, and control signal central bus lines. """
@@ -509,7 +509,7 @@ class multibank(design.design):
# Overall central bus width. It includes all the column mux lines,
# and control lines.
# The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs
# 2 pitches on the right for vias/jogs to access the inputs
control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, 0)
control_bus_length = self.bitcell_array_inst.uy()
self.bus_xoffset = self.create_vertical_bus(layer="m2",
@@ -542,7 +542,7 @@ class multibank(design.design):
# Only do this if we have a column mux!
if self.col_addr_size==0:
return
for i in range(self.num_cols):
col_mux_bl = self.col_mux_array_inst.get_pin("bl_{}".format(i)).uc()
col_mux_br = self.col_mux_array_inst.get_pin("br_{}".format(i)).uc()
@@ -554,7 +554,7 @@ class multibank(design.design):
vector(bitcell_bl.x,yoffset), bitcell_bl])
self.add_path("m2",[col_mux_br, vector(col_mux_br.x,yoffset),
vector(bitcell_br.x,yoffset), bitcell_br])
def route_sense_amp_to_col_mux_or_bitcell_array(self):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
@@ -570,19 +570,19 @@ class multibank(design.design):
# Sense amp is directly connected to the bitcell array
connect_bl = self.bitcell_array_inst.get_pin("bl_{}".format(i)).bc()
connect_br = self.bitcell_array_inst.get_pin("br_{}".format(i)).bc()
yoffset = 0.5*(sense_amp_bl.y+connect_bl.y)
self.add_path("m2",[sense_amp_bl, vector(sense_amp_bl.x,yoffset),
vector(connect_bl.x,yoffset), connect_bl])
self.add_path("m2",[sense_amp_br, vector(sense_amp_br.x,yoffset),
vector(connect_br.x,yoffset), connect_br])
def route_sense_amp_to_trigate(self):
""" Routing of sense amp output to tri_gate input """
for i in range(self.word_size):
# Connection of data_out of sense amp to data_in
# Connection of data_out of sense amp to data_in
tri_gate_in = self.tri_gate_array_inst.get_pin("in_{}".format(i)).lc()
sa_data_out = self.sense_amp_array_inst.get_pin("data_{}".format(i)).bc()
@@ -597,17 +597,17 @@ class multibank(design.design):
for i in range(self.word_size):
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(i))
self.add_layout_pin_rect_center(text="dout_{}".format(i),
layer=data_pin.layer,
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width()),
def route_tri_gate_out(self):
""" Metal 3 routing of tri_gate output data """
for i in range(self.word_size):
data_pin = self.tri_gate_array_inst.get_pin("out_{}".format(i))
self.add_layout_pin_rect_center(text="dout_{}".format(i),
layer=data_pin.layer,
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width()),
@@ -622,21 +622,21 @@ class multibank(design.design):
decoder_name = "a_{}".format(i)
addr_name = "a_{}".format(addr_idx)
self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name)
def route_write_driver(self):
""" Connecting write driver """
for i in range(self.word_size):
data_name = "data_{}".format(i)
data_name = "data_{}".format(i)
din_name = "bank_din_{}".format(i)
self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
def route_wordline_driver(self):
""" Connecting Wordline driver output to Bitcell WL connection """
# we don't care about bends after connecting to the input pin, so let the path code decide.
for i in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
@@ -653,23 +653,23 @@ class multibank(design.design):
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_column_address_lines(self):
""" Connecting the select lines of column mux to the address bus """
if not self.col_addr_size>0:
return
if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# The Address LSB
self.copy_layout_pin(self.col_decoder_inst, "A", "a[0]")
self.copy_layout_pin(self.col_decoder_inst, "A", "a[0]")
elif self.col_addr_size > 1:
decode_names = []
for i in range(self.num_col_addr_lines):
@@ -679,7 +679,7 @@ class multibank(design.design):
decoder_name = "in_{}".format(i)
addr_name = "a_{}".format(i)
self.copy_layout_pin(self.col_decoder_inst, decoder_name, addr_name)
# This will do a quick "river route" on two layers.
# When above the top select line it will offset "inward" again to prevent conflicts.
@@ -688,7 +688,7 @@ class multibank(design.design):
for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)):
mux_name = "sel_{}".format(i)
mux_addr_pos = self.col_mux_array_inst.get_pin(mux_name).lc()
decode_out_pos = self.col_decoder_inst.get_pin(decode_name).center()
# To get to the edge of the decoder and one track out
@@ -700,13 +700,13 @@ class multibank(design.design):
mid2_pos = vector(mid1_pos.x,mux_addr_pos.y)
#self.add_wire(self.m1_stack,[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
self.add_path("m1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos])
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.
""" 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.
"""
@@ -715,9 +715,9 @@ class multibank(design.design):
wl_name = "wl_{}".format(i)
wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=wl_name,
layer="m1",
layer="m1",
offset=wl_pin.center())
# Add the bitline names
for i in range(self.num_cols):
bl_name = "bl_{}".format(i)
@@ -725,35 +725,35 @@ class multibank(design.design):
bl_pin = self.bitcell_array_inst.get_pin(bl_name)
br_pin = self.bitcell_array_inst.get_pin(br_name)
self.add_label(text=bl_name,
layer="m2",
layer="m2",
offset=bl_pin.center())
self.add_label(text=br_name,
layer="m2",
layer="m2",
offset=br_pin.center())
# # Add the data output names to the sense amp output
# # Add the data output names to the sense amp output
# for i in range(self.word_size):
# data_name = "data_{}".format(i)
# data_pin = self.sense_amp_array_inst.get_pin(data_name)
# self.add_label(text="sa_out_{}".format(i),
# layer="m2",
# layer="m2",
# offset=data_pin.center())
# Add labels on the decoder
for i in range(self.word_size):
data_name = "dec_out_{}".format(i)
pin_name = "in_{}".format(i)
pin_name = "in_{}".format(i)
data_pin = self.wordline_driver_inst.get_pin(pin_name)
self.add_label(text=data_name,
layer="m1",
layer="m1",
offset=data_pin.center())
def route_control_lines(self):
""" Route the control lines of the entire bank """
# Make a list of tuples that we will connect.
# From control signal to the module pin
# From control signal to the module pin
# Connection from the central bus to the main control block crosses
# pre-decoder and this connection is in metal3
connection = []
@@ -762,7 +762,7 @@ class multibank(design.design):
connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst.get_pin("en").lc()))
connection.append((self.prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc()))
connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc()))
for (control_signal, pin_pos) in connection:
control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y)
self.add_path("m1", [control_pos, pin_pos])
@@ -781,7 +781,7 @@ class multibank(design.design):
self.add_via_center(layers=self.m1_stack,
offset=control_via_pos,
rotate=90)
def add_control_pins(self):
""" Add the control signal input pins """
@@ -791,15 +791,15 @@ class multibank(design.design):
if self.num_banks > 1:
# it's not an input pin if we have multiple banks
self.add_label_pin(text=ctrl,
layer="m2",
offset=vector(x_offset, self.min_y_offset),
width=self.m2_width,
layer="m2",
offset=vector(x_offset, self.min_y_offset),
width=self.m2_width,
height=self.max_y_offset-self.min_y_offset)
else:
self.add_layout_pin(text=ctrl,
layer="m2",
offset=vector(x_offset, self.min_y_offset),
width=self.m2_width,
layer="m2",
offset=vector(x_offset, self.min_y_offset),
width=self.m2_width,
height=self.max_y_offset-self.min_y_offset)
@@ -815,8 +815,8 @@ class multibank(design.design):
self.add_via(layers=self.m2_stack,
offset=in_pin + self.m2m3_via_offset,
rotate=90)
def connect_rail_from_left(self,inst, pin, rail):
""" Helper routine to connect an unrotated/mirrored oriented instance to the rails """
in_pin = inst.get_pin(pin).rc()
+8 -8
View File
@@ -27,7 +27,7 @@ class bitcell_array(bitcell_base_array):
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
@@ -41,7 +41,7 @@ class bitcell_array(bitcell_base_array):
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -58,20 +58,20 @@ class bitcell_array(bitcell_base_array):
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.cell)
self.connect_inst(self.get_bitcell_pins(col, row))
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
bl_swing = OPTS.rbl_delay_percentage
freq = spice["default_event_frequency"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
# Calculate the bitcell power which currently only includes leakage
cell_power = self.cell.analytical_power(corner, load)
# Leakage power grows with entire array and bitlines.
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
cell_power.leakage * self.column_size * self.row_size)
@@ -102,7 +102,7 @@ class bitcell_array(bitcell_base_array):
bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size
return total_cin
def graph_exclude_bits(self, targ_row, targ_col):
"""Excludes bits in column from being added to graph except target"""
# Function is not robust with column mux configurations
@@ -111,7 +111,7 @@ class bitcell_array(bitcell_base_array):
if row == targ_row and col == targ_col:
continue
self.graph_inst_exclude.add(self.cell_inst[row, col])
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
return inst_name + '.x' + self.cell_inst[row, col].name, self.cell_inst[row, col]
+18 -18
View File
@@ -19,12 +19,12 @@ class port_address(design.design):
"""
def __init__(self, cols, rows, port, name=""):
self.num_cols = cols
self.num_rows = rows
self.port = port
self.addr_size = ceil(log(self.num_rows, 2))
if name == "":
name = "port_address_{0}_{1}".format(cols, rows)
super().__init__(name)
@@ -42,7 +42,7 @@ class port_address(design.design):
self.create_row_decoder()
self.create_wordline_driver()
self.create_rbl_driver()
def create_layout(self):
if "li" in layer:
self.route_layer = "li"
@@ -57,23 +57,23 @@ class port_address(design.design):
for bit in range(self.addr_size):
self.add_pin("addr_{0}".format(bit), "INPUT")
self.add_pin("wl_en", "INPUT")
for bit in range(self.num_rows):
self.add_pin("wl_{0}".format(bit), "OUTPUT")
self.add_pin("rbl_wl", "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def route_layout(self):
""" Create routing amoung the modules """
self.route_pins()
self.route_internal()
self.route_supplies()
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]:
@@ -85,7 +85,7 @@ class port_address(design.design):
self.add_power_pin("vdd", rbl_vdd_pin.center())
else:
self.add_power_pin("vdd", rbl_vdd_pin.lc())
def route_pins(self):
for row in range(self.addr_size):
decoder_name = "addr_{}".format(row)
@@ -96,7 +96,7 @@ class port_address(design.design):
self.copy_layout_pin(self.wordline_driver_array_inst, driver_name)
self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl")
def route_internal(self):
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
@@ -133,13 +133,13 @@ class port_address(design.design):
self.add_layout_pin_rect_center(text="wl_en",
layer=en_pin.layer,
offset=rbl_in_pos)
def add_modules(self):
self.row_decoder = factory.create(module_type="decoder",
num_outputs=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
rows=self.num_rows,
cols=self.num_cols)
@@ -165,12 +165,12 @@ class port_address(design.design):
self.rbl_driver = factory.create(module_type="buf_dec",
size=driver_size,
height=b.height)
self.add_mod(self.rbl_driver)
def create_row_decoder(self):
""" Create the hierarchical row decoder """
self.row_decoder_inst = self.add_inst(name="row_decoder",
mod=self.row_decoder)
@@ -187,7 +187,7 @@ class port_address(design.design):
self.rbl_driver_inst = self.add_inst(name="rbl_driver",
mod=self.rbl_driver)
temp = []
temp.append("wl_en")
temp.append("rbl_wl")
@@ -197,7 +197,7 @@ class port_address(design.design):
def create_wordline_driver(self):
""" Create the Wordline Driver """
self.wordline_driver_array_inst = self.add_inst(name="wordline_driver",
mod=self.wordline_driver_array)
@@ -231,7 +231,7 @@ class port_address(design.design):
rbl_driver_offset = vector(x_offset,
self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset)
# Pass this up
self.predecoder_height = self.row_decoder.predecoder_height
+15 -15
View File
@@ -39,7 +39,7 @@ class port_data(design.design):
self.bit_offsets.append(i * bitcell.width)
else:
self.bit_offsets = bit_offsets
if name == "":
name = "port_data_{0}".format(self.port)
super().__init__(name)
@@ -189,7 +189,7 @@ class port_data(design.design):
# Precharge will be shifted left if needed
# Column offset is set to port so extra column can be on left or right
# and mirroring happens correctly
# Used for names/dimensions only
self.cell = factory.create(module_type="bitcell")
@@ -295,7 +295,7 @@ class port_data(design.design):
for bit in range(self.num_cols):
temp.append("bl_{0}".format(bit))
temp.append("br_{0}".format(bit))
for bit in range(self.num_spare_cols):
temp.append("sparebl_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
@@ -352,12 +352,12 @@ class port_data(design.design):
else:
temp.append("bl_out_{0}".format(bit))
temp.append("br_out_{0}".format(bit))
for bit in range(self.num_spare_cols):
temp.append("dout_{}".format(self.word_size + bit))
temp.append("sparebl_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
temp.append("s_en")
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
@@ -561,26 +561,26 @@ class port_data(design.design):
else:
start_bit=0
# spare cols connected to precharge array since they are read independently
# spare cols connected to precharge array since they are read independently
if self.num_spare_cols and self.col_addr_size>0:
if self.port==0:
off = 1
else:
off = 0
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
elif layer_props.port_data.channel_route_bitlines:
self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
@@ -595,7 +595,7 @@ class port_data(design.design):
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
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 """
inst2 = self.write_driver_array_inst
@@ -619,19 +619,19 @@ class port_data(design.design):
else:
off = 0
# Channel route spare columns' bitlines
# Channel route spare columns' bitlines
if self.num_spare_cols and self.col_addr_size>0:
if self.port==0:
off = 1
else:
off = 0
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
@@ -689,7 +689,7 @@ class port_data(design.design):
"br_{}".format(bit))
else:
debug.error("Didn't find precharge array.")
# Copy bitlines of spare columns
for bit in range(self.num_spare_cols):
if self.precharge_array_inst:
+8 -8
View File
@@ -23,7 +23,7 @@ class precharge_array(design.design):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
self.columns = columns
self.offsets = offsets
self.size = size
@@ -35,7 +35,7 @@ class precharge_array(design.design):
self.en_bar_layer = "m3"
else:
self.en_bar_layer = "m1"
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -61,10 +61,10 @@ class precharge_array(design.design):
self.add_modules()
self.add_pins()
self.create_insts()
def create_layout(self):
self.place_insts()
self.width = self.offsets[-1] + self.pc_cell.width
self.height = self.pc_cell.height
@@ -94,12 +94,12 @@ class precharge_array(design.design):
to_layer=self.en_bar_layer,
offset=inst.get_pin("en_bar").center())
self.copy_layout_pin(inst, "vdd")
for i in range(len(self.local_insts)):
inst = self.local_insts[i]
self.copy_layout_pin(inst, "bl", "bl_{0}".format(i))
self.copy_layout_pin(inst, "br", "br_{0}".format(i))
def create_insts(self):
"""Creates a precharge array by horizontally tiling the precharge cell"""
self.local_insts = []
@@ -114,7 +114,7 @@ class precharge_array(design.design):
def place_insts(self):
""" Places precharge array by horizontally tiling the precharge cell"""
# Default to single spaced columns
if not self.offsets:
self.offsets = [n * self.pc_cell.width for n in range(self.columns)]
@@ -130,4 +130,4 @@ class precharge_array(design.design):
offset = vector(tempx, 0)
self.local_insts[i].place(offset=offset, mirror=mirror)
+19 -19
View File
@@ -52,7 +52,7 @@ class replica_bitcell_array(bitcell_base_array):
else:
self.right_rbl=[1] if len(self.all_ports) > 1 else []
self.rbls = self.left_rbl + self.right_rbl
debug.check(sum(self.rbl) == len(self.all_ports),
"Invalid number of RBLs for port configuration.")
debug.check(sum(self.rbl) >= len(self.left_rbl) + len(self.right_rbl),
@@ -80,7 +80,7 @@ class replica_bitcell_array(bitcell_base_array):
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
@@ -119,7 +119,7 @@ class replica_bitcell_array(bitcell_base_array):
# Replica bitlines
self.replica_columns = {}
for port in self.all_ports:
if port in self.left_rbl:
# We will always have self.rbl[0] rows of replica wordlines below
@@ -127,17 +127,17 @@ class replica_bitcell_array(bitcell_base_array):
# These go from the top (where the bitcell array starts ) down
replica_bit = self.rbl[0] - port
elif port in self.right_rbl:
# We will always have self.rbl[0] rows of replica wordlines below
# the array.
# These go from the bottom up
replica_bit = self.rbl[0] + self.row_size + port
else:
continue
# If we have an odd numer on the bottom
column_offset = self.rbl[0] + 1
self.replica_columns[port] = factory.create(module_type="replica_column",
rows=self.row_size,
rbl=self.rbl,
@@ -213,7 +213,7 @@ class replica_bitcell_array(bitcell_base_array):
#
# vdd
# gnd
self.add_bitline_pins()
self.add_wordline_pins()
self.add_pin("vdd", "POWER")
@@ -238,13 +238,13 @@ class replica_bitcell_array(bitcell_base_array):
self.add_pin_list(self.all_bitline_names, "INOUT")
for port in self.right_rbl:
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
def add_wordline_pins(self):
try:
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
# Wordlines to ground
self.gnd_wordline_names = []
@@ -259,7 +259,7 @@ class replica_bitcell_array(bitcell_base_array):
self.wordline_names = self.bitcell_array.wordline_names
self.all_wordline_names = self.bitcell_array.all_wordline_names
# All wordlines including dummy and RBL
self.replica_array_wordline_names = []
self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names()))
@@ -297,7 +297,7 @@ class replica_bitcell_array(bitcell_base_array):
self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies)
else:
self.replica_col_insts.append(None)
# Dummy rows under the bitcell array (connected with with the replica cell wl)
self.dummy_row_replica_insts = []
# Note, this is the number of left and right even if we aren't adding the columns to this bitcell array!
@@ -347,7 +347,7 @@ class replica_bitcell_array(bitcell_base_array):
self.bitcell_array_inst.place(offset=self.unused_offset)
self.add_replica_columns()
self.add_end_caps()
@@ -359,7 +359,7 @@ class replica_bitcell_array(bitcell_base_array):
self.add_layout_pins()
self.route_unused_wordlines()
self.add_boundary()
self.DRC_LVS()
@@ -419,7 +419,7 @@ class replica_bitcell_array(bitcell_base_array):
dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul()
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset,
mirror="MX" if bit % 2 else "R0")
def add_end_caps(self):
""" Add dummy cells or end caps around the array """
try:
@@ -465,7 +465,7 @@ class replica_bitcell_array(bitcell_base_array):
def add_layout_pins(self):
""" Add the layout pins """
#All wordlines
#Main array wl and bl/br
@@ -514,7 +514,7 @@ class replica_bitcell_array(bitcell_base_array):
# vdd/gnd are only connected in the perimeter cells
# replica column should only have a vdd/gnd in the dummy cell on top/bottom
supply_insts = self.dummy_col_insts + self.dummy_row_insts
for pin_name in self.supplies:
for inst in supply_insts:
pin_list = inst.get_pins(pin_name)
@@ -560,7 +560,7 @@ class replica_bitcell_array(bitcell_base_array):
def ground_pin(self, inst, name):
pin = inst.get_pin(name)
pin_layer = pin.layer
left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy())
right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy())
@@ -573,7 +573,7 @@ class replica_bitcell_array(bitcell_base_array):
# Add a path to connect to the array
self.add_path(pin_layer, [left_loc, left_pin_loc])
self.add_path(pin_layer, [right_loc, right_pin_loc])
def gen_bl_wire(self):
if OPTS.netlist_only:
height = 0
@@ -605,7 +605,7 @@ class replica_bitcell_array(bitcell_base_array):
return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col)
def clear_exclude_bits(self):
"""
"""
Clears the bit exclusions
"""
self.bitcell_array.init_graph_params()
+7 -7
View File
@@ -35,7 +35,7 @@ class replica_column(bitcell_base_array):
self.total_size += 2
except AttributeError:
self.total_size += 2
self.column_offset = column_offset
debug.check(replica_bit != 0 and replica_bit != rows,
@@ -96,7 +96,7 @@ class replica_column(bitcell_base_array):
end_caps_enabled = cell_properties.bitcell.end_caps
except AttributeError:
end_caps_enabled = False
for row in range(self.total_size):
name="rbc_{0}".format(row)
# Top/bottom cell are always dummy cells.
@@ -197,7 +197,7 @@ class replica_column(bitcell_base_array):
self.copy_power_pins(inst, pin_name)
else:
self.copy_layout_pin(inst, pin_name)
def get_bitline_names(self, port=None):
if port == None:
return self.all_bitline_names
@@ -205,9 +205,9 @@ class replica_column(bitcell_base_array):
return self.bitline_names[port]
def get_bitcell_pins(self, row, col):
"""
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
indexed by column and row, for instance use in bitcell_array
"""
bitcell_pins = []
for port in self.all_ports:
@@ -219,7 +219,7 @@ class replica_column(bitcell_base_array):
return bitcell_pins
def get_bitcell_pins_col_cap(self, row, col):
"""
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
@@ -242,4 +242,4 @@ class replica_column(bitcell_base_array):
if row != self.replica_bit:
self.graph_inst_exclude.add(cell)
+8 -8
View File
@@ -36,16 +36,16 @@ class sense_amp(design.design):
(width, height) = utils.get_libcell_size(name,
GDS["unit"],
layer[self.cell_size_layer])
pin_map = utils.get_libcell_pins(self.pin_names,
name,
GDS["unit"])
self.width = width
self.height = height
self.pin_map = pin_map
self.add_pin_types(self.type_list)
def get_bl_names(self):
return props.sense_amp.pin.bl
@@ -61,16 +61,16 @@ class sense_amp(design.design):
return props.sense_amp.pin.en
def get_cin(self):
# FIXME: This input load will be applied to both the s_en timing and bitline timing.
# Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
from tech import spice
# Default is 8x. Per Samira and Hodges-Jackson book:
# "Column-mux transistors driven by the decoder must be sized for optimal speed"
bitline_pmos_size = 8 # FIXME: This should be set somewhere and referenced. Probably in tech file.
return spice["min_tx_drain_c"] * bitline_pmos_size # ff
def get_stage_effort(self, load):
# Delay of the sense amp will depend on the size of the amp and the output load.
parasitic_delay = 1
@@ -84,14 +84,14 @@ class sense_amp(design.design):
# Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
total_power = self.return_power()
return total_power
def get_enable_name(self):
"""Returns name used for enable net"""
# FIXME: A better programmatic solution to designate pins
enable_name = self.en_name
debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name))
return enable_name
def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets)
+5 -5
View File
@@ -34,7 +34,7 @@ class sense_amp_array(design.design):
self.num_spare_cols = 0
else:
self.num_spare_cols = num_spare_cols
self.column_offset = column_offset
self.row_size = self.word_size * self.words_per_row
@@ -71,13 +71,13 @@ class sense_amp_array(design.design):
def create_layout(self):
self.place_sense_amp_array()
self.height = self.amp.height
self.width = self.local_insts[-1].rx()
self.add_layout_pins()
self.route_rails()
self.add_boundary()
self.DRC_LVS()
@@ -115,7 +115,7 @@ class sense_amp_array(design.design):
self.amp_spacing = self.bitcell.width
else:
self.amp_spacing = self.amp.width
if not self.offsets:
self.offsets = []
for i in range(self.num_cols + self.num_spare_cols):
@@ -130,7 +130,7 @@ class sense_amp_array(design.design):
amp_position = vector(xoffset, 0)
self.local_insts[i].place(offset=amp_position, mirror=mirror)
# place spare sense amps (will share the same enable as regular sense amps)
for i, xoffset in enumerate(self.offsets[self.num_cols:]):
index = self.word_size + i
+7 -7
View File
@@ -25,7 +25,7 @@ class tri_gate_array(design.design):
self.columns = columns
self.word_size = word_size
self.words_per_row = int(self.columns / self.word_size)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -34,7 +34,7 @@ class tri_gate_array(design.design):
self.add_modules()
self.add_pins()
self.create_array()
def create_layout(self):
self.width = (self.columns / self.words_per_row) * self.tri.width
self.height = self.tri.height
@@ -47,7 +47,7 @@ class tri_gate_array(design.design):
def add_modules(self):
self.tri = factory.create(module_type="tri_gate")
self.add_mod(self.tri)
def add_pins(self):
"""create the name of pins depend on the word size"""
for i in range(self.word_size):
@@ -74,10 +74,10 @@ class tri_gate_array(design.design):
for i in range(0,self.columns,self.words_per_row):
base = vector(i*self.tri.width, 0)
self.tri_inst[i].place(base)
def add_layout_pins(self):
for i in range(0,self.columns,self.words_per_row):
index = int(i/self.words_per_row)
@@ -105,7 +105,7 @@ class tri_gate_array(design.design):
self.add_layout_pin_rect_center(text=n,
layer="m3",
offset=pin_pos)
width = self.tri.width * self.columns - (self.words_per_row - 1) * self.tri.width
en_pin = self.tri_inst[0].get_pin("en")
@@ -114,7 +114,7 @@ class tri_gate_array(design.design):
offset=en_pin.ll().scale(0, 1),
width=width,
height=drc("minwidth_m1"))
enbar_pin = self.tri_inst[0].get_pin("en_bar")
self.add_layout_pin(text="en_bar",
layer="m1",
+9 -9
View File
@@ -23,7 +23,7 @@ class wordline_buffer_array(design.design):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows
self.cols = cols
@@ -35,7 +35,7 @@ class wordline_buffer_array(design.design):
self.add_modules()
self.add_pins()
self.create_drivers()
def create_layout(self):
if "li" in layer:
self.route_layer = "li"
@@ -47,7 +47,7 @@ class wordline_buffer_array(design.design):
self.offset_all_coordinates()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
@@ -60,12 +60,12 @@ class wordline_buffer_array(design.design):
def add_modules(self):
b = factory.create(module_type="bitcell")
self.wl_driver = factory.create(module_type="inv_dec",
size=self.cols,
height=b.height)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):
"""
Add a pin for each row of vdd/gnd which
@@ -84,7 +84,7 @@ class wordline_buffer_array(design.design):
xoffset_list = [self.wld_inst[0].rx()]
for num in range(self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the and's too
(gate_offset, y_dir) = self.get_gate_offset(0,
self.wl_driver.height,
@@ -92,12 +92,12 @@ class wordline_buffer_array(design.design):
# Route both supplies
for name in ["vdd", "gnd"]:
supply_pin = self.wld_inst[num].get_pin(name)
# Add pins in two locations
for xoffset in xoffset_list:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name, pin_pos)
def create_drivers(self):
self.wld_inst = []
for row in range(self.rows):
@@ -119,7 +119,7 @@ class wordline_buffer_array(design.design):
inst_mirror = "MX"
offset = [0, y_offset]
self.wld_inst[row].place(offset=offset,
mirror=inst_mirror)
+12 -12
View File
@@ -24,7 +24,7 @@ class wordline_driver_array(design.design):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows
self.cols = cols
@@ -36,7 +36,7 @@ class wordline_driver_array(design.design):
self.add_modules()
self.add_pins()
self.create_drivers()
def create_layout(self):
if "li" in layer:
self.route_layer = "li"
@@ -48,7 +48,7 @@ class wordline_driver_array(design.design):
self.offset_x_coordinates()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
@@ -61,12 +61,12 @@ class wordline_driver_array(design.design):
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.wl_driver = factory.create(module_type="wordline_driver",
cols=self.cols)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):
"""
Add a pin for each row of vdd/gnd which
@@ -85,7 +85,7 @@ class wordline_driver_array(design.design):
xoffset_list = [self.wld_inst[0].rx()]
for num in range(self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the and's too
(gate_offset, y_dir) = self.get_gate_offset(0,
self.wl_driver.height,
@@ -93,12 +93,12 @@ class wordline_driver_array(design.design):
# Route both supplies
for name in ["vdd", "gnd"]:
supply_pin = self.wld_inst[num].get_pin(name)
# Add pins in two locations
for xoffset in xoffset_list:
pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name, pin_pos)
def create_drivers(self):
self.wld_inst = []
for row in range(self.rows):
@@ -123,7 +123,7 @@ class wordline_driver_array(design.design):
inst_mirror = "R0"
and2_offset = [self.wl_driver.width, y_offset]
# add and2
self.wld_inst[row].place(offset=and2_offset,
mirror=inst_mirror)
@@ -143,7 +143,7 @@ class wordline_driver_array(design.design):
layer="m2",
offset=en_bottom_pos,
height=self.height)
for row in range(self.rows):
and_inst = self.wld_inst[row]
@@ -152,7 +152,7 @@ class wordline_driver_array(design.design):
self.add_via_stack_center(from_layer=b_pin.layer,
to_layer="m2",
offset=b_pin.center())
# connect the decoder input pin to and2 A
self.copy_layout_pin(and_inst, "A", "in_{0}".format(row))
+6 -6
View File
@@ -121,13 +121,13 @@ class write_driver_array(design.design):
if w == self.write_size:
w = 0
windex+=1
elif self.num_spare_cols and not self.write_size:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(0), "vdd", "gnd"])
else:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
@@ -173,13 +173,13 @@ class write_driver_array(design.design):
# place spare write drivers (if spare columns are specified)
for i, xoffset in enumerate(self.offsets[self.columns:]):
index = self.word_size + i
if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
@@ -229,14 +229,14 @@ class write_driver_array(design.design):
offset=en_pin.ll(),
width=wmask_en_len - en_gap,
height=en_pin.height())
for i in range(self.num_spare_cols):
inst = self.driver_insts[self.word_size + i]
en_pin = inst.get_pin(inst.mod.en_name)
self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks),
layer="m1",
offset=en_pin.lr() + vector(-drc("minwidth_m1"),0))
elif self.num_spare_cols and not self.write_size:
# shorten enable rail to accomodate those for spare write drivers
left_inst = self.driver_insts[0]
+2 -2
View File
@@ -96,7 +96,7 @@ class write_mask_and_array(design.design):
self.offsets = []
for i in range(self.columns):
self.offsets.append(i * self.driver_spacing)
self.width = self.offsets[-1] + self.driver_spacing
self.height = self.and2.height
@@ -128,7 +128,7 @@ class write_mask_and_array(design.design):
layer="m2",
offset=in_pos)
self.add_path(a_pin.layer, [in_pos, a_pos])
# Copy remaining layout pins
self.copy_layout_pin(self.and2_insts[i], "Z", "wmask_out_{0}".format(i))