mirror of https://github.com/VLSIDA/OpenRAM.git
Merged, fixed conflict bt matching control logic creation to dev.
This commit is contained in:
commit
62cbbca852
|
|
@ -1,6 +1,6 @@
|
||||||
# OpenRAM
|
# OpenRAM
|
||||||
Stable: [](https://github.com/VLSIDA/PrivateRAM/commits/master)
|
Master: [](https://github.com/VLSIDA/PrivateRAM/commits/master)
|
||||||
Unstable: [](https://github.com/VLSIDA/PrivateRAM/commits/dev)
|
Dev: [](https://github.com/VLSIDA/PrivateRAM/commits/dev)
|
||||||
[](https://github.com/VLSIDA/PrivateRAM/archive/master.zip)
|
[](https://github.com/VLSIDA/PrivateRAM/archive/master.zip)
|
||||||
[](./LICENSE)
|
[](./LICENSE)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,12 @@ class design(hierarchy_design):
|
||||||
self.readwrite_ports = []
|
self.readwrite_ports = []
|
||||||
# These are the read/write and write-only port indices
|
# These are the read/write and write-only port indices
|
||||||
self.write_ports = []
|
self.write_ports = []
|
||||||
|
# These are the write-only port indices.
|
||||||
|
self.writeonly_ports = []
|
||||||
# These are teh read/write and read-only port indice
|
# These are teh read/write and read-only port indice
|
||||||
self.read_ports = []
|
self.read_ports = []
|
||||||
|
# These are the read-only port indices.
|
||||||
|
self.readonly_ports = []
|
||||||
# These are all the ports
|
# These are all the ports
|
||||||
self.all_ports = list(range(total_ports))
|
self.all_ports = list(range(total_ports))
|
||||||
|
|
||||||
|
|
@ -78,9 +82,11 @@ class design(hierarchy_design):
|
||||||
port_number += 1
|
port_number += 1
|
||||||
for port in range(OPTS.num_w_ports):
|
for port in range(OPTS.num_w_ports):
|
||||||
self.write_ports.append(port_number)
|
self.write_ports.append(port_number)
|
||||||
|
self.writeonly_ports.append(port_number)
|
||||||
port_number += 1
|
port_number += 1
|
||||||
for port in range(OPTS.num_r_ports):
|
for port in range(OPTS.num_r_ports):
|
||||||
self.read_ports.append(port_number)
|
self.read_ports.append(port_number)
|
||||||
|
self.readonly_ports.append(port_number)
|
||||||
port_number += 1
|
port_number += 1
|
||||||
|
|
||||||
def analytical_power(self, proc, vdd, temp, load):
|
def analytical_power(self, proc, vdd, temp, load):
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,24 @@ class pin_layout:
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def bbox(self, pin_list):
|
||||||
|
"""
|
||||||
|
Given a list of layout pins, create a bounding box layout.
|
||||||
|
"""
|
||||||
|
(ll, ur) = self.rect
|
||||||
|
min_x = ll.x
|
||||||
|
max_x = ur.x
|
||||||
|
min_y = ll.y
|
||||||
|
max_y = ur.y
|
||||||
|
|
||||||
|
for pin in pin_list:
|
||||||
|
min_x = min(min_x, pin.ll().x)
|
||||||
|
max_x = max(max_x, pin.ur().x)
|
||||||
|
min_y = min(min_y, pin.ll().y)
|
||||||
|
max_y = max(max_y, pin.ur().y)
|
||||||
|
|
||||||
|
self.rect = [vector(min_x,min_y),vector(max_x,max_y)]
|
||||||
|
|
||||||
def inflate(self, spacing=None):
|
def inflate(self, spacing=None):
|
||||||
"""
|
"""
|
||||||
Inflate the rectangle by the spacing (or other rule)
|
Inflate the rectangle by the spacing (or other rule)
|
||||||
|
|
@ -325,7 +343,7 @@ class pin_layout:
|
||||||
(r2_ll,r2_ur) = other.rect
|
(r2_ll,r2_ur) = other.rect
|
||||||
|
|
||||||
def dist(x1, y1, x2, y2):
|
def dist(x1, y1, x2, y2):
|
||||||
return sqrt((x2-x1)**2 + (y2-y1)**2)
|
return math.sqrt((x2-x1)**2 + (y2-y1)**2)
|
||||||
|
|
||||||
left = r2_ur.x < r1_ll.x
|
left = r2_ur.x < r1_ll.x
|
||||||
right = r1_ur.x < r2_ll.x
|
right = r1_ur.x < r2_ll.x
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ class bank(design.design):
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adding pins for Bank module"""
|
""" Adding pins for Bank module"""
|
||||||
for port in self.read_ports:
|
for port in self.read_ports:
|
||||||
|
|
@ -877,9 +876,9 @@ class bank(design.design):
|
||||||
if self.col_addr_size==0:
|
if self.col_addr_size==0:
|
||||||
return
|
return
|
||||||
|
|
||||||
bottom_inst = self.column_mux_array_inst[port]
|
inst1 = self.column_mux_array_inst[port]
|
||||||
top_inst = self.precharge_array_inst[port]
|
inst2 = self.precharge_array_inst[port]
|
||||||
self.connect_bitlines(top_inst, bottom_inst, self.num_cols)
|
self.connect_bitlines(inst1, inst2, self.num_cols)
|
||||||
|
|
||||||
def route_column_mux_to_bitcell_array(self, port):
|
def route_column_mux_to_bitcell_array(self, port):
|
||||||
""" Routing of BL and BR between col mux bitcell array """
|
""" Routing of BL and BR between col mux bitcell array """
|
||||||
|
|
@ -888,47 +887,50 @@ class bank(design.design):
|
||||||
if self.col_addr_size==0:
|
if self.col_addr_size==0:
|
||||||
return
|
return
|
||||||
|
|
||||||
bottom_inst = self.column_mux_array_inst[port]
|
inst2 = self.column_mux_array_inst[port]
|
||||||
top_inst = self.bitcell_array_inst
|
inst1 = self.bitcell_array_inst
|
||||||
self.connect_bitlines(top_inst, bottom_inst, self.num_cols)
|
inst1_bl_name = self.bl_names[port]+"_{}"
|
||||||
|
inst1_br_name = self.br_names[port]+"_{}"
|
||||||
|
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
|
||||||
|
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
|
def route_sense_amp_to_column_mux_or_precharge_array(self, port):
|
||||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||||
bottom_inst = self.sense_amp_array_inst[port]
|
inst2 = self.sense_amp_array_inst[port]
|
||||||
|
|
||||||
if self.col_addr_size>0:
|
if self.col_addr_size>0:
|
||||||
# Sense amp is connected to the col mux
|
# Sense amp is connected to the col mux
|
||||||
top_inst = self.column_mux_array_inst[port]
|
inst1 = self.column_mux_array_inst[port]
|
||||||
top_bl = "bl_out_{}"
|
inst1_bl_name = "bl_out_{}"
|
||||||
top_br = "br_out_{}"
|
inst1_br_name = "br_out_{}"
|
||||||
else:
|
else:
|
||||||
# Sense amp is directly connected to the precharge array
|
# Sense amp is directly connected to the precharge array
|
||||||
top_inst = self.precharge_array_inst[port]
|
inst1 = self.precharge_array_inst[port]
|
||||||
top_bl = "bl_{}"
|
inst1_bl_name = "bl_{}"
|
||||||
top_br = "br_{}"
|
inst1_br_name = "br_{}"
|
||||||
|
|
||||||
self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size,
|
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||||
inst1_bl_name=top_bl, inst1_br_name=top_br)
|
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||||
|
|
||||||
def route_write_driver_to_column_mux_or_precharge_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 precharge array """
|
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
|
||||||
bottom_inst = self.write_driver_array_inst[port]
|
inst2 = self.write_driver_array_inst[port]
|
||||||
|
|
||||||
if self.col_addr_size>0:
|
if self.col_addr_size>0:
|
||||||
# Sense amp is connected to the col mux
|
# Write driver is connected to the col mux
|
||||||
top_inst = self.column_mux_array_inst[port]
|
inst1 = self.column_mux_array_inst[port]
|
||||||
top_bl = "bl_out_{}"
|
inst1_bl_name = "bl_out_{}"
|
||||||
top_br = "br_out_{}"
|
inst1_br_name = "br_out_{}"
|
||||||
else:
|
else:
|
||||||
# Sense amp is directly connected to the precharge array
|
# Write driver is directly connected to the bitcell array
|
||||||
top_inst = self.precharge_array_inst[port]
|
inst1 = self.bitcell_array_inst
|
||||||
top_bl = "bl_{}"
|
inst1_bl_name = self.bl_names[port]+"_{}"
|
||||||
top_br = "br_{}"
|
inst1_br_name = self.br_names[port]+"_{}"
|
||||||
|
|
||||||
self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size,
|
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||||
inst1_bl_name=top_bl, inst1_br_name=top_br)
|
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||||
|
|
||||||
def route_write_driver_to_sense_amp(self, port):
|
def route_write_driver_to_sense_amp(self, port):
|
||||||
""" Routing of BL and BR between write driver and sense amp """
|
""" Routing of BL and BR between write driver and sense amp """
|
||||||
|
|
@ -943,7 +945,7 @@ class bank(design.design):
|
||||||
|
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit))
|
data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit))
|
||||||
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(self.read_ports[port],bit),
|
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit),
|
||||||
layer=data_pin.layer,
|
layer=data_pin.layer,
|
||||||
offset=data_pin.center(),
|
offset=data_pin.center(),
|
||||||
height=data_pin.height(),
|
height=data_pin.height(),
|
||||||
|
|
@ -969,6 +971,37 @@ class bank(design.design):
|
||||||
din_name = "din{0}_{1}".format(port,row)
|
din_name = "din{0}_{1}".format(port,row)
|
||||||
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
|
self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
|
||||||
|
|
||||||
|
def channel_route_bitlines(self, inst1, inst2, num_bits,
|
||||||
|
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
||||||
|
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
||||||
|
"""
|
||||||
|
Route the bl and br of two modules using the channel router.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# determine top and bottom automatically.
|
||||||
|
# since they don't overlap, we can just check the bottom y coordinate.
|
||||||
|
if inst1.by() < inst2.by():
|
||||||
|
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||||
|
(top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||||
|
else:
|
||||||
|
(bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name)
|
||||||
|
(top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name)
|
||||||
|
|
||||||
|
|
||||||
|
# Channel route each mux separately since we don't minimize the number
|
||||||
|
# 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)]
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
def connect_bitlines(self, inst1, inst2, num_bits,
|
def connect_bitlines(self, inst1, inst2, num_bits,
|
||||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
||||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Create layout and route between modules """
|
""" Create layout and route between modules """
|
||||||
self.route_rails()
|
|
||||||
self.place_instances()
|
self.place_instances()
|
||||||
self.route_all()
|
self.route_all()
|
||||||
|
|
||||||
|
|
@ -266,7 +265,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def route_rails(self):
|
def route_rails(self):
|
||||||
""" Add the input signal inverted tracks """
|
""" Add the input signal inverted tracks """
|
||||||
height = 4*self.inv1.height - self.m2_pitch
|
height = self.control_logic_center.y - self.m2_pitch
|
||||||
offset = vector(self.ctrl_dff_array.width,0)
|
offset = vector(self.ctrl_dff_array.width,0)
|
||||||
|
|
||||||
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
|
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
|
||||||
|
|
@ -299,21 +298,21 @@ class control_logic(design.design):
|
||||||
row += 2
|
row += 2
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.place_we_row(row=row)
|
self.place_we_row(row=row)
|
||||||
pre_height = self.w_en_inst.uy()
|
height = self.w_en_inst.uy()
|
||||||
control_center_y = self.w_en_inst.by()
|
control_center_y = self.w_en_inst.uy()
|
||||||
row += 1
|
row += 1
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.place_rbl_in_row(row=row)
|
self.place_rbl_in_row(row=row)
|
||||||
self.place_sen_row(row=row+1)
|
self.place_sen_row(row=row+1)
|
||||||
self.place_rbl(row=row+2)
|
self.place_rbl(row=row+2)
|
||||||
pre_height = self.rbl_inst.uy()
|
height = self.rbl_inst.uy()
|
||||||
control_center_y = self.rbl_inst.by()
|
control_center_y = self.rbl_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)
|
||||||
|
|
||||||
# Extra pitch on top and right
|
# Extra pitch on top and right
|
||||||
self.height = pre_height + self.m3_pitch
|
self.height = height + 2*self.m1_pitch
|
||||||
# Max of modules or logic rows
|
# Max of modules or logic rows
|
||||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||||
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
|
self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch
|
||||||
|
|
@ -322,6 +321,7 @@ class control_logic(design.design):
|
||||||
|
|
||||||
def route_all(self):
|
def route_all(self):
|
||||||
""" Routing between modules """
|
""" Routing between modules """
|
||||||
|
self.route_rails()
|
||||||
self.route_dffs()
|
self.route_dffs()
|
||||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||||
self.route_wen()
|
self.route_wen()
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ class hierarchical_predecode(design.design):
|
||||||
|
|
||||||
# Find the x offsets for where the vias/pins should be placed
|
# Find the x offsets for where the vias/pins should be placed
|
||||||
in_xoffset = self.in_inst[0].rx()
|
in_xoffset = self.in_inst[0].rx()
|
||||||
out_xoffset = self.inv_inst[0].lx()
|
out_xoffset = self.inv_inst[0].lx() - self.m1_space
|
||||||
for num in range(0,self.number_of_outputs):
|
for num in range(0,self.number_of_outputs):
|
||||||
# this will result in duplicate polygons for rails, but who cares
|
# this will result in duplicate polygons for rails, but who cares
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ Some utility functions for sets of grid cells.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import debug
|
import debug
|
||||||
|
import math
|
||||||
from direction import direction
|
from direction import direction
|
||||||
from vector3d import vector3d
|
from vector3d import vector3d
|
||||||
|
|
||||||
|
|
@ -139,3 +140,16 @@ def flatten_set(curset):
|
||||||
else:
|
else:
|
||||||
newset.update(flatten_set(c))
|
newset.update(flatten_set(c))
|
||||||
return newset
|
return newset
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def distance_set(coord, curset):
|
||||||
|
"""
|
||||||
|
Return the distance from a coordinate to any item in the set
|
||||||
|
"""
|
||||||
|
min_dist = math.inf
|
||||||
|
for c in curset:
|
||||||
|
min_dist = min(coord.euclidean_distance(c), min_dist)
|
||||||
|
|
||||||
|
return min_dist
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -465,15 +465,22 @@ class pin_group:
|
||||||
if pin.contained_by_any(self.enclosures):
|
if pin.contained_by_any(self.enclosures):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Find a connector in the cardinal directions
|
||||||
|
# If there is overlap, but it isn't contained, these could all be None
|
||||||
|
# These could also be none if the pin is diagonal from the enclosure
|
||||||
left_connector = self.find_left_connector(pin, self.enclosures)
|
left_connector = self.find_left_connector(pin, self.enclosures)
|
||||||
right_connector = self.find_right_connector(pin, self.enclosures)
|
right_connector = self.find_right_connector(pin, self.enclosures)
|
||||||
above_connector = self.find_above_connector(pin, self.enclosures)
|
above_connector = self.find_above_connector(pin, self.enclosures)
|
||||||
below_connector = self.find_below_connector(pin, self.enclosures)
|
below_connector = self.find_below_connector(pin, self.enclosures)
|
||||||
for connector in [left_connector, right_connector, above_connector, below_connector]:
|
connector_list = [left_connector, right_connector, above_connector, below_connector]
|
||||||
if connector:
|
filtered_list = list(filter(lambda x: x!=None, connector_list))
|
||||||
self.enclosures.append(connector)
|
if (len(filtered_list)>0):
|
||||||
|
import copy
|
||||||
|
bbox_connector = copy.copy(pin)
|
||||||
|
bbox_connector.bbox(filtered_list)
|
||||||
|
self.enclosures.append(bbox_connector)
|
||||||
|
|
||||||
# Now, make sure each pin touches an enclosure. If not, add a connector.
|
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector.
|
||||||
# This could only happen when there was no enclosure in any cardinal direction from a pin
|
# This could only happen when there was no enclosure in any cardinal direction from a pin
|
||||||
for pin_list in self.pins:
|
for pin_list in self.pins:
|
||||||
if not self.overlap_any_shape(pin_list, self.enclosures):
|
if not self.overlap_any_shape(pin_list, self.enclosures):
|
||||||
|
|
@ -595,7 +602,7 @@ class pin_group:
|
||||||
|
|
||||||
# At least one of the groups must have some valid tracks
|
# At least one of the groups must have some valid tracks
|
||||||
if (len(pin_set)==0 and len(blockage_set)==0):
|
if (len(pin_set)==0 and len(blockage_set)==0):
|
||||||
debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
|
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
|
||||||
|
|
||||||
for pin_list in self.pins:
|
for pin_list in self.pins:
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
|
|
@ -649,7 +656,6 @@ class pin_group:
|
||||||
that is ensured to overlap the supply rail wire.
|
that is ensured to overlap the supply rail wire.
|
||||||
It then adds rectangle(s) for the enclosure.
|
It then adds rectangle(s) for the enclosure.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
additional_set = set()
|
additional_set = set()
|
||||||
# Check the layer of any element in the pin to determine which direction to route it
|
# Check the layer of any element in the pin to determine which direction to route it
|
||||||
e = next(iter(start_set))
|
e = next(iter(start_set))
|
||||||
|
|
@ -673,3 +679,6 @@ class pin_group:
|
||||||
self.set_routed()
|
self.set_routed()
|
||||||
self.enclosures = self.compute_enclosures()
|
self.enclosures = self.compute_enclosures()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -515,7 +515,7 @@ class router(router_tech):
|
||||||
# scale the size bigger to include neaby tracks
|
# scale the size bigger to include neaby tracks
|
||||||
ll=ll.scale(self.track_factor).floor()
|
ll=ll.scale(self.track_factor).floor()
|
||||||
ur=ur.scale(self.track_factor).ceil()
|
ur=ur.scale(self.track_factor).ceil()
|
||||||
|
#print(pin)
|
||||||
# Keep tabs on tracks with sufficient and insufficient overlap
|
# Keep tabs on tracks with sufficient and insufficient overlap
|
||||||
sufficient_list = set()
|
sufficient_list = set()
|
||||||
insufficient_list = set()
|
insufficient_list = set()
|
||||||
|
|
@ -523,35 +523,50 @@ class router(router_tech):
|
||||||
zindex=self.get_zindex(pin.layer_num)
|
zindex=self.get_zindex(pin.layer_num)
|
||||||
for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion):
|
for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion):
|
||||||
for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion):
|
for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion):
|
||||||
debug.info(4,"Converting [ {0} , {1} ]".format(x,y))
|
|
||||||
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
|
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
|
||||||
if full_overlap:
|
if full_overlap:
|
||||||
sufficient_list.update([full_overlap])
|
sufficient_list.update([full_overlap])
|
||||||
if partial_overlap:
|
if partial_overlap:
|
||||||
insufficient_list.update([partial_overlap])
|
insufficient_list.update([partial_overlap])
|
||||||
|
debug.info(4,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap))
|
||||||
|
|
||||||
|
# Remove the blocked grids
|
||||||
|
sufficient_list.difference_update(self.blocked_grids)
|
||||||
|
insufficient_list.difference_update(self.blocked_grids)
|
||||||
|
|
||||||
if len(sufficient_list)>0:
|
if len(sufficient_list)>0:
|
||||||
return sufficient_list
|
return sufficient_list
|
||||||
elif expansion==0 and len(insufficient_list)>0:
|
elif expansion==0 and len(insufficient_list)>0:
|
||||||
#Remove blockages and return the best to be patched
|
best_pin = self.get_all_offgrid_pin(pin, insufficient_list)
|
||||||
insufficient_list.difference_update(self.blocked_grids)
|
#print(best_pin)
|
||||||
return self.get_best_offgrid_pin(pin, insufficient_list)
|
return best_pin
|
||||||
elif expansion>0:
|
elif expansion>0:
|
||||||
#Remove blockages and return the nearest
|
nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list)
|
||||||
insufficient_list.difference_update(self.blocked_grids)
|
return nearest_pin
|
||||||
return self.get_nearest_offgrid_pin(pin, insufficient_list)
|
|
||||||
else:
|
else:
|
||||||
debug.error("Unable to find any overlapping grids.", -1)
|
return set()
|
||||||
|
|
||||||
|
def get_all_offgrid_pin(self, pin, insufficient_list):
|
||||||
|
"""
|
||||||
|
Find a list of all pins with some overlap.
|
||||||
|
"""
|
||||||
|
#print("INSUFFICIENT LIST",insufficient_list)
|
||||||
|
# Find the coordinate with the most overlap
|
||||||
|
any_overlap = set()
|
||||||
|
for coord in insufficient_list:
|
||||||
|
full_pin = self.convert_track_to_pin(coord)
|
||||||
|
# Compute the overlap with that rectangle
|
||||||
|
overlap_rect=pin.compute_overlap(full_pin)
|
||||||
|
# Determine the max x or y overlap
|
||||||
|
max_overlap = max(overlap_rect)
|
||||||
|
if max_overlap>0:
|
||||||
|
any_overlap.update([coord])
|
||||||
|
|
||||||
|
return any_overlap
|
||||||
|
|
||||||
def get_best_offgrid_pin(self, pin, insufficient_list):
|
def get_best_offgrid_pin(self, pin, insufficient_list):
|
||||||
"""
|
"""
|
||||||
Given a pin and a list of partial overlap grids:
|
Find a list of the single pin with the most overlap.
|
||||||
1) Find the unblocked grids.
|
|
||||||
2) If one, use it.
|
|
||||||
3) If not, find the greatest overlap.
|
|
||||||
4) Add a pin with the most overlap to make it "on grid"
|
|
||||||
that is not blocked.
|
|
||||||
"""
|
"""
|
||||||
#print("INSUFFICIENT LIST",insufficient_list)
|
#print("INSUFFICIENT LIST",insufficient_list)
|
||||||
# Find the coordinate with the most overlap
|
# Find the coordinate with the most overlap
|
||||||
|
|
@ -569,6 +584,23 @@ class router(router_tech):
|
||||||
|
|
||||||
return set([best_coord])
|
return set([best_coord])
|
||||||
|
|
||||||
|
def get_furthest_offgrid_pin(self, pin, insufficient_list):
|
||||||
|
"""
|
||||||
|
Get a grid cell that is the furthest from the blocked grids.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#print("INSUFFICIENT LIST",insufficient_list)
|
||||||
|
# Find the coordinate with the most overlap
|
||||||
|
best_coord = None
|
||||||
|
best_dist = math.inf
|
||||||
|
for coord in insufficient_list:
|
||||||
|
min_dist = grid_utils.distance_set(coord, self.blocked_grids)
|
||||||
|
if min_dist<best_dist:
|
||||||
|
best_dist=min_dist
|
||||||
|
best_coord=coord
|
||||||
|
|
||||||
|
return set([best_coord])
|
||||||
|
|
||||||
def get_nearest_offgrid_pin(self, pin, insufficient_list):
|
def get_nearest_offgrid_pin(self, pin, insufficient_list):
|
||||||
"""
|
"""
|
||||||
Given a pin and a list of grid cells (probably non-overlapping),
|
Given a pin and a list of grid cells (probably non-overlapping),
|
||||||
|
|
|
||||||
|
|
@ -164,9 +164,13 @@ class vector3d():
|
||||||
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
|
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
|
||||||
|
|
||||||
def distance(self, other):
|
def distance(self, other):
|
||||||
""" Return the planar distance between two values """
|
""" Return the manhattan distance between two values """
|
||||||
return abs(self.x-other.x)+abs(self.y-other.y)
|
return abs(self.x-other.x)+abs(self.y-other.y)
|
||||||
|
|
||||||
|
def euclidean_distance(self, other):
|
||||||
|
""" Return the euclidean distance between two values """
|
||||||
|
return math.sqrt((self.x-other.x)**2+(self.y-other.y)**2)
|
||||||
|
|
||||||
|
|
||||||
def adjacent(self, other):
|
def adjacent(self, other):
|
||||||
""" Is the one grid adjacent in any planar direction to the other """
|
""" Is the one grid adjacent in any planar direction to the other """
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,10 @@ class sram_1bank(sram_base):
|
||||||
self.control_logic_insts[port].place(control_pos[port])
|
self.control_logic_insts[port].place(control_pos[port])
|
||||||
|
|
||||||
# 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.
|
||||||
row_addr_pos[port] = vector(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
|
||||||
self.control_logic_insts[port].uy())
|
# It is aove the control logic but below the top of the bitcell array
|
||||||
|
y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
|
||||||
|
row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(row_addr_pos[port])
|
self.row_addr_dff_insts[port].place(row_addr_pos[port])
|
||||||
|
|
||||||
# Add the col address flops below the bank to the left of the lower-left of bank array
|
# Add the col address flops below the bank to the left of the lower-left of bank array
|
||||||
|
|
@ -103,8 +105,10 @@ class sram_1bank(sram_base):
|
||||||
self.control_logic_insts[port].place(control_pos[port], mirror="MY")
|
self.control_logic_insts[port].place(control_pos[port], mirror="MY")
|
||||||
|
|
||||||
# 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.
|
||||||
row_addr_pos[port] = vector(control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width,
|
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
||||||
self.control_logic_insts[port].uy())
|
# It is above the control logic but below the top of the bitcell array
|
||||||
|
y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
|
||||||
|
row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY")
|
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY")
|
||||||
|
|
||||||
# Add the col address flops above the bank to the right of the upper-right of bank array
|
# Add the col address flops above the bank to the right of the upper-right of bank array
|
||||||
|
|
|
||||||
|
|
@ -217,29 +217,6 @@ class sram_base(design):
|
||||||
c = reload(__import__(OPTS.bitcell))
|
c = reload(__import__(OPTS.bitcell))
|
||||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||||
self.bitcell = self.mod_bitcell()
|
self.bitcell = self.mod_bitcell()
|
||||||
# <<<<<<< HEAD
|
|
||||||
# =======
|
|
||||||
|
|
||||||
# c = reload(__import__(OPTS.control_logic))
|
|
||||||
# self.mod_control_logic = getattr(c, OPTS.control_logic)
|
|
||||||
|
|
||||||
# # Create the control logic module for each port type
|
|
||||||
# if len(self.readwrite_ports)>0:
|
|
||||||
# self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
|
||||||
# words_per_row=self.words_per_row,
|
|
||||||
# port_type="rw")
|
|
||||||
# self.add_mod(self.control_logic_rw)
|
|
||||||
# if len(self.write_ports)>0:
|
|
||||||
# self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
|
||||||
# words_per_row=self.words_per_row,
|
|
||||||
# port_type="w")
|
|
||||||
# self.add_mod(self.control_logic_w)
|
|
||||||
# if len(self.read_ports)>0:
|
|
||||||
# self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
|
||||||
# words_per_row=self.words_per_row,
|
|
||||||
# port_type="r")
|
|
||||||
# self.add_mod(self.control_logic_r)
|
|
||||||
# >>>>>>> dev
|
|
||||||
|
|
||||||
# Create the address and control flops (but not the clk)
|
# Create the address and control flops (but not the clk)
|
||||||
from dff_array import dff_array
|
from dff_array import dff_array
|
||||||
|
|
@ -283,13 +260,13 @@ class sram_base(design):
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="rw")
|
port_type="rw")
|
||||||
self.add_mod(self.control_logic_rw)
|
self.add_mod(self.control_logic_rw)
|
||||||
if len(self.write_ports)>0:
|
if len(self.writeonly_ports)>0:
|
||||||
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="w")
|
port_type="w")
|
||||||
self.add_mod(self.control_logic_w)
|
self.add_mod(self.control_logic_w)
|
||||||
if len(self.read_ports)>0:
|
if len(self.readonly_ports)>0:
|
||||||
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
sram=self,
|
sram=self,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Run a regression test on a 1 bank SRAM
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
||||||
|
class psram_1bank_2mux_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
|
||||||
|
OPTS.num_rw_ports = 0
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=32,
|
||||||
|
num_banks=1)
|
||||||
|
c.num_words=32
|
||||||
|
c.words_per_row=2
|
||||||
|
debug.info(1, "Single bank two way column mux 1w/1r with control logic")
|
||||||
|
a = sram(c, "sram")
|
||||||
|
self.local_check(a, final_verification=True)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in New Issue