Single bank passing DRC and LVS again.

Unfold hierarchical decoder to improve routability.
This commit is contained in:
Matt Guthaus
2018-03-23 08:13:10 -07:00
parent b867e163a6
commit 1f81b24e96
10 changed files with 163 additions and 117 deletions
+19 -49
View File
@@ -96,7 +96,6 @@ class bank(design.design):
self.route_tri_gate_out()
self.route_wordline_driver()
self.route_row_decoder()
self.route_address()
self.route_column_address_lines()
self.route_control_lines()
self.add_control_pins()
@@ -174,11 +173,6 @@ class bank(design.design):
# The width of this bus is needed to place other modules (e.g. decoder)
self.central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 1)
# The width of the bus below the decoder to route to the central bus
self.addr_bus_height = self.m1_pitch * (self.addr_size + 1)
@@ -411,7 +405,7 @@ class bank(design.design):
"""
# Place the col decoder aligned left to row decoder
x_off = -(self.central_bus_width + self.row_decoder.width)
y_off = -(self.row_decoder.predecoder_height + self.col_decoder.height + self.addr_bus_height)
y_off = -(self.row_decoder.predecoder_height + self.col_decoder.height + 2*drc["well_to_well"])
self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder,
offset=vector(x_off,y_off))
@@ -460,10 +454,8 @@ class bank(design.design):
offset=self.bank_select_pos)
temp = []
for i in range(self.num_control_lines):
temp.append(self.input_control_signals[i])
for i in range(self.num_control_lines):
temp.append(self.control_signals[i])
temp.extend(self.input_control_signals)
temp.extend(self.control_signals)
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
@@ -475,7 +467,7 @@ class bank(design.design):
layer="metal3",
start=vector(self.left_gnd_x_offset,in_pos.y),
end=in_pos)
for gated_name in self.control_signals:
# Connect the inverter output to the central bus
out_pos = self.bank_select_inst.get_pin(gated_name).rc()
@@ -505,9 +497,7 @@ class bank(design.design):
if self.col_addr_size > 0:
col_decoder_min_point = self.col_decoder_inst.by()
else:
col_decoder_min_point = row_decoder_min_point - self.addr_bus_height
self.addr_min_point = row_decoder_min_point - self.addr_bus_height
col_decoder_min_point = row_decoder_min_point
if self.num_banks>1:
# The control gating logic is below the decoder
@@ -575,11 +565,11 @@ class bank(design.design):
# Make the xoffset map the center of the rail
self.bus_xoffset[name]=x_offset + 0.5*self.m2_width
# Add a label pin for LVS correspondence and visual help inspecting the rail.
self.add_label_pin(text=name,
self.add_layout_pin(text=name,
layer="metal2",
offset=vector(x_offset, self.addr_min_point),
offset=vector(x_offset, self.min_point),
width=self.m2_width,
height=-self.addr_min_point)
height=-self.min_point)
# Column mux lines if there is column mux
# goes from bottom of bitcell array down to the bottom of the column decoder/addresses
@@ -775,11 +765,11 @@ class bank(design.design):
# The Address LSB
decode_in_pin = self.col_decoder_inst.get_pin("A")
pin_pos = vector(self.left_gnd_x_offset, decode_in_pin.cy())
pin_pos = vector(decode_in_pin.cx(), self.min_point)
self.add_layout_pin_center_segment(text="A[0]",
layer="metal1",
layer="metal2",
start=pin_pos,
end=decode_in_pin.lc())
end=decode_in_pin.bc())
elif self.col_addr_size > 1:
# Route the col decoder outputs to the col select bus
@@ -794,14 +784,14 @@ class bank(design.design):
# Route from the col decoder up to the address bus
for i in range(self.col_addr_size):
name = "A[{}]".format(i)
decode_in_pin = self.col_decoder_inst.get_pin("in[{}]".format(i))
addr_pin = self.get_pin(name)
addr_pos = vector(decode_in_pin.cx(), addr_pin.by() + 0.5*self.m1_width)
self.add_path("metal2", [addr_pos, decode_in_pin.uc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=addr_pos,
rotate=90)
decoder_name = "in[{}]".format(i)
addr_name = "A[{}]".format(i)
decode_in_pin = self.col_decoder_inst.get_pin(decoder_name)
pin_pos = vector(decode_in_pin.cx(), self.min_point)
self.add_layout_pin_center_segment(text=addr_name,
layer="metal2",
start=pin_pos,
end=decode_in_pin.bc())
# route the gnd rails, add contact to rail as well
@@ -823,26 +813,6 @@ class bank(design.design):
rotate=90)
def route_address(self):
""" Routing the row address lines from the address ms-flop array to the row-decoder """
for i in range(self.addr_size):
name = "A[{}]".format(i)
address_y_offset = self.addr_min_point + (i+1)*self.m1_pitch
pin_pos = vector(self.left_gnd_x_offset, address_y_offset)
if name in self.bus_xoffset:
rail_pos = vector(self.bus_xoffset[name],pin_pos.y)
else:
# Route to right of col decoder if it's not part of central bus
rail_pos = vector(self.col_decoder_inst.rx(),pin_pos.y)
self.add_layout_pin_center_segment(text=name,
layer="metal1",
start=pin_pos,
end=rail_pos)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=rail_pos,
rotate=90)
def add_lvs_correspondence_points(self):
+6 -10
View File
@@ -21,18 +21,14 @@ class bank_select(design.design):
# Number of control lines in the bus
self.num_control_lines = 6
# The order of the control signals on the control bus:
self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"]
self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"]
# These will be outputs of the gaters if this is multibank
self.control_signals = ["gated_"+str for str in self.input_control_signals]
for i in range(self.num_control_lines):
input_name = self.input_control_signals[i]
self.add_pin(input_name)
for i in range(self.num_control_lines):
gated_name = self.control_signals[i]
self.add_pin(gated_name)
self.add_pin("vdd")
self.add_pin("gnd")
self.add_pin_list(self.input_control_signals, "INPUT")
self.add_pin_list(self.control_signals, "OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
self.create_modules()
self.calculate_module_offsets()
+20 -2
View File
@@ -82,7 +82,7 @@ class control_logic(design.design):
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
#self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
self.input_list =["web","csb","oeb"]
self.input_list =["csb","web","oeb"]
self.input_width = len(self.input_list)*self.m2_pitch
self.input_bar_list = ["clk_buf_bar", "we", "cs", "oe"]
self.input_bar_width = len(self.input_bar_list)*self.m2_pitch
@@ -602,7 +602,7 @@ class control_logic(design.design):
rows_end = self.width
well_width = drc["minwidth_well"]
for i in range(7):
for i in range(8):
if i%2:
name = "vdd"
well_type = "nwell"
@@ -648,6 +648,24 @@ class control_logic(design.design):
start=left,
end=right)
for vdd_pin in self.rbl_inst.get_pins("vdd"):
if vdd_pin.layer != "metal2":
continue
self.add_layout_pin(text="vdd",
layer="metal2",
offset=vdd_pin.ll(),
height=vdd_pin.height(),
width=vdd_pin.width())
for gnd_pin in self.rbl_inst.get_pins("gnd"):
if gnd_pin.layer != "metal2":
continue
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_pin.ll(),
height=gnd_pin.height(),
width=gnd_pin.width())
def add_lvs_correspondence_points(self):
""" This adds some points for easier debugging if LVS goes wrong.
+31 -20
View File
@@ -33,6 +33,9 @@ class hierarchical_decoder(design.design):
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def create_layout(self):
@@ -155,8 +158,8 @@ class hierarchical_decoder(design.design):
self.row_decoder_height = self.inv.height * self.rows
# Calculates height and width of hierarchical decoder
self.height = self.predecoder_height + self.row_decoder_height
self.width = self.predecoder_width + self.routing_width
self.height = self.row_decoder_height
self.width = self.predecoder_width + self.row_decoder_width
def create_pre_decoder(self):
""" Creates pre-decoder and places labels input address [A] """
@@ -171,12 +174,10 @@ class hierarchical_decoder(design.design):
""" Add a 2x4 predecoder """
if (self.num_inputs == 2):
base = vector(self.routing_width,0)
mirror = "RO"
base = vector(-self.pre2_4.width,0)
index_off1 = index_off2 = 0
else:
base= vector(self.routing_width+self.pre2_4.width, num * self.pre2_4.height)
mirror = "MY"
base= vector(-self.pre2_4.width, num * self.pre2_4.height)
index_off1 = num * 2
index_off2 = num * 4
@@ -189,8 +190,7 @@ class hierarchical_decoder(design.design):
self.pre2x4_inst.append(self.add_inst(name="pre[{0}]".format(num),
mod=self.pre2_4,
offset=base,
mirror=mirror))
offset=base))
self.connect_inst(pins)
self.add_pre2x4_pins(num)
@@ -215,12 +215,11 @@ class hierarchical_decoder(design.design):
def add_pre3x8(self,num):
""" Add 3x8 numbered predecoder """
if (self.num_inputs == 3):
offset = vector(self.routing_width,0)
offset = vector(-self.pre_3_8.width,0)
mirror ="R0"
else:
height = self.no_of_pre2x4*self.pre2_4.height + num*self.pre3_8.height
offset = vector(self.routing_width+self.pre3_8.width, height)
mirror="MY"
offset = vector(-self.pre3_8.width, height)
# If we had 2x4 predecodes, those are used as the lower
# decode output bits
@@ -236,8 +235,7 @@ class hierarchical_decoder(design.design):
self.pre3x8_inst.append(self.add_inst(name="pre3x8[{0}]".format(num),
mod=self.pre3_8,
offset=offset,
mirror=mirror))
offset=offset))
self.connect_inst(pins)
# The 3x8 predecoders will be stacked, so use yoffset
@@ -305,11 +303,11 @@ class hierarchical_decoder(design.design):
for row in range(self.rows):
name = "DEC_NAND[{0}]".format(row)
if ((row % 2) == 0):
y_off = self.predecoder_height + nand_mod.height*row
y_off = nand_mod.height*row
y_dir = 1
mirror = "R0"
else:
y_off = self.predecoder_height + nand_mod.height*(row + 1)
y_off = nand_mod.height*(row + 1)
y_dir = -1
mirror = "MX"
@@ -342,7 +340,7 @@ class hierarchical_decoder(design.design):
inv_row_height = self.inv.height * (row + 1)
mirror = "MX"
y_dir = -1
y_off = self.predecoder_height + inv_row_height
y_off = inv_row_height
offset = vector(x_off,y_off)
self.inv_inst.append(self.add_inst(name=name,
@@ -408,7 +406,7 @@ class hierarchical_decoder(design.design):
index = pre_num * 4 + i
out_name = "out[{}]".format(i)
pin = self.pre2x4_inst[pre_num].get_pin(out_name)
self.connect_rail(index, pin)
self.connect_rail_m3(index, pin)
for pre_num in range(self.no_of_pre3x8):
@@ -416,7 +414,7 @@ class hierarchical_decoder(design.design):
index = pre_num * 8 + i + self.no_of_pre2x4 * 4
out_name = "out[{}]".format(i)
pin = self.pre3x8_inst[pre_num].get_pin(out_name)
self.connect_rail(index, pin)
self.connect_rail_m3(index, pin)
@@ -448,11 +446,11 @@ class hierarchical_decoder(design.design):
def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
for num in range(0,self.total_number_of_predecoder_outputs + self.rows):
for num in range(0,self.rows):
# this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num)
(gate_offset, y_dir) = self.get_gate_offset(-self.predecoder_width, self.inv.height, num)
# route vdd
vdd_offset = gate_offset + self.inv.get_pin("vdd").ll().scale(1,y_dir)
self.add_layout_pin(text="vdd",
@@ -478,6 +476,19 @@ class hierarchical_decoder(design.design):
offset=rail_pos,
rotate=90)
def connect_rail_m3(self, rail_index, pin):
""" Connect the routing rail to the given metal1 pin """
mid_point = vector(pin.cx(), pin.cy()-self.inv.height/2)
rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin.center(),
rotate=90)
self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=rail_pos,
rotate=90)
def analytical_delay(self, slew, load = 0.0):
# A -> out
+7 -7
View File
@@ -49,9 +49,8 @@ class hierarchical_predecode(design.design):
debug.error("Invalid number of predecode inputs.",-1)
def setup_constraints(self):
# we are going to use horizontal vias, so use the via height
# use a conservative douple spacing just to get rid of annoying via DRCs
self.m2_pitch = contact.m1m2.height + 2*self.m2_space
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space)
# The rail offsets are indexed by the label
self.rails = {}
@@ -203,11 +202,12 @@ class hierarchical_predecode(design.design):
mid2_pos = vector(0.5*(zr_pos.x+al_pos.x), al_pos.y)
self.add_path("metal1", [zr_pos, mid1_pos, mid2_pos, al_pos])
z_pos = self.inv_inst[num].get_pin("Z").rc()
self.add_layout_pin_center_segment(text="out[{}]".format(num),
layer="metal1",
start=z_pos,
end=z_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(),0))
z_pin = self.inv_inst[num].get_pin("Z")
self.add_layout_pin(text="out[{}]".format(num),
layer="metal1",
offset=z_pin.ll(),
height=z_pin.height(),
width=z_pin.width())
def route_input_inverters(self):