mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-07 03:20:39 +02:00
Single bank passing DRC and LVS again.
Unfold hierarchical decoder to improve routability.
This commit is contained in:
+19
-49
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user