mirror of https://github.com/VLSIDA/OpenRAM.git
Convert channel router to take netlist of pins rather than names.
This commit is contained in:
parent
a7bc9e0de0
commit
4df862d8af
|
|
@ -745,13 +745,14 @@ class layout(lef.lef):
|
||||||
self.add_wire(layer_stack, [pin.center(), mid, trunk_mid])
|
self.add_wire(layer_stack, [pin.center(), mid, trunk_mid])
|
||||||
|
|
||||||
|
|
||||||
def create_channel_route(self, netlist, pins, offset,
|
def create_channel_route(self, netlist,
|
||||||
layer_stack=("metal1", "via1", "metal2"), pitch=None,
|
offset,
|
||||||
|
layer_stack=("metal1", "via1", "metal2"),
|
||||||
|
pitch=None,
|
||||||
vertical=False):
|
vertical=False):
|
||||||
"""
|
"""
|
||||||
The net list is a list of the nets. Each net is a list of pin
|
The net list is a list of the nets. Each net is a list of pins
|
||||||
names to be connected. Pins is a dictionary of the pin names
|
to be connected. Offset is the lower-left of where the
|
||||||
to the pin structures. Offset is the lower-left of where the
|
|
||||||
routing channel will start. This does NOT try to minimize the
|
routing channel will start. This does NOT try to minimize the
|
||||||
number of tracks -- instead, it picks an order to avoid the
|
number of tracks -- instead, it picks an order to avoid the
|
||||||
vertical conflicts between pins.
|
vertical conflicts between pins.
|
||||||
|
|
@ -786,7 +787,10 @@ class layout(lef.lef):
|
||||||
|
|
||||||
def vcg_pin_overlap(pin1, pin2, vertical):
|
def vcg_pin_overlap(pin1, pin2, vertical):
|
||||||
""" Check for vertical or horizontal overlap of the two pins """
|
""" 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
|
# Pin 1 must be in the "BOTTOM" set
|
||||||
x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x-pin2.center().x)<pitch
|
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:
|
for pin_list in netlist:
|
||||||
net_name = "n{}".format(index)
|
net_name = "n{}".format(index)
|
||||||
index += 1
|
index += 1
|
||||||
nets[net_name] = []
|
nets[net_name] = pin_list
|
||||||
for pin_name in pin_list:
|
|
||||||
pin = pins[pin_name]
|
|
||||||
nets[net_name].append(pin)
|
|
||||||
|
|
||||||
# Find the vertical pin conflicts
|
# Find the vertical pin conflicts
|
||||||
# FIXME: O(n^2) but who cares for now
|
# FIXME: O(n^2) but who cares for now
|
||||||
|
|
@ -868,23 +869,21 @@ class layout(lef.lef):
|
||||||
offset += vector(0,pitch)
|
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"),
|
layer_stack=("metal1", "via1", "metal2"),
|
||||||
pitch=None):
|
pitch=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a vertical channel route
|
Wrapper to create a vertical channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, pins, offset, layer_stack,
|
self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=True)
|
||||||
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"),
|
layer_stack=("metal1", "via1", "metal2"),
|
||||||
pitch=None):
|
pitch=None):
|
||||||
"""
|
"""
|
||||||
Wrapper to create a horizontal channel route
|
Wrapper to create a horizontal channel route
|
||||||
"""
|
"""
|
||||||
self.create_channel_route(netlist, pins, offset,
|
self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=False)
|
||||||
layer_stack, pitch, vertical=False)
|
|
||||||
|
|
||||||
def add_enclosure(self, insts, layer="nwell"):
|
def add_enclosure(self, insts, layer="nwell"):
|
||||||
""" Add a layer that surrounds the given instances. Useful
|
""" Add a layer that surrounds the given instances. Useful
|
||||||
|
|
|
||||||
|
|
@ -907,6 +907,9 @@ class bank(design.design):
|
||||||
inst1 = self.bitcell_array_inst
|
inst1 = self.bitcell_array_inst
|
||||||
inst1_bl_name = self.bl_names[port]+"_{}"
|
inst1_bl_name = self.bl_names[port]+"_{}"
|
||||||
inst1_br_name = self.br_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,
|
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
|
||||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
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_bl_name = "bl_{}"
|
||||||
inst1_br_name = "br_{}"
|
inst1_br_name = "br_{}"
|
||||||
|
|
||||||
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
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)
|
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||||
|
|
||||||
def route_write_driver_to_column_mux_or_bitcell_array(self, port):
|
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 """
|
""" 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]
|
inst1 = self.write_driver_array_inst[port]
|
||||||
inst2 = self.sense_amp_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):
|
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!
|
# 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)
|
offset = bottom_inst.ul() + vector(0,self.m1_pitch)
|
||||||
for bit in range(num_bits):
|
for bit in range(num_bits):
|
||||||
bottom_names = [bottom_bl_name.format(bit), bottom_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_bl_name.format(bit), top_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))
|
route_map = list(zip(bottom_names, top_names))
|
||||||
bottom_pins = {key: bottom_inst.get_pin(key) for key in bottom_names }
|
self.create_horizontal_channel_route(route_map, offset)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
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)
|
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])
|
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):
|
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:
|
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:
|
else:
|
||||||
self.route_column_address_lines_left(port)
|
offset = self.column_decoder_inst[port].lr() + vector(self.m2_pitch, 0)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
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)]
|
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))
|
# def route_column_address_lines_right(self, port):
|
||||||
decode_pins = {key: self.column_decoder_inst[port].get_pin(key) for key in decode_names }
|
# """ Connecting the select lines of column mux to the address bus """
|
||||||
column_mux_pins = {key: self.column_mux_array_inst[port].get_pin(key) for key in sel_names }
|
# if not self.col_addr_size>0:
|
||||||
# Combine the dff and bank pins into a single dictionary of pin name to pin.
|
# return
|
||||||
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):
|
# if self.col_addr_size == 1:
|
||||||
""" 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]
|
# # Connect to sel[0] and sel[1]
|
||||||
decode_names = ["Zb", "Z"]
|
# decode_names = ["Zb", "Z"]
|
||||||
|
|
||||||
# The Address LSB
|
# # The Address LSB
|
||||||
self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port))
|
# self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port))
|
||||||
|
|
||||||
elif self.col_addr_size > 1:
|
# elif self.col_addr_size > 1:
|
||||||
decode_names = []
|
# decode_names = []
|
||||||
for i in range(self.num_col_addr_lines):
|
# for i in range(self.num_col_addr_lines):
|
||||||
decode_names.append("out_{}".format(i))
|
# decode_names.append("out_{}".format(i))
|
||||||
|
|
||||||
for i in range(self.col_addr_size):
|
# for i in range(self.col_addr_size):
|
||||||
decoder_name = "in_{}".format(i)
|
# decoder_name = "in_{}".format(i)
|
||||||
addr_name = "addr{0}_{1}".format(port,i)
|
# addr_name = "addr{0}_{1}".format(port,i)
|
||||||
self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
|
# 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))
|
# route_map = list(zip(decode_names, sel_names))
|
||||||
decode_pins = {key: self.column_decoder_inst[port].get_pin(key) for key in decode_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 }
|
# 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.
|
# # Combine the dff and bank pins into a single dictionary of pin name to pin.
|
||||||
all_pins = {**decode_pins, **column_mux_pins}
|
# all_pins = {**decode_pins, **column_mux_pins}
|
||||||
self.create_vertical_channel_route(route_map, all_pins, offset)
|
# self.create_vertical_channel_route(route_map, all_pins, offset)
|
||||||
|
|
||||||
|
|
||||||
def add_lvs_correspondence_points(self):
|
def add_lvs_correspondence_points(self):
|
||||||
|
|
|
||||||
|
|
@ -278,17 +278,20 @@ class sram_1bank(sram_base):
|
||||||
""" Connect the output of the data flops to the write driver """
|
""" Connect the output of the data flops to the write driver """
|
||||||
# This is where the channel will start (y-dimension at least)
|
# This is where the channel will start (y-dimension at least)
|
||||||
for port in self.write_ports:
|
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_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)]
|
bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
|
||||||
|
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||||
route_map = list(zip(bank_names, dff_names))
|
|
||||||
dff_pins = {key: self.data_dff_insts[port].get_pin(key) for key in dff_names }
|
route_map = list(zip(bank_pins, dff_pins))
|
||||||
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
|
self.create_horizontal_channel_route(route_map, offset)
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue