Merged, fixed conflict bt matching control logic creation to dev.

This commit is contained in:
Hunter Nichols 2018-11-19 22:20:20 -08:00
commit 62cbbca852
13 changed files with 235 additions and 94 deletions

View File

@ -1,6 +1,6 @@
# OpenRAM # OpenRAM
Stable: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/master/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/master) Master: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/master/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/master)
Unstable: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/dev/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/dev) Dev: [![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/dev/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits/dev)
[![Download](images/download.svg)](https://github.com/VLSIDA/PrivateRAM/archive/master.zip) [![Download](images/download.svg)](https://github.com/VLSIDA/PrivateRAM/archive/master.zip)
[![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) [![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE)

View File

@ -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):

View File

@ -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

View File

@ -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_{}"):

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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),

View File

@ -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 """

View File

@ -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

View File

@ -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,

View File

@ -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()