mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-29 01:24:39 +02:00
Remove EOL whitespace globally
This commit is contained in:
+73
-73
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user