mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into laptop_checkpoint
This commit is contained in:
commit
0ba229afe5
|
|
@ -112,18 +112,22 @@ class lef:
|
||||||
for pin_name in self.pins:
|
for pin_name in self.pins:
|
||||||
pin = self.get_pin(pin_name)
|
pin = self.get_pin(pin_name)
|
||||||
inflated_pin = pin.inflated_pin(multiple=1)
|
inflated_pin = pin.inflated_pin(multiple=1)
|
||||||
for blockage in self.blockages[pin.layer]:
|
another_iteration_needed = True
|
||||||
if blockage.overlaps(inflated_pin):
|
while another_iteration_needed:
|
||||||
intersection_shape = blockage.intersection(inflated_pin)
|
another_iteration_needed = False
|
||||||
# If it is zero area, don't add the pin
|
old_blockages = list(self.blockages[pin.layer])
|
||||||
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
|
for blockage in old_blockages:
|
||||||
continue
|
if blockage.overlaps(inflated_pin):
|
||||||
# Remove the old blockage and add the new ones
|
intersection_shape = blockage.intersection(inflated_pin)
|
||||||
self.blockages[pin.layer].remove(blockage)
|
# If it is zero area, don't add the pin
|
||||||
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
|
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
|
||||||
new_blockages = blockage.cut(intersection_pin)
|
continue
|
||||||
self.blockages[pin.layer].extend(new_blockages)
|
another_iteration_needed = True
|
||||||
|
# Remove the old blockage and add the new ones
|
||||||
|
self.blockages[pin.layer].remove(blockage)
|
||||||
|
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
|
||||||
|
new_blockages = blockage.cut(intersection_pin)
|
||||||
|
self.blockages[pin.layer].extend(new_blockages)
|
||||||
|
|
||||||
def lef_write_header(self):
|
def lef_write_header(self):
|
||||||
""" Header of LEF file """
|
""" Header of LEF file """
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ class verilog:
|
||||||
self.vf.write("\n")
|
self.vf.write("\n")
|
||||||
|
|
||||||
self.vf.write("module {0}(\n".format(self.name))
|
self.vf.write("module {0}(\n".format(self.name))
|
||||||
|
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||||
|
self.vf.write(" vdd,\n")
|
||||||
|
self.vf.write(" gnd,\n")
|
||||||
|
self.vf.write("`endif\n")
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
if port in self.readwrite_ports:
|
if port in self.readwrite_ports:
|
||||||
self.vf.write("// Port {0}: RW\n".format(port))
|
self.vf.write("// Port {0}: RW\n".format(port))
|
||||||
|
|
@ -65,6 +70,11 @@ class verilog:
|
||||||
self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n")
|
self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n")
|
||||||
self.vf.write("\n")
|
self.vf.write("\n")
|
||||||
|
|
||||||
|
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||||
|
self.vf.write(" inout vdd;\n")
|
||||||
|
self.vf.write(" inout gnd;\n")
|
||||||
|
self.vf.write("`endif\n")
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.add_inputs_outputs(port)
|
self.add_inputs_outputs(port)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ process_corners = ["TT"]
|
||||||
supply_voltages = [5.0]
|
supply_voltages = [5.0]
|
||||||
temperatures = [25]
|
temperatures = [25]
|
||||||
|
|
||||||
route_supplies = True
|
route_supplies = "side"
|
||||||
check_lvsdrc = True
|
check_lvsdrc = True
|
||||||
|
|
||||||
output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports,
|
output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports,
|
||||||
|
|
|
||||||
|
|
@ -426,7 +426,8 @@ class VlsiLayout:
|
||||||
self.structures[self.rootStructureName].texts.append(textToAdd)
|
self.structures[self.rootStructureName].texts.append(textToAdd)
|
||||||
|
|
||||||
def padText(self, text):
|
def padText(self, text):
|
||||||
if(len(text)%2 == 1):
|
debug.check(len(text) > 0, "Cannot have zero length text string.")
|
||||||
|
if(len(text) % 2 == 1):
|
||||||
return text + '\x00'
|
return text + '\x00'
|
||||||
else:
|
else:
|
||||||
return text
|
return text
|
||||||
|
|
@ -700,7 +701,6 @@ class VlsiLayout:
|
||||||
|
|
||||||
return max_pins
|
return max_pins
|
||||||
|
|
||||||
|
|
||||||
def getAllPinShapes(self, pin_name):
|
def getAllPinShapes(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,11 @@ class bank(design.design):
|
||||||
self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1)
|
self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1)
|
||||||
self.bank_array_ur = self.bitcell_array_inst.ur()
|
self.bank_array_ur = self.bitcell_array_inst.ur()
|
||||||
self.bank_array_ul = self.bitcell_array_inst.ul()
|
self.bank_array_ul = self.bitcell_array_inst.ul()
|
||||||
|
|
||||||
|
# These are used for other placements (e.g. address flops)
|
||||||
|
self.predecoder_top = self.port_address[0].predecoder_height + self.port_address_inst[0].by()
|
||||||
|
self.predecoder_bottom = self.port_address_inst[0].by()
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
@ -227,7 +232,6 @@ class bank(design.design):
|
||||||
x_offset = self.m2_gap + self.port_address[port].width
|
x_offset = self.m2_gap + self.port_address[port].width
|
||||||
self.port_address_offsets[port] = vector(-x_offset,
|
self.port_address_offsets[port] = vector(-x_offset,
|
||||||
self.main_bitcell_array_bottom)
|
self.main_bitcell_array_bottom)
|
||||||
self.predecoder_height = self.port_address[port].predecoder_height + self.port_address_offsets[port].y
|
|
||||||
|
|
||||||
# LOWER LEFT QUADRANT
|
# LOWER LEFT QUADRANT
|
||||||
# Place the col decoder left aligned with wordline driver
|
# Place the col decoder left aligned with wordline driver
|
||||||
|
|
|
||||||
|
|
@ -346,9 +346,12 @@ class control_logic(design.design):
|
||||||
row += 1
|
row += 1
|
||||||
self.place_wlen_row(row)
|
self.place_wlen_row(row)
|
||||||
row += 1
|
row += 1
|
||||||
self.place_delay(row)
|
|
||||||
|
control_center_y = self.wl_en_inst.uy() + self.m3_pitch
|
||||||
|
|
||||||
|
# Delay chain always gets placed at row 4
|
||||||
|
self.place_delay(4)
|
||||||
height = self.delay_inst.uy()
|
height = self.delay_inst.uy()
|
||||||
control_center_y = self.delay_inst.by()
|
|
||||||
|
|
||||||
# This offset is used for placement of the control logic in the SRAM level.
|
# This offset is used for placement of the control logic in the SRAM level.
|
||||||
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
|
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
|
||||||
|
|
@ -387,19 +390,22 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def place_delay(self, row):
|
def place_delay(self, row):
|
||||||
""" Place the replica bitline """
|
""" Place the replica bitline """
|
||||||
y_off = row * self.and2.height + 2 * self.m1_pitch
|
debug.check(row % 2 == 0, "Must place delay chain at even row for supply alignment.")
|
||||||
|
|
||||||
|
# It is flipped on X axis
|
||||||
|
y_off = row * self.and2.height + self.delay_chain.height
|
||||||
|
|
||||||
# Add the RBL above the rows
|
# Add the RBL above the rows
|
||||||
# Add to the right of the control rows and routing channel
|
# Add to the right of the control rows and routing channel
|
||||||
offset = vector(self.delay_chain.width, y_off)
|
offset = vector(0, y_off)
|
||||||
self.delay_inst.place(offset, mirror="MY")
|
self.delay_inst.place(offset, mirror="MX")
|
||||||
|
|
||||||
def route_delay(self):
|
def route_delay(self):
|
||||||
|
|
||||||
out_pos = self.delay_inst.get_pin("out").bc()
|
out_pos = self.delay_inst.get_pin("out").center()
|
||||||
# Connect to the rail level with the vdd rail
|
# Connect to the rail level with the vdd rail
|
||||||
# Use pen since it is in every type of control logic
|
# Use gated clock since it is in every type of control logic
|
||||||
vdd_ypos = self.p_en_bar_nand_inst.get_pin("vdd").by()
|
vdd_ypos = self.gated_clk_buf_inst.get_pin("vdd").cy() + self.m1_pitch
|
||||||
in_pos = vector(self.input_bus["rbl_bl_delay"].cx(), vdd_ypos)
|
in_pos = vector(self.input_bus["rbl_bl_delay"].cx(), vdd_ypos)
|
||||||
mid1 = vector(out_pos.x, in_pos.y)
|
mid1 = vector(out_pos.x, in_pos.y)
|
||||||
self.add_wire(self.m1_stack, [out_pos, mid1, in_pos])
|
self.add_wire(self.m1_stack, [out_pos, mid1, in_pos])
|
||||||
|
|
@ -676,7 +682,7 @@ class control_logic(design.design):
|
||||||
# Connect the clock rail to the other clock rail
|
# Connect the clock rail to the other clock rail
|
||||||
# by routing in the supply rail track to avoid channel conflicts
|
# by routing in the supply rail track to avoid channel conflicts
|
||||||
in_pos = self.ctrl_dff_inst.get_pin("clk").uc()
|
in_pos = self.ctrl_dff_inst.get_pin("clk").uc()
|
||||||
mid_pos = in_pos + vector(0, self.and2.height)
|
mid_pos = vector(in_pos.x, self.gated_clk_buf_inst.get_pin("vdd").cy() - self.m1_pitch)
|
||||||
rail_pos = vector(self.input_bus["clk_buf"].cx(), mid_pos.y)
|
rail_pos = vector(self.input_bus["clk_buf"].cx(), mid_pos.y)
|
||||||
self.add_wire(self.m1_stack, [in_pos, mid_pos, rail_pos])
|
self.add_wire(self.m1_stack, [in_pos, mid_pos, rail_pos])
|
||||||
self.add_via_center(layers=self.m1_stack,
|
self.add_via_center(layers=self.m1_stack,
|
||||||
|
|
@ -794,3 +800,8 @@ class control_logic(design.design):
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=out_pos)
|
offset=out_pos)
|
||||||
|
|
||||||
|
def get_left_pins(self, name):
|
||||||
|
"""
|
||||||
|
Return the left side supply pins to connect to a vertical stripe.
|
||||||
|
"""
|
||||||
|
return(self.cntrl_dff_inst.get_pins(name) + self.delay_inst.get_pins(name))
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
# number of inverters including any fanout loads.
|
# number of inverters including any fanout loads.
|
||||||
self.fanout_list = fanout_list
|
self.fanout_list = fanout_list
|
||||||
|
self.rows = len(self.fanout_list)
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
|
|
@ -43,7 +44,7 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
# Each stage is a a row
|
# Each stage is a a row
|
||||||
self.height = len(self.fanout_list) * self.inv.height
|
self.height = self.rows * self.inv.height
|
||||||
# The width is determined by the largest fanout plus the driver
|
# The width is determined by the largest fanout plus the driver
|
||||||
self.width = (max(self.fanout_list) + 1) * self.inv.width
|
self.width = (max(self.fanout_list) + 1) * self.inv.width
|
||||||
|
|
||||||
|
|
@ -62,14 +63,19 @@ class delay_chain(design.design):
|
||||||
self.add_pin("gnd", "GROUND")
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.inv = factory.create(module_type="pinv")
|
|
||||||
|
self.dff = factory.create(module_type="dff_buf")
|
||||||
|
dff_height = self.dff.height
|
||||||
|
|
||||||
|
self.inv = factory.create(module_type="pinv",
|
||||||
|
height=dff_height)
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
def create_inverters(self):
|
def create_inverters(self):
|
||||||
""" Create the inverters and connect them based on the stage list """
|
""" Create the inverters and connect them based on the stage list """
|
||||||
self.driver_inst_list = []
|
self.driver_inst_list = []
|
||||||
self.load_inst_map = {}
|
self.load_inst_map = {}
|
||||||
for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list):
|
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
|
||||||
# Add the inverter
|
# Add the inverter
|
||||||
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
|
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
|
||||||
mod=self.inv)
|
mod=self.inv)
|
||||||
|
|
@ -77,7 +83,7 @@ class delay_chain(design.design):
|
||||||
self.driver_inst_list.append(cur_driver)
|
self.driver_inst_list.append(cur_driver)
|
||||||
|
|
||||||
# Hook up the driver
|
# Hook up the driver
|
||||||
if stage_num + 1 == len(self.fanout_list):
|
if stage_num + 1 == self.rows:
|
||||||
stageout_name = "out"
|
stageout_name = "out"
|
||||||
else:
|
else:
|
||||||
stageout_name = "dout_{}".format(stage_num + 1)
|
stageout_name = "dout_{}".format(stage_num + 1)
|
||||||
|
|
@ -101,7 +107,7 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
def place_inverters(self):
|
def place_inverters(self):
|
||||||
""" Place the inverters and connect them based on the stage list """
|
""" Place the inverters and connect them based on the stage list """
|
||||||
for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list):
|
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
|
||||||
if stage_num % 2:
|
if stage_num % 2:
|
||||||
inv_mirror = "MX"
|
inv_mirror = "MX"
|
||||||
inv_offset = vector(0, (stage_num + 1) * self.inv.height)
|
inv_offset = vector(0, (stage_num + 1) * self.inv.height)
|
||||||
|
|
@ -185,24 +191,26 @@ class delay_chain(design.design):
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
# input is A pin of first inverter
|
# input is A pin of first inverter
|
||||||
|
# It gets routed to the left a bit to prevent pin access errors
|
||||||
|
# due to the output pin when going up to M3
|
||||||
a_pin = self.driver_inst_list[0].get_pin("A")
|
a_pin = self.driver_inst_list[0].get_pin("A")
|
||||||
|
mid_loc = vector(a_pin.cx() - self.m3_pitch, a_pin.cy())
|
||||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=a_pin.center())
|
offset=mid_loc)
|
||||||
self.add_layout_pin(text="in",
|
self.add_path(a_pin.layer, [a_pin.center(), mid_loc])
|
||||||
layer="m2",
|
|
||||||
offset=a_pin.ll().scale(1, 0),
|
|
||||||
height=a_pin.cy())
|
|
||||||
|
|
||||||
# output is A pin of last load inverter
|
self.add_layout_pin_rect_center(text="in",
|
||||||
|
layer="m2",
|
||||||
|
offset=mid_loc)
|
||||||
|
|
||||||
|
# output is A pin of last load/fanout inverter
|
||||||
last_driver_inst = self.driver_inst_list[-1]
|
last_driver_inst = self.driver_inst_list[-1]
|
||||||
a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A")
|
a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A")
|
||||||
self.add_via_stack_center(from_layer=a_pin.layer,
|
self.add_via_stack_center(from_layer=a_pin.layer,
|
||||||
to_layer="m2",
|
to_layer="m1",
|
||||||
offset=a_pin.center())
|
offset=a_pin.center())
|
||||||
mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy())
|
self.add_layout_pin_rect_center(text="out",
|
||||||
self.add_path("m2", [a_pin.center(), mid_point, mid_point.scale(1, 0)])
|
layer="m1",
|
||||||
self.add_layout_pin_segment_center(text="out",
|
offset=a_pin.center())
|
||||||
layer="m2",
|
|
||||||
start=mid_point,
|
|
||||||
end=mid_point.scale(1, 0))
|
|
||||||
|
|
|
||||||
|
|
@ -122,34 +122,44 @@ class grid:
|
||||||
self.set_target(n)
|
self.set_target(n)
|
||||||
# self.set_blocked(n, False)
|
# self.set_blocked(n, False)
|
||||||
|
|
||||||
def add_perimeter_target(self, side="all"):
|
def get_perimeter_list(self, side="left", layers=[0, 1], width=1, margin=0, offset=0):
|
||||||
debug.info(3, "Adding perimeter target")
|
"""
|
||||||
|
Side specifies which side.
|
||||||
|
Layer specifies horizontal (0) or vertical (1)
|
||||||
|
Width specifies how wide the perimter "stripe" should be.
|
||||||
|
"""
|
||||||
perimeter_list = []
|
perimeter_list = []
|
||||||
# Add the left/right columns
|
# Add the left/right columns
|
||||||
if side=="all" or side=="left":
|
if side=="all" or side=="left":
|
||||||
x = self.ll.x
|
for x in range(self.ll.x + offset, self.ll.x + width + offset, 1):
|
||||||
for y in range(self.ll.y, self.ur.y, 1):
|
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
|
||||||
perimeter_list.append(vector3d(x, y, 0))
|
for layer in layers:
|
||||||
perimeter_list.append(vector3d(x, y, 1))
|
perimeter_list.append(vector3d(x, y, layer))
|
||||||
|
|
||||||
if side=="all" or side=="right":
|
if side=="all" or side=="right":
|
||||||
x = self.ur.x
|
for x in range(self.ur.x - width - offset, self.ur.x - offset, 1):
|
||||||
for y in range(self.ll.y, self.ur.y, 1):
|
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
|
||||||
perimeter_list.append(vector3d(x, y, 0))
|
for layer in layers:
|
||||||
perimeter_list.append(vector3d(x, y, 1))
|
perimeter_list.append(vector3d(x, y, layer))
|
||||||
|
|
||||||
if side=="all" or side=="bottom":
|
if side=="all" or side=="bottom":
|
||||||
y = self.ll.y
|
for y in range(self.ll.y + offset, self.ll.y + width + offset, 1):
|
||||||
for x in range(self.ll.x, self.ur.x, 1):
|
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
|
||||||
perimeter_list.append(vector3d(x, y, 0))
|
for layer in layers:
|
||||||
perimeter_list.append(vector3d(x, y, 1))
|
perimeter_list.append(vector3d(x, y, layer))
|
||||||
|
|
||||||
if side=="all" or side=="top":
|
if side=="all" or side=="top":
|
||||||
y = self.ur.y
|
for y in range(self.ur.y - width - offset, self.ur.y - offset, 1):
|
||||||
for x in range(self.ll.x, self.ur.x, 1):
|
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
|
||||||
perimeter_list.append(vector3d(x, y, 0))
|
for layer in layers:
|
||||||
perimeter_list.append(vector3d(x, y, 1))
|
perimeter_list.append(vector3d(x, y, layer))
|
||||||
|
|
||||||
|
return perimeter_list
|
||||||
|
|
||||||
|
def add_perimeter_target(self, side="all", layers=[0, 1]):
|
||||||
|
debug.info(3, "Adding perimeter target")
|
||||||
|
|
||||||
|
perimeter_list = self.get_perimeter_list(side, layers)
|
||||||
|
|
||||||
self.set_target(perimeter_list)
|
self.set_target(perimeter_list)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,10 @@ class pin_group:
|
||||||
# Now simplify the enclosure list
|
# Now simplify the enclosure list
|
||||||
new_pin_list = self.remove_redundant_shapes(pin_list)
|
new_pin_list = self.remove_redundant_shapes(pin_list)
|
||||||
|
|
||||||
|
# Now add the right name
|
||||||
|
for pin in new_pin_list:
|
||||||
|
pin.name = self.name
|
||||||
|
|
||||||
debug.check(len(new_pin_list) > 0,
|
debug.check(len(new_pin_list) > 0,
|
||||||
"Did not find any enclosures.")
|
"Did not find any enclosures.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class router(router_tech):
|
||||||
route on a given layer. This is limited to two layer routes.
|
route on a given layer. This is limited to two layer routes.
|
||||||
It populates blockages on a grid class.
|
It populates blockages on a grid class.
|
||||||
"""
|
"""
|
||||||
def __init__(self, layers, design, gds_filename=None, bbox=None, margin=0, route_track_width=1):
|
def __init__(self, layers, design, bbox=None, margin=0, route_track_width=1):
|
||||||
"""
|
"""
|
||||||
This will instantiate a copy of the gds file or the module at (0,0) and
|
This will instantiate a copy of the gds file or the module at (0,0) and
|
||||||
route on top of this. The blockages from the gds/module will be
|
route on top of this. The blockages from the gds/module will be
|
||||||
|
|
@ -39,19 +39,7 @@ class router(router_tech):
|
||||||
|
|
||||||
self.cell = design
|
self.cell = design
|
||||||
|
|
||||||
# If didn't specify a gds blockage file, write it out to read the gds
|
self.gds_filename = OPTS.openram_temp + "temp.gds"
|
||||||
# This isn't efficient, but easy for now
|
|
||||||
# start_time = datetime.now()
|
|
||||||
if not gds_filename:
|
|
||||||
gds_filename = OPTS.openram_temp+"temp.gds"
|
|
||||||
self.cell.gds_write(gds_filename)
|
|
||||||
|
|
||||||
# Load the gds file and read in all the shapes
|
|
||||||
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
|
||||||
self.reader = gdsMill.Gds2reader(self.layout)
|
|
||||||
self.reader.loadFromFile(gds_filename)
|
|
||||||
self.top_name = self.layout.rootStructureName
|
|
||||||
# print_time("GDS read",datetime.now(), start_time)
|
|
||||||
|
|
||||||
# The pin data structures
|
# The pin data structures
|
||||||
# A map of pin names to a set of pin_layout structures
|
# A map of pin names to a set of pin_layout structures
|
||||||
|
|
@ -91,6 +79,16 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Initialize the ll,ur values with the paramter or using the layout boundary.
|
Initialize the ll,ur values with the paramter or using the layout boundary.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# If didn't specify a gds blockage file, write it out to read the gds
|
||||||
|
# This isn't efficient, but easy for now
|
||||||
|
# Load the gds file and read in all the shapes
|
||||||
|
self.cell.gds_write(self.gds_filename)
|
||||||
|
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||||
|
self.reader = gdsMill.Gds2reader(self.layout)
|
||||||
|
self.reader.loadFromFile(self.gds_filename)
|
||||||
|
self.top_name = self.layout.rootStructureName
|
||||||
|
|
||||||
if not bbox:
|
if not bbox:
|
||||||
# The boundary will determine the limits to the size
|
# The boundary will determine the limits to the size
|
||||||
# of the routing grid
|
# of the routing grid
|
||||||
|
|
@ -178,6 +176,17 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Find the pins and blockages in the design
|
Find the pins and blockages in the design
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# If didn't specify a gds blockage file, write it out to read the gds
|
||||||
|
# This isn't efficient, but easy for now
|
||||||
|
# Load the gds file and read in all the shapes
|
||||||
|
self.cell.gds_write(self.gds_filename)
|
||||||
|
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||||
|
self.reader = gdsMill.Gds2reader(self.layout)
|
||||||
|
self.reader.loadFromFile(self.gds_filename)
|
||||||
|
self.top_name = self.layout.rootStructureName
|
||||||
|
# print_time("GDS read",datetime.now(), start_time)
|
||||||
|
|
||||||
# This finds the pin shapes and sorts them into "groups" that
|
# This finds the pin shapes and sorts them into "groups" that
|
||||||
# are connected. This must come before the blockages, so we
|
# are connected. This must come before the blockages, so we
|
||||||
# can not count the pins themselves
|
# can not count the pins themselves
|
||||||
|
|
@ -881,6 +890,26 @@ class router(router_tech):
|
||||||
# Clearing the blockage of this pin requires the inflated pins
|
# Clearing the blockage of this pin requires the inflated pins
|
||||||
self.clear_blockages(pin_name)
|
self.clear_blockages(pin_name)
|
||||||
|
|
||||||
|
def add_side_supply_pin(self, name, side="left", width=2):
|
||||||
|
"""
|
||||||
|
Adds a supply pin to the perimeter and resizes the bounding box.
|
||||||
|
"""
|
||||||
|
pg = pin_group(name, [], self)
|
||||||
|
if name == "vdd":
|
||||||
|
offset = width
|
||||||
|
else:
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
pg.grids = set(self.rg.get_perimeter_list(side=side,
|
||||||
|
width=width,
|
||||||
|
margin=self.margin,
|
||||||
|
offset=offset,
|
||||||
|
layers=[1]))
|
||||||
|
pg.enclosures = pg.compute_enclosures()
|
||||||
|
pg.pins = set(pg.enclosures)
|
||||||
|
self.cell.pin_map[name].update(pg.pins)
|
||||||
|
self.pin_groups[name].append(pg)
|
||||||
|
|
||||||
def add_perimeter_target(self, side="all"):
|
def add_perimeter_target(self, side="all"):
|
||||||
"""
|
"""
|
||||||
This will mark all the cells on the perimeter of the original layout as a target.
|
This will mark all the cells on the perimeter of the original layout as a target.
|
||||||
|
|
@ -1219,7 +1248,7 @@ class router(router_tech):
|
||||||
""" Return the lowest, leftest pin group """
|
""" Return the lowest, leftest pin group """
|
||||||
|
|
||||||
keep_pin = None
|
keep_pin = None
|
||||||
for index,pg in enumerate(self.pin_groups[pin_name]):
|
for index, pg in enumerate(self.pin_groups[pin_name]):
|
||||||
for pin in pg.enclosures:
|
for pin in pg.enclosures:
|
||||||
if not keep_pin:
|
if not keep_pin:
|
||||||
keep_pin = pin
|
keep_pin = pin
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ class router_tech:
|
||||||
|
|
||||||
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
|
||||||
|
|
||||||
min_width = drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
|
min_width = self.route_track_width * drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
|
||||||
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf)
|
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf)
|
||||||
|
|
||||||
return (min_width, min_spacing)
|
return (min_width, min_spacing)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class signal_escape_router(router):
|
||||||
A router that routes signals to perimeter and makes pins.
|
A router that routes signals to perimeter and makes pins.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, layers, design, bbox=None, margin=0, gds_filename=None):
|
def __init__(self, layers, design, bbox=None, margin=0):
|
||||||
"""
|
"""
|
||||||
This will route on layers in design. It will get the blockages from
|
This will route on layers in design. It will get the blockages from
|
||||||
either the gds file name or the design itself (by saving to a gds file).
|
either the gds file name or the design itself (by saving to a gds file).
|
||||||
|
|
@ -25,7 +25,6 @@ class signal_escape_router(router):
|
||||||
router.__init__(self,
|
router.__init__(self,
|
||||||
layers=layers,
|
layers=layers,
|
||||||
design=design,
|
design=design,
|
||||||
gds_filename=gds_filename,
|
|
||||||
bbox=bbox,
|
bbox=bbox,
|
||||||
margin=margin)
|
margin=margin)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ class signal_router(router):
|
||||||
route on a given layer. This is limited to two layer routes.
|
route on a given layer. This is limited to two layer routes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
def __init__(self, layers, design, bbox=None):
|
||||||
"""
|
"""
|
||||||
This will route on layers in design. It will get the blockages from
|
This will route on layers in design. It will get the blockages from
|
||||||
either the gds file name or the design itself (by saving to a gds file).
|
either the gds file name or the design itself (by saving to a gds file).
|
||||||
"""
|
"""
|
||||||
router.__init__(self, layers, design, gds_filename, bbox)
|
router.__init__(self, layers, design, bbox)
|
||||||
|
|
||||||
def route(self, src, dest, detour_scale=5):
|
def route(self, src, dest, detour_scale=5):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class supply_grid_router(router):
|
||||||
routes a grid to connect the supply on the two layers.
|
routes a grid to connect the supply on the two layers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
def __init__(self, layers, design, margin=0, bbox=None):
|
||||||
"""
|
"""
|
||||||
This will route on layers in design. It will get the blockages from
|
This will route on layers in design. It will get the blockages from
|
||||||
either the gds file name or the design itself (by saving to a gds file).
|
either the gds file name or the design itself (by saving to a gds file).
|
||||||
|
|
@ -29,9 +29,9 @@ class supply_grid_router(router):
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
|
||||||
# Power rail width in minimum wire widths
|
# Power rail width in minimum wire widths
|
||||||
self.route_track_width = 2
|
self.route_track_width = 1
|
||||||
|
|
||||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
router.__init__(self, layers, design, bbox=bbox, margin=margin, route_track_width=self.route_track_width)
|
||||||
|
|
||||||
# The list of supply rails (grid sets) that may be routed
|
# The list of supply rails (grid sets) that may be routed
|
||||||
self.supply_rails = {}
|
self.supply_rails = {}
|
||||||
|
|
@ -357,7 +357,8 @@ class supply_grid_router(router):
|
||||||
|
|
||||||
# This is inefficient since it is non-incremental, but it was
|
# This is inefficient since it is non-incremental, but it was
|
||||||
# easier to debug.
|
# easier to debug.
|
||||||
self.prepare_blockages(pin_name)
|
self.prepare_blockages()
|
||||||
|
self.clear_blockages(self.vdd_name)
|
||||||
|
|
||||||
# Add the single component of the pin as the source
|
# Add the single component of the pin as the source
|
||||||
# which unmarks it as a blockage too
|
# which unmarks it as a blockage too
|
||||||
|
|
@ -369,7 +370,7 @@ class supply_grid_router(router):
|
||||||
|
|
||||||
# Actually run the A* router
|
# Actually run the A* router
|
||||||
if not self.run_router(detour_scale=5):
|
if not self.run_router(detour_scale=5):
|
||||||
self.write_debug_gds("debug_route.gds", False)
|
self.write_debug_gds("debug_route.gds")
|
||||||
|
|
||||||
# if index==3 and pin_name=="vdd":
|
# if index==3 and pin_name=="vdd":
|
||||||
# self.write_debug_gds("route.gds",False)
|
# self.write_debug_gds("route.gds",False)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class supply_tree_router(router):
|
||||||
routes a grid to connect the supply on the two layers.
|
routes a grid to connect the supply on the two layers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
def __init__(self, layers, design, bbox=None, side_pin=None):
|
||||||
"""
|
"""
|
||||||
This will route on layers in design. It will get the blockages from
|
This will route on layers in design. It will get the blockages from
|
||||||
either the gds file name or the design itself (by saving to a gds file).
|
either the gds file name or the design itself (by saving to a gds file).
|
||||||
|
|
@ -31,11 +31,19 @@ class supply_tree_router(router):
|
||||||
# for prettier routes.
|
# for prettier routes.
|
||||||
self.route_track_width = 1
|
self.route_track_width = 1
|
||||||
|
|
||||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
# The pin escape router already made the bounding box big enough,
|
||||||
|
# so we can use the regular bbox here.
|
||||||
|
self.side_pin = side_pin
|
||||||
|
router.__init__(self,
|
||||||
|
layers,
|
||||||
|
design,
|
||||||
|
bbox=bbox,
|
||||||
|
route_track_width=self.route_track_width)
|
||||||
|
|
||||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||||
"""
|
"""
|
||||||
Route the two nets in a single layer)
|
Route the two nets in a single layer.
|
||||||
|
Setting pin stripe will make a power rail on the left side.
|
||||||
"""
|
"""
|
||||||
debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
|
||||||
self.vdd_name = vdd_name
|
self.vdd_name = vdd_name
|
||||||
|
|
@ -50,11 +58,17 @@ class supply_tree_router(router):
|
||||||
# but this is simplest for now.
|
# but this is simplest for now.
|
||||||
self.create_routing_grid(signal_grid)
|
self.create_routing_grid(signal_grid)
|
||||||
|
|
||||||
# Get the pin shapes
|
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
|
||||||
|
# Get the pin shapes
|
||||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||||
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
|
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
|
||||||
|
|
||||||
|
# Add side pins if enabled
|
||||||
|
if self.side_pin:
|
||||||
|
self.add_side_supply_pin(self.vdd_name)
|
||||||
|
self.add_side_supply_pin(self.gnd_name)
|
||||||
|
|
||||||
# Route the supply pins to the supply rails
|
# Route the supply pins to the supply rails
|
||||||
# Route vdd first since we want it to be shorter
|
# Route vdd first since we want it to be shorter
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
|
@ -87,16 +101,21 @@ class supply_tree_router(router):
|
||||||
pin_size = len(self.pin_groups[pin_name])
|
pin_size = len(self.pin_groups[pin_name])
|
||||||
adj_matrix = [[0] * pin_size for i in range(pin_size)]
|
adj_matrix = [[0] * pin_size for i in range(pin_size)]
|
||||||
|
|
||||||
for index1,pg1 in enumerate(self.pin_groups[pin_name]):
|
for index1, pg1 in enumerate(self.pin_groups[pin_name]):
|
||||||
for index2,pg2 in enumerate(self.pin_groups[pin_name]):
|
for index2, pg2 in enumerate(self.pin_groups[pin_name]):
|
||||||
if index1>=index2:
|
if index1>=index2:
|
||||||
continue
|
continue
|
||||||
dist = int(grid_utils.distance_set(list(pg1.grids)[0], pg2.grids))
|
dist = int(grid_utils.distance_set(list(pg1.grids)[0], pg2.grids))
|
||||||
adj_matrix[index1][index2] = dist
|
adj_matrix[index1][index2] = dist
|
||||||
|
|
||||||
# Find MST
|
# Find MST
|
||||||
debug.info(2, "Finding MinimumSpanning Tree")
|
debug.info(2, "Finding Minimum Spanning Tree")
|
||||||
X = csr_matrix(adj_matrix)
|
X = csr_matrix(adj_matrix)
|
||||||
|
from scipy.sparse import save_npz
|
||||||
|
#print("Saving {}.npz".format(self.cell.name))
|
||||||
|
#save_npz("{}.npz".format(self.cell.name), X)
|
||||||
|
#exit(1)
|
||||||
|
|
||||||
Tcsr = minimum_spanning_tree(X)
|
Tcsr = minimum_spanning_tree(X)
|
||||||
mst = Tcsr.toarray().astype(int)
|
mst = Tcsr.toarray().astype(int)
|
||||||
connections = []
|
connections = []
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,9 @@ class sram_1bank(sram_base):
|
||||||
port = 0
|
port = 0
|
||||||
# The row address bits are placed above the control logic aligned on the right.
|
# The row address bits are placed above the control logic aligned on the right.
|
||||||
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
|
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
|
||||||
# It is above the control logic but below the top of the bitcell array
|
# It is above the control logic and the predecoder array
|
||||||
y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_height)
|
y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_top)
|
||||||
|
|
||||||
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(self.row_addr_pos[port])
|
self.row_addr_dff_insts[port].place(self.row_addr_pos[port])
|
||||||
|
|
||||||
|
|
@ -130,7 +131,7 @@ class sram_1bank(sram_base):
|
||||||
# The row address bits are placed above the control logic aligned on the left.
|
# The row address bits are placed above the control logic aligned on the left.
|
||||||
x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
||||||
# If it can be placed above the predecoder and below the control logic, do it
|
# If it can be placed above the predecoder and below the control logic, do it
|
||||||
y_offset = self.bank.bank_array_ll.y
|
y_offset = self.bank.predecoder_bottom
|
||||||
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")
|
self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")
|
||||||
|
|
||||||
|
|
@ -419,11 +420,11 @@ class sram_1bank(sram_base):
|
||||||
if len(route_map) > 0:
|
if len(route_map) > 0:
|
||||||
|
|
||||||
# The write masks will have blockages on M1
|
# The write masks will have blockages on M1
|
||||||
if self.num_wmasks > 0 and port in self.write_ports:
|
# if self.num_wmasks > 0 and port in self.write_ports:
|
||||||
layer_stack = self.m3_stack
|
# layer_stack = self.m3_stack
|
||||||
else:
|
# else:
|
||||||
layer_stack = self.m1_stack
|
# layer_stack = self.m1_stack
|
||||||
|
layer_stack = self.m3_stack
|
||||||
if port == 0:
|
if port == 0:
|
||||||
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
||||||
- self.data_bus_size[port] + 2 * self.m3_pitch)
|
- self.data_bus_size[port] + 2 * self.m3_pitch)
|
||||||
|
|
@ -527,13 +528,13 @@ class sram_1bank(sram_base):
|
||||||
# Only input (besides pins) is the replica bitline
|
# Only input (besides pins) is the replica bitline
|
||||||
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
|
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
|
||||||
dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port))
|
dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port))
|
||||||
self.add_wire(self.m2_stack[::-1],
|
self.add_wire(self.m3_stack,
|
||||||
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
|
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
|
||||||
self.add_via_stack_center(from_layer=src_pin.layer,
|
self.add_via_stack_center(from_layer=src_pin.layer,
|
||||||
to_layer="m2",
|
to_layer="m4",
|
||||||
offset=src_pin.center())
|
offset=src_pin.center())
|
||||||
self.add_via_stack_center(from_layer=dest_pin.layer,
|
self.add_via_stack_center(from_layer=dest_pin.layer,
|
||||||
to_layer="m2",
|
to_layer="m3",
|
||||||
offset=dest_pin.center())
|
offset=dest_pin.center())
|
||||||
|
|
||||||
def route_row_addr_dff(self):
|
def route_row_addr_dff(self):
|
||||||
|
|
|
||||||
|
|
@ -226,10 +226,6 @@ class sram_base(design, verilog, lef):
|
||||||
for inst in self.insts:
|
for inst in self.insts:
|
||||||
self.copy_power_pins(inst, pin_name)
|
self.copy_power_pins(inst, pin_name)
|
||||||
|
|
||||||
if not OPTS.route_supplies:
|
|
||||||
# Do not route the power supply (leave as must-connect pins)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from tech import power_grid
|
from tech import power_grid
|
||||||
grid_stack = power_grid
|
grid_stack = power_grid
|
||||||
|
|
@ -238,43 +234,99 @@ class sram_base(design, verilog, lef):
|
||||||
# Route a M3/M4 grid
|
# Route a M3/M4 grid
|
||||||
grid_stack = self.m3_stack
|
grid_stack = self.m3_stack
|
||||||
|
|
||||||
if OPTS.route_supplies == "grid":
|
# lowest_coord = self.find_lowest_coords()
|
||||||
|
# highest_coord = self.find_highest_coords()
|
||||||
|
|
||||||
|
# # Add two rails to the side
|
||||||
|
# if OPTS.route_supplies == "side":
|
||||||
|
# supply_pins = {}
|
||||||
|
# # Find the lowest leftest pin for vdd and gnd
|
||||||
|
# for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]:
|
||||||
|
# pin_width = 8 * getattr(self, "{}_width".format(grid_stack[2]))
|
||||||
|
# pin_space = 2 * getattr(self, "{}_space".format(grid_stack[2]))
|
||||||
|
# supply_pitch = pin_width + pin_space
|
||||||
|
|
||||||
|
# # Add side power rails on left from bottom to top
|
||||||
|
# # These have a temporary name and will be connected later.
|
||||||
|
# # They are here to reserve space now and ensure other pins go beyond
|
||||||
|
# # their perimeter.
|
||||||
|
# supply_height = highest_coord.y - lowest_coord.y
|
||||||
|
|
||||||
|
# supply_pins[pin_name] = self.add_layout_pin(text=pin_name,
|
||||||
|
# layer=grid_stack[2],
|
||||||
|
# offset=lowest_coord + vector(pin_index * supply_pitch, 0),
|
||||||
|
# width=pin_width,
|
||||||
|
# height=supply_height)
|
||||||
|
|
||||||
|
if not OPTS.route_supplies:
|
||||||
|
# Do not route the power supply (leave as must-connect pins)
|
||||||
|
return
|
||||||
|
elif OPTS.route_supplies == "grid":
|
||||||
from supply_grid_router import supply_grid_router as router
|
from supply_grid_router import supply_grid_router as router
|
||||||
elif OPTS.route_supplies:
|
else:
|
||||||
from supply_tree_router import supply_tree_router as router
|
from supply_tree_router import supply_tree_router as router
|
||||||
|
|
||||||
rtr=router(grid_stack, self)
|
rtr=router(grid_stack, self, side_pin=(OPTS.route_supplies == "side"))
|
||||||
rtr.route()
|
rtr.route()
|
||||||
|
|
||||||
# Find the lowest leftest pin for vdd and gnd
|
if OPTS.route_supplies == "side":
|
||||||
for pin_name in ["vdd", "gnd"]:
|
# Find the lowest leftest pin for vdd and gnd
|
||||||
# Copy the pin shape(s) to rectangles
|
for pin_name in ["vdd", "gnd"]:
|
||||||
for pin in self.get_pins(pin_name):
|
# Copy the pin shape(s) to rectangles
|
||||||
|
for pin in self.get_pins(pin_name):
|
||||||
|
self.add_rect(pin.layer,
|
||||||
|
pin.ll(),
|
||||||
|
pin.width(),
|
||||||
|
pin.height())
|
||||||
|
|
||||||
|
# Remove the pin shape(s)
|
||||||
|
self.remove_layout_pin(pin_name)
|
||||||
|
|
||||||
|
# Get the lowest, leftest pin
|
||||||
|
pin = rtr.get_ll_pin(pin_name)
|
||||||
|
self.add_layout_pin(pin_name,
|
||||||
|
pin.layer,
|
||||||
|
pin.ll(),
|
||||||
|
pin.width(),
|
||||||
|
pin.height())
|
||||||
|
|
||||||
|
elif OPTS.route_supplies:
|
||||||
|
# Update these as we may have routed outside the region (perimeter pins)
|
||||||
|
lowest_coord = self.find_lowest_coords()
|
||||||
|
|
||||||
|
# Find the lowest leftest pin for vdd and gnd
|
||||||
|
for pin_name in ["vdd", "gnd"]:
|
||||||
|
# Copy the pin shape(s) to rectangles
|
||||||
|
for pin in self.get_pins(pin_name):
|
||||||
|
self.add_rect(pin.layer,
|
||||||
|
pin.ll(),
|
||||||
|
pin.width(),
|
||||||
|
pin.height())
|
||||||
|
|
||||||
|
# Remove the pin shape(s)
|
||||||
|
self.remove_layout_pin(pin_name)
|
||||||
|
|
||||||
|
# Get the lowest, leftest pin
|
||||||
|
pin = rtr.get_ll_pin(pin_name)
|
||||||
|
|
||||||
|
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
|
||||||
|
|
||||||
|
# Add it as an IO pin to the perimeter
|
||||||
|
route_width = pin.rx() - lowest_coord.x
|
||||||
|
pin_offset = vector(lowest_coord.x, pin.by())
|
||||||
self.add_rect(pin.layer,
|
self.add_rect(pin.layer,
|
||||||
pin.ll(),
|
pin_offset,
|
||||||
pin.width(),
|
route_width,
|
||||||
pin.height())
|
pin.height())
|
||||||
|
|
||||||
# Remove the pin shape(s)
|
self.add_layout_pin(pin_name,
|
||||||
self.remove_layout_pin(pin_name)
|
pin.layer,
|
||||||
|
pin_offset,
|
||||||
# Get the lowest, leftest pin
|
pin_width,
|
||||||
pin = rtr.get_ll_pin(pin_name)
|
pin.height())
|
||||||
|
else:
|
||||||
# Add it as an IO pin to the perimeter
|
# Grid is left with many top level pins
|
||||||
lowest_coord = self.find_lowest_coords()
|
pass
|
||||||
route_width = pin.rx() - lowest_coord.x
|
|
||||||
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
|
|
||||||
pin_offset = vector(lowest_coord.x, pin.by())
|
|
||||||
self.add_layout_pin(pin_name,
|
|
||||||
pin.layer,
|
|
||||||
pin_offset,
|
|
||||||
pin_width,
|
|
||||||
pin.height())
|
|
||||||
self.add_rect(pin.layer,
|
|
||||||
pin_offset,
|
|
||||||
route_width,
|
|
||||||
pin.height())
|
|
||||||
|
|
||||||
def route_escape_pins(self):
|
def route_escape_pins(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -319,7 +371,7 @@ class sram_base(design, verilog, lef):
|
||||||
from signal_escape_router import signal_escape_router as router
|
from signal_escape_router import signal_escape_router as router
|
||||||
rtr=router(layers=self.m3_stack,
|
rtr=router(layers=self.m3_stack,
|
||||||
design=self,
|
design=self,
|
||||||
margin=4 * self.m3_pitch)
|
margin=8 * self.m3_pitch)
|
||||||
rtr.escape_route(pins_to_route)
|
rtr.escape_route(pins_to_route)
|
||||||
|
|
||||||
def compute_bus_sizes(self):
|
def compute_bus_sizes(self):
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
// Word size: 2
|
// Word size: 2
|
||||||
|
|
||||||
module sram_2_16_1_freepdk45(
|
module sram_2_16_1_freepdk45(
|
||||||
|
`ifdef USE_POWER_PINS
|
||||||
|
vdd,
|
||||||
|
gnd,
|
||||||
|
`endif
|
||||||
// Port 0: RW
|
// Port 0: RW
|
||||||
clk0,csb0,web0,addr0,din0,dout0
|
clk0,csb0,web0,addr0,din0,dout0
|
||||||
);
|
);
|
||||||
|
|
@ -15,6 +19,10 @@ module sram_2_16_1_freepdk45(
|
||||||
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
|
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
|
||||||
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
|
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
|
||||||
|
|
||||||
|
`ifdef USE_POWER_PINS
|
||||||
|
inout vdd;
|
||||||
|
inout gnd;
|
||||||
|
`endif
|
||||||
input clk0; // clock
|
input clk0; // clock
|
||||||
input csb0; // active low chip select
|
input csb0; // active low chip select
|
||||||
input web0; // active low write control
|
input web0; // active low write control
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
// Word size: 2
|
// Word size: 2
|
||||||
|
|
||||||
module sram_2_16_1_scn4m_subm(
|
module sram_2_16_1_scn4m_subm(
|
||||||
|
`ifdef USE_POWER_PINS
|
||||||
|
vdd,
|
||||||
|
gnd,
|
||||||
|
`endif
|
||||||
// Port 0: RW
|
// Port 0: RW
|
||||||
clk0,csb0,web0,addr0,din0,dout0
|
clk0,csb0,web0,addr0,din0,dout0
|
||||||
);
|
);
|
||||||
|
|
@ -15,6 +19,10 @@ module sram_2_16_1_scn4m_subm(
|
||||||
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
|
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
|
||||||
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
|
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
|
||||||
|
|
||||||
|
`ifdef USE_POWER_PINS
|
||||||
|
inout vdd;
|
||||||
|
inout gnd;
|
||||||
|
`endif
|
||||||
input clk0; // clock
|
input clk0; // clock
|
||||||
input csb0; // active low chip select
|
input csb0; // active low chip select
|
||||||
input web0; // active low write control
|
input web0; // active low write control
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue