Convert channel router to take netlist of pins rather than names.

This commit is contained in:
Matt Guthaus 2018-11-29 12:12:10 -08:00
parent a7bc9e0de0
commit 4df862d8af
3 changed files with 100 additions and 93 deletions

View File

@ -745,13 +745,14 @@ class layout(lef.lef):
self.add_wire(layer_stack, [pin.center(), mid, trunk_mid])
def create_channel_route(self, netlist, pins, offset,
layer_stack=("metal1", "via1", "metal2"), pitch=None,
def create_channel_route(self, netlist,
offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None,
vertical=False):
"""
The net list is a list of the nets. Each net is a list of pin
names to be connected. Pins is a dictionary of the pin names
to the pin structures. Offset is the lower-left of where the
The net list is a list of the nets. Each net is a list of pins
to be connected. Offset is the lower-left of where the
routing channel will start. This does NOT try to minimize the
number of tracks -- instead, it picks an order to avoid the
vertical conflicts between pins.
@ -786,7 +787,10 @@ class layout(lef.lef):
def vcg_pin_overlap(pin1, pin2, vertical):
""" Check for vertical or horizontal overlap of the two pins """
# FIXME: If the pins are not in a row, this may break.
# However, a top pin shouldn't overlap another top pin, for example, so the
# extra comparison *shouldn't* matter.
# Pin 1 must be in the "BOTTOM" set
x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x-pin2.center().x)<pitch
@ -815,10 +819,7 @@ class layout(lef.lef):
for pin_list in netlist:
net_name = "n{}".format(index)
index += 1
nets[net_name] = []
for pin_name in pin_list:
pin = pins[pin_name]
nets[net_name].append(pin)
nets[net_name] = pin_list
# Find the vertical pin conflicts
# FIXME: O(n^2) but who cares for now
@ -868,23 +869,21 @@ class layout(lef.lef):
offset += vector(0,pitch)
def create_vertical_channel_route(self, netlist, pins, offset,
def create_vertical_channel_route(self, netlist, offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Wrapper to create a vertical channel route
"""
self.create_channel_route(netlist, pins, offset, layer_stack,
pitch, vertical=True)
self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=True)
def create_horizontal_channel_route(self, netlist, pins, offset,
def create_horizontal_channel_route(self, netlist, offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Wrapper to create a horizontal channel route
"""
self.create_channel_route(netlist, pins, offset,
layer_stack, pitch, vertical=False)
self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=False)
def add_enclosure(self, insts, layer="nwell"):
""" Add a layer that surrounds the given instances. Useful

View File

@ -907,6 +907,9 @@ class bank(design.design):
inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}"
# The column mux is constructed to match the bitline pitch, so we can directly connect
# here and not channel route the bitlines.
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
@ -927,8 +930,8 @@ class bank(design.design):
inst1_bl_name = "bl_{}"
inst1_br_name = "br_{}"
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
def route_write_driver_to_column_mux_or_bitcell_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
@ -953,7 +956,11 @@ class bank(design.design):
inst1 = self.write_driver_array_inst[port]
inst2 = self.sense_amp_array_inst[port]
self.connect_bitlines(inst1, inst2, self.word_size)
# These should be pitch matched in the cell library,
# but just in case, do a channel route.
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
def route_sense_amp_out(self, port):
@ -1008,14 +1015,10 @@ class bank(design.design):
# of tracks in teh channel router yet. If we did, we could route all the bits at once!
offset = bottom_inst.ul() + vector(0,self.m1_pitch)
for bit in range(num_bits):
bottom_names = [bottom_bl_name.format(bit), bottom_br_name.format(bit)]
top_names = [top_bl_name.format(bit), top_br_name.format(bit)]
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit)), bottom_inst.get_pin(bottom_br_name.format(bit))]
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))
bottom_pins = {key: bottom_inst.get_pin(key) for key in bottom_names }
top_pins = {key: top_inst.get_pin(key) for key in top_names }
all_pins = {**bottom_pins, **top_pins}
debug.check(len(all_pins)==len(bottom_pins)+len(top_pins),"Duplicate named pins in bitline channel route.")
self.create_horizontal_channel_route(route_map, all_pins, offset)
self.create_horizontal_channel_route(route_map, offset)
def connect_bitlines(self, inst1, inst2, num_bits,
@ -1093,79 +1096,81 @@ class bank(design.design):
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
# def route_column_address_lines(self, port):
# if port%2:
# self.route_column_address_lines_right(port)
# else:
# self.route_column_address_lines_left(port)
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:
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.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):
decode_names.append("out_{}".format(i))
for i in range(self.col_addr_size):
decoder_name = "in_{}".format(i)
addr_name = "addr{0}_{1}".format(port,i)
self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
if port%2:
self.route_column_address_lines_right(port)
offset = self.column_decoder_inst[port].ll() - vector(self.num_col_addr_lines*self.m2_pitch, 0)
else:
self.route_column_address_lines_left(port)
def route_column_address_lines_left(self, port):
""" 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.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):
decode_names.append("out_{}".format(i))
for i in range(self.col_addr_size):
decoder_name = "in_{}".format(i)
addr_name = "addr{0}_{1}".format(port,i)
self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
offset = self.column_decoder_inst[port].lr() + vector(self.m2_pitch, 0)
offset = self.column_decoder_inst[port].lr() + vector(self.m2_pitch, 0)
decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names]
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
column_mux_pins = [self.column_mux_array_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)
route_map = list(zip(decode_names, sel_names))
decode_pins = {key: self.column_decoder_inst[port].get_pin(key) for key in decode_names }
column_mux_pins = {key: self.column_mux_array_inst[port].get_pin(key) for key in sel_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**decode_pins, **column_mux_pins}
self.create_vertical_channel_route(route_map, all_pins, offset)
# def route_column_address_lines_right(self, port):
# """ Connecting the select lines of column mux to the address bus """
# if not self.col_addr_size>0:
# return
def route_column_address_lines_right(self, port):
""" 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:
# if self.col_addr_size == 1:
# Connect to sel[0] and sel[1]
decode_names = ["Zb", "Z"]
# # 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))
# # 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):
decode_names.append("out_{}".format(i))
# elif self.col_addr_size > 1:
# decode_names = []
# for i in range(self.num_col_addr_lines):
# decode_names.append("out_{}".format(i))
for i in range(self.col_addr_size):
decoder_name = "in_{}".format(i)
addr_name = "addr{0}_{1}".format(port,i)
self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
# for i in range(self.col_addr_size):
# decoder_name = "in_{}".format(i)
# addr_name = "addr{0}_{1}".format(port,i)
# self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
offset = self.column_decoder_inst[port].ll() - vector(self.num_col_addr_lines*self.m2_pitch, 0)
# offset = self.column_decoder_inst[port].ll() - vector(self.num_col_addr_lines*self.m2_pitch, 0)
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
# sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
route_map = list(zip(decode_names, sel_names))
decode_pins = {key: self.column_decoder_inst[port].get_pin(key) for key in decode_names }
column_mux_pins = {key: self.column_mux_array_inst[port].get_pin(key) for key in sel_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**decode_pins, **column_mux_pins}
self.create_vertical_channel_route(route_map, all_pins, offset)
# route_map = list(zip(decode_names, sel_names))
# decode_pins = {key: self.column_decoder_inst[port].get_pin(key) for key in decode_names }
# column_mux_pins = {key: self.column_mux_array_inst[port].get_pin(key) for key in sel_names }
# # Combine the dff and bank pins into a single dictionary of pin name to pin.
# all_pins = {**decode_pins, **column_mux_pins}
# self.create_vertical_channel_route(route_map, all_pins, offset)
def add_lvs_correspondence_points(self):

View File

@ -278,17 +278,20 @@ class sram_1bank(sram_base):
""" Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least)
for port in self.write_ports:
offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
if port%2:
offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
else:
offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_insts[port].get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins}
self.create_horizontal_channel_route(route_map, all_pins, offset)
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
route_map = list(zip(bank_pins, dff_pins))
self.create_horizontal_channel_route(route_map, offset)