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
|
||||
Stable: [](https://github.com/VLSIDA/PrivateRAM/commits/master)
|
||||
Unstable: [](https://github.com/VLSIDA/PrivateRAM/commits/dev)
|
||||
Master: [](https://github.com/VLSIDA/PrivateRAM/commits/master)
|
||||
Dev: [](https://github.com/VLSIDA/PrivateRAM/commits/dev)
|
||||
[](https://github.com/VLSIDA/PrivateRAM/archive/master.zip)
|
||||
[](./LICENSE)
|
||||
|
||||
|
|
|
|||
|
|
@ -65,8 +65,12 @@ class design(hierarchy_design):
|
|||
self.readwrite_ports = []
|
||||
# These are the read/write and write-only port indices
|
||||
self.write_ports = []
|
||||
# These are the write-only port indices.
|
||||
self.writeonly_ports = []
|
||||
# These are teh read/write and read-only port indice
|
||||
self.read_ports = []
|
||||
# These are the read-only port indices.
|
||||
self.readonly_ports = []
|
||||
# These are all the ports
|
||||
self.all_ports = list(range(total_ports))
|
||||
|
||||
|
|
@ -78,9 +82,11 @@ class design(hierarchy_design):
|
|||
port_number += 1
|
||||
for port in range(OPTS.num_w_ports):
|
||||
self.write_ports.append(port_number)
|
||||
self.writeonly_ports.append(port_number)
|
||||
port_number += 1
|
||||
for port in range(OPTS.num_r_ports):
|
||||
self.read_ports.append(port_number)
|
||||
self.readonly_ports.append(port_number)
|
||||
port_number += 1
|
||||
|
||||
def analytical_power(self, proc, vdd, temp, load):
|
||||
|
|
|
|||
|
|
@ -62,6 +62,24 @@ class pin_layout:
|
|||
else:
|
||||
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):
|
||||
"""
|
||||
Inflate the rectangle by the spacing (or other rule)
|
||||
|
|
@ -325,7 +343,7 @@ class pin_layout:
|
|||
(r2_ll,r2_ur) = other.rect
|
||||
|
||||
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
|
||||
right = r1_ur.x < r2_ll.x
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ class bank(design.design):
|
|||
self.bank_array_ur = self.bitcell_array_inst.ur()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
""" Adding pins for Bank module"""
|
||||
for port in self.read_ports:
|
||||
|
|
@ -877,9 +876,9 @@ class bank(design.design):
|
|||
if self.col_addr_size==0:
|
||||
return
|
||||
|
||||
bottom_inst = self.column_mux_array_inst[port]
|
||||
top_inst = self.precharge_array_inst[port]
|
||||
self.connect_bitlines(top_inst, bottom_inst, self.num_cols)
|
||||
inst1 = self.column_mux_array_inst[port]
|
||||
inst2 = self.precharge_array_inst[port]
|
||||
self.connect_bitlines(inst1, inst2, self.num_cols)
|
||||
|
||||
def route_column_mux_to_bitcell_array(self, port):
|
||||
""" Routing of BL and BR between col mux bitcell array """
|
||||
|
|
@ -888,47 +887,50 @@ class bank(design.design):
|
|||
if self.col_addr_size==0:
|
||||
return
|
||||
|
||||
bottom_inst = self.column_mux_array_inst[port]
|
||||
top_inst = self.bitcell_array_inst
|
||||
self.connect_bitlines(top_inst, bottom_inst, self.num_cols)
|
||||
inst2 = self.column_mux_array_inst[port]
|
||||
inst1 = self.bitcell_array_inst
|
||||
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):
|
||||
""" 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:
|
||||
# Sense amp is connected to the col mux
|
||||
top_inst = self.column_mux_array_inst[port]
|
||||
top_bl = "bl_out_{}"
|
||||
top_br = "br_out_{}"
|
||||
inst1 = self.column_mux_array_inst[port]
|
||||
inst1_bl_name = "bl_out_{}"
|
||||
inst1_br_name = "br_out_{}"
|
||||
else:
|
||||
# Sense amp is directly connected to the precharge array
|
||||
top_inst = self.precharge_array_inst[port]
|
||||
top_bl = "bl_{}"
|
||||
top_br = "br_{}"
|
||||
inst1 = self.precharge_array_inst[port]
|
||||
inst1_bl_name = "bl_{}"
|
||||
inst1_br_name = "br_{}"
|
||||
|
||||
self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size,
|
||||
inst1_bl_name=top_bl, inst1_br_name=top_br)
|
||||
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||
|
||||
def route_write_driver_to_column_mux_or_precharge_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or precharge array """
|
||||
bottom_inst = self.write_driver_array_inst[port]
|
||||
def route_write_driver_to_column_mux_or_bitcell_array(self, port):
|
||||
""" Routing of BL and BR between sense_amp and column mux or bitcell array """
|
||||
inst2 = self.write_driver_array_inst[port]
|
||||
|
||||
if self.col_addr_size>0:
|
||||
# Sense amp is connected to the col mux
|
||||
top_inst = self.column_mux_array_inst[port]
|
||||
top_bl = "bl_out_{}"
|
||||
top_br = "br_out_{}"
|
||||
# Write driver is connected to the col mux
|
||||
inst1 = self.column_mux_array_inst[port]
|
||||
inst1_bl_name = "bl_out_{}"
|
||||
inst1_br_name = "br_out_{}"
|
||||
else:
|
||||
# Sense amp is directly connected to the precharge array
|
||||
top_inst = self.precharge_array_inst[port]
|
||||
top_bl = "bl_{}"
|
||||
top_br = "br_{}"
|
||||
# Write driver is directly connected to the bitcell array
|
||||
inst1 = self.bitcell_array_inst
|
||||
inst1_bl_name = self.bl_names[port]+"_{}"
|
||||
inst1_br_name = self.br_names[port]+"_{}"
|
||||
|
||||
self.connect_bitlines(inst1=top_inst, inst2=bottom_inst, num_bits=self.word_size,
|
||||
inst1_bl_name=top_bl, inst1_br_name=top_br)
|
||||
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
|
||||
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
|
||||
|
||||
def route_write_driver_to_sense_amp(self, port):
|
||||
""" 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):
|
||||
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,
|
||||
offset=data_pin.center(),
|
||||
height=data_pin.height(),
|
||||
|
|
@ -969,6 +971,37 @@ class bank(design.design):
|
|||
din_name = "din{0}_{1}".format(port,row)
|
||||
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,
|
||||
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
|
||||
inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ class control_logic(design.design):
|
|||
|
||||
def create_layout(self):
|
||||
""" Create layout and route between modules """
|
||||
self.route_rails()
|
||||
self.place_instances()
|
||||
self.route_all()
|
||||
|
||||
|
|
@ -266,7 +265,7 @@ class control_logic(design.design):
|
|||
|
||||
def route_rails(self):
|
||||
""" 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)
|
||||
|
||||
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
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.place_we_row(row=row)
|
||||
pre_height = self.w_en_inst.uy()
|
||||
control_center_y = self.w_en_inst.by()
|
||||
height = self.w_en_inst.uy()
|
||||
control_center_y = self.w_en_inst.uy()
|
||||
row += 1
|
||||
if (self.port_type == "rw") or (self.port_type == "r"):
|
||||
self.place_rbl_in_row(row=row)
|
||||
self.place_sen_row(row=row+1)
|
||||
self.place_rbl(row=row+2)
|
||||
pre_height = self.rbl_inst.uy()
|
||||
height = self.rbl_inst.uy()
|
||||
control_center_y = self.rbl_inst.by()
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
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
|
||||
|
|
@ -322,6 +321,7 @@ class control_logic(design.design):
|
|||
|
||||
def route_all(self):
|
||||
""" Routing between modules """
|
||||
self.route_rails()
|
||||
self.route_dffs()
|
||||
if (self.port_type == "rw") or (self.port_type == "w"):
|
||||
self.route_wen()
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class hierarchical_predecode(design.design):
|
|||
|
||||
# Find the x offsets for where the vias/pins should be placed
|
||||
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):
|
||||
# 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 math
|
||||
from direction import direction
|
||||
from vector3d import vector3d
|
||||
|
||||
|
|
@ -139,3 +140,16 @@ def flatten_set(curset):
|
|||
else:
|
||||
newset.update(flatten_set(c))
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -464,16 +464,23 @@ class pin_group:
|
|||
# If it is contained, it won't need a connector
|
||||
if pin.contained_by_any(self.enclosures):
|
||||
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)
|
||||
right_connector = self.find_right_connector(pin, self.enclosures)
|
||||
above_connector = self.find_above_connector(pin, self.enclosures)
|
||||
below_connector = self.find_below_connector(pin, self.enclosures)
|
||||
for connector in [left_connector, right_connector, above_connector, below_connector]:
|
||||
if connector:
|
||||
self.enclosures.append(connector)
|
||||
connector_list = [left_connector, right_connector, above_connector, below_connector]
|
||||
filtered_list = list(filter(lambda x: x!=None, connector_list))
|
||||
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
|
||||
for pin_list in self.pins:
|
||||
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
|
||||
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 in pin_list:
|
||||
|
|
@ -603,7 +610,7 @@ class pin_group:
|
|||
# Determine which tracks the pin overlaps
|
||||
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
|
||||
pin_set.update(pin_in_tracks)
|
||||
|
||||
|
||||
if len(pin_set)==0:
|
||||
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
|
||||
self.router.write_debug_gds("blocked_pin.gds")
|
||||
|
|
@ -649,7 +656,6 @@ class pin_group:
|
|||
that is ensured to overlap the supply rail wire.
|
||||
It then adds rectangle(s) for the enclosure.
|
||||
"""
|
||||
|
||||
additional_set = set()
|
||||
# Check the layer of any element in the pin to determine which direction to route it
|
||||
e = next(iter(start_set))
|
||||
|
|
@ -673,3 +679,6 @@ class pin_group:
|
|||
self.set_routed()
|
||||
self.enclosures = self.compute_enclosures()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ class router(router_tech):
|
|||
# scale the size bigger to include neaby tracks
|
||||
ll=ll.scale(self.track_factor).floor()
|
||||
ur=ur.scale(self.track_factor).ceil()
|
||||
|
||||
#print(pin)
|
||||
# Keep tabs on tracks with sufficient and insufficient overlap
|
||||
sufficient_list = set()
|
||||
insufficient_list = set()
|
||||
|
|
@ -523,35 +523,50 @@ class router(router_tech):
|
|||
zindex=self.get_zindex(pin.layer_num)
|
||||
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):
|
||||
debug.info(4,"Converting [ {0} , {1} ]".format(x,y))
|
||||
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
|
||||
if full_overlap:
|
||||
sufficient_list.update([full_overlap])
|
||||
if 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:
|
||||
return sufficient_list
|
||||
elif expansion==0 and len(insufficient_list)>0:
|
||||
#Remove blockages and return the best to be patched
|
||||
insufficient_list.difference_update(self.blocked_grids)
|
||||
return self.get_best_offgrid_pin(pin, insufficient_list)
|
||||
best_pin = self.get_all_offgrid_pin(pin, insufficient_list)
|
||||
#print(best_pin)
|
||||
return best_pin
|
||||
elif expansion>0:
|
||||
#Remove blockages and return the nearest
|
||||
insufficient_list.difference_update(self.blocked_grids)
|
||||
return self.get_nearest_offgrid_pin(pin, insufficient_list)
|
||||
nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list)
|
||||
return nearest_pin
|
||||
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):
|
||||
"""
|
||||
Given a pin and a list of partial overlap grids:
|
||||
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.
|
||||
Find a list of the single pin with the most overlap.
|
||||
"""
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
|
|
@ -568,6 +583,23 @@ class router(router_tech):
|
|||
best_coord=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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -164,8 +164,12 @@ class vector3d():
|
|||
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
|
|
|
|||
|
|
@ -73,8 +73,10 @@ class sram_1bank(sram_base):
|
|||
self.control_logic_insts[port].place(control_pos[port])
|
||||
|
||||
# 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,
|
||||
self.control_logic_insts[port].uy())
|
||||
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
|
||||
# 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])
|
||||
|
||||
# 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")
|
||||
|
||||
# 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,
|
||||
self.control_logic_insts[port].uy())
|
||||
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
||||
# 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")
|
||||
|
||||
# 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))
|
||||
self.mod_bitcell = getattr(c, OPTS.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)
|
||||
from dff_array import dff_array
|
||||
|
|
@ -283,13 +260,13 @@ class sram_base(design):
|
|||
sram=self,
|
||||
port_type="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,
|
||||
words_per_row=self.words_per_row,
|
||||
sram=self,
|
||||
port_type="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,
|
||||
words_per_row=self.words_per_row,
|
||||
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